-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.ts
More file actions
182 lines (150 loc) · 5.76 KB
/
index.ts
File metadata and controls
182 lines (150 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/**
* @file index.ts
*
* Proof-of-concept to highlight breaking down a python file by function and
* assigning each component a CID on IPFS through ingesting a profiled program
*/
import * as fs from 'fs'
import * as dotenv from "dotenv"
import { spawn } from 'child_process'
import Extractor from './scripts/extractor'
import Uploader from './scripts/uploader'
import { glob } from 'glob'
import moduleFuncFinder from './scripts/moduleFuncFinder'
import moduleFuncExtractor from './scripts/moduleFuncExtractor'
import createManifest from './scripts/createManifest'
dotenv.config()
class Profiled {
apiKey: string | undefined
constructor() {
this.apiKey = process.env.WEB3_STORAGE_KEY
this.parseImports()
}
/**
* @function parseImports
*
* Create dictionary for imports in inputs directory
*/
async parseImports(): Promise<void> {
// Delete outputs folder if it exists
if (fs.existsSync('./outputs')) fs.rmSync('./outputs', { recursive: true, force: true });
// Get array of all python files in inputs directory
const inputFiles = await glob('./inputs/**/*.py', {
ignore: './inputs/example.py'
})
// Traverse each file and parse inputs
for (let x = 0; x < inputFiles.length; x++) {
const handler = new moduleFuncFinder({
directory: inputFiles[x]
})
await handler.getImports()
}
return this.parseProfile()
}
/**
* @function parseProfile
*
* Spawns helper subprocess to parse profile functions
*/
async parseProfile(): Promise<void> {
// Check to see if profile exists
if (!fs.existsSync('./inputs/profile')) throw new Error('[ERROR] profile does not exist in inputs directory!')
// Execute helper in a subprocess
console.log('[!] Parsing profile (give this some time)...')
let helper = spawn('python', ['scripts/helper.py'])
helper.on('exit', (data) => {
return this.readPrimaryFunctions()
});
helper.stdout.on('data', function(data) {
// Do something with data to prevent hanging
let tmp = data
});
// Throw an error if subprocess fails
helper.stderr.on('data', (data) => {
throw new Error(`Helper error: ${data}`)
})
}
/**
* @function readPrimaryFunctions
*
* Spawns helper subprocess to parse front-facing functions
*/
async readPrimaryFunctions(): Promise<void> {
if (!fs.existsSync('./outputs')) fs.mkdirSync('./outputs')
const functionDictionary = JSON.parse(fs.readFileSync('./scripts/tmp/primary_functions.json', 'utf-8'))
// Iterate through every function name
Object.keys(functionDictionary).forEach(async (functionName: string) => {
// Iterate through instance a function name is invoked
const functions = functionDictionary[functionName]
for (let x = 0; x < functions.length; x++) {
// Some files in the inputs directory have a unique case
if (!fs.existsSync(functions[x][0]) && functions[x][0].includes('Python-Atomizer')) {
// Construct fixed directory
const inputFileDirectory: fs.PathLike = functions[x][0].split('Python-Atomizer/')[0] +
'Python-Atomizer/inputs/' + functions[x][0].split('Python-Atomizer/')[1]
// Extract function and write to outputs folder
const extract = new Extractor({
functionName,
directory: inputFileDirectory,
lineNumber: functions[x][1]
})
await extract.extractFunction()
} else {
if (functions[x][0].includes('inputs')) {
// Extract function and write to outputs folder
const extract = new Extractor({
functionName,
directory: functions[x][0],
lineNumber: functions[x][1]
})
await extract.extractFunction()
}
}
}
})
return this.extractModuleFunctions()
}
/**
* @function extractModuleFunctions
*
* Extracts imported functions
*/
async extractModuleFunctions(): Promise<void> {
let dictionary: any;
if (fs.existsSync('scripts/tmp/secondary_definitions.json')) {
const extract = new moduleFuncExtractor()
dictionary = await extract.readPrimaryExtraction()
//console.log(JSON.stringify(dictionary))
}
return this.uploadToIPFS(dictionary)
}
/**
* @function uploadToIPFS
*
* Uploads atomized functions to IPFS and outputs JSON manifest
*/
async uploadToIPFS(dictionary: {}): Promise<void> {
const files = fs.readdirSync('outputs')
const pythonFiles = files.filter((file: string) => file.includes('.py'))
const upload = new Uploader({
functions: pythonFiles
})
await upload.uploadToIPFS()
return this.createManifest(dictionary)
}
/**
* @function createManifest
*
* Writes function/cid manifest to JSON file
*
* @param dictionary JSON of functions and CIDs
*/
async createManifest(dictionary: {}): Promise<void> {
const manifest = new createManifest({
dictionary
})
await manifest.writeParentFunctions()
console.log(`[!] Wrote manifest to outputs/manifest.json`)
}
}
const tmp = new Profiled()