motia 0.5.11-beta.120-382150 → 0.5.11-beta.120-357906
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cloud/build/builders/python/index.d.ts +12 -3
- package/dist/cjs/cloud/build/builders/python/index.js +216 -79
- package/dist/cjs/cloud/build/builders/python/uv-packager.d.ts +14 -0
- package/dist/cjs/cloud/build/builders/python/uv-packager.js +76 -0
- package/dist/cjs/dev.js +0 -2
- package/dist/cjs/utils/uv-install.d.ts +6 -0
- package/dist/cjs/utils/uv-install.js +129 -0
- package/dist/esm/cloud/build/builders/python/index.d.ts +12 -3
- package/dist/esm/cloud/build/builders/python/index.js +216 -79
- package/dist/esm/cloud/build/builders/python/uv-packager.d.ts +14 -0
- package/dist/esm/cloud/build/builders/python/uv-packager.js +69 -0
- package/dist/esm/dev.js +0 -2
- package/dist/esm/utils/uv-install.d.ts +6 -0
- package/dist/esm/utils/uv-install.js +122 -0
- package/dist/types/cloud/build/builders/python/index.d.ts +12 -3
- package/dist/types/cloud/build/builders/python/uv-packager.d.ts +14 -0
- package/dist/types/utils/uv-install.d.ts +6 -0
- package/package.json +4 -4
- package/dist/cjs/cloud/build/builders/python/add-package-to-archive.d.ts +0 -2
- package/dist/cjs/cloud/build/builders/python/add-package-to-archive.js +0 -56
- package/dist/cjs/cloud/build/builders/python/python-builder.py +0 -226
- package/dist/cjs/cloud/endpoints.d.ts +0 -2
- package/dist/cjs/cloud/endpoints.js +0 -107
- package/dist/cjs/cloud/new-deployment/listeners/streaming-deployment-listener.d.ts +0 -45
- package/dist/cjs/cloud/new-deployment/listeners/streaming-deployment-listener.js +0 -334
- package/dist/cjs/cloud/new-deployment/streams/deployment-stream.d.ts +0 -46
- package/dist/cjs/cloud/new-deployment/streams/deployment-stream.js +0 -111
- package/dist/esm/cloud/build/builders/python/add-package-to-archive.d.ts +0 -2
- package/dist/esm/cloud/build/builders/python/add-package-to-archive.js +0 -49
- package/dist/esm/cloud/build/builders/python/python-builder.py +0 -226
- package/dist/esm/cloud/endpoints.d.ts +0 -2
- package/dist/esm/cloud/endpoints.js +0 -103
- package/dist/esm/cloud/new-deployment/listeners/streaming-deployment-listener.d.ts +0 -45
- package/dist/esm/cloud/new-deployment/listeners/streaming-deployment-listener.js +0 -330
- package/dist/esm/cloud/new-deployment/streams/deployment-stream.d.ts +0 -46
- package/dist/esm/cloud/new-deployment/streams/deployment-stream.js +0 -106
- package/dist/types/cloud/build/builders/python/add-package-to-archive.d.ts +0 -2
- package/dist/types/cloud/endpoints.d.ts +0 -2
- package/dist/types/cloud/new-deployment/listeners/streaming-deployment-listener.d.ts +0 -45
- package/dist/types/cloud/new-deployment/streams/deployment-stream.d.ts +0 -46
|
@@ -4,9 +4,18 @@ import { BuildListener } from '../../../new-deployment/listeners/listener.types'
|
|
|
4
4
|
export declare class PythonBuilder implements StepBuilder {
|
|
5
5
|
private readonly builder;
|
|
6
6
|
private readonly listener;
|
|
7
|
+
private uvPackager;
|
|
8
|
+
private uvConfig;
|
|
7
9
|
constructor(builder: Builder, listener: BuildListener);
|
|
8
|
-
private
|
|
9
|
-
build(step: Step): Promise<void>;
|
|
10
|
+
private loadUvConfig;
|
|
10
11
|
buildApiSteps(steps: Step<ApiRouteConfig>[]): Promise<RouterBuildResult>;
|
|
11
|
-
|
|
12
|
+
build(step: Step): Promise<void>;
|
|
13
|
+
private addStepToArchive;
|
|
14
|
+
private addPackagesToArchive;
|
|
15
|
+
private shouldIgnoreFile;
|
|
16
|
+
private normalizeStepPath;
|
|
17
|
+
private createRouterTemplate;
|
|
18
|
+
private findInternalFiles;
|
|
19
|
+
private resolveModulePaths;
|
|
20
|
+
private getModuleName;
|
|
12
21
|
}
|
|
@@ -4,115 +4,252 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.PythonBuilder = void 0;
|
|
7
|
-
const child_process_1 = require("child_process");
|
|
8
7
|
const fs_1 = __importDefault(require("fs"));
|
|
9
8
|
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const activate_python_env_1 = require("../../../../utils/activate-python-env");
|
|
11
9
|
const archiver_1 = require("../archiver");
|
|
12
10
|
const include_static_files_1 = require("../include-static-files");
|
|
13
|
-
const add_package_to_archive_1 = require("./add-package-to-archive");
|
|
14
11
|
const constants_1 = require("../../../new-deployment/constants");
|
|
12
|
+
const uv_packager_1 = require("./uv-packager");
|
|
15
13
|
class PythonBuilder {
|
|
16
14
|
constructor(builder, listener) {
|
|
17
15
|
this.builder = builder;
|
|
18
16
|
this.listener = listener;
|
|
19
|
-
|
|
17
|
+
this.uvConfig = { ...uv_packager_1.defaultUvConfig, ...this.loadUvConfig() };
|
|
18
|
+
this.uvPackager = new uv_packager_1.UvPackager(this.builder.projectDir, this.uvConfig);
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
loadUvConfig() {
|
|
21
|
+
const configFiles = ['uv.config.json', '.uvrc.json'];
|
|
22
|
+
for (const configFile of configFiles) {
|
|
23
|
+
const configPath = path_1.default.join(this.builder.projectDir, configFile);
|
|
24
|
+
if (fs_1.default.existsSync(configPath)) {
|
|
25
|
+
try {
|
|
26
|
+
const configContent = fs_1.default.readFileSync(configPath, 'utf-8');
|
|
27
|
+
return JSON.parse(configContent);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
console.warn(`Warning: Failed to load UV config from ${configFile}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
async buildApiSteps(steps) {
|
|
37
|
+
const zipName = 'router-python.zip';
|
|
38
|
+
const archive = new archiver_1.Archiver(path_1.default.join(constants_1.distDir, zipName));
|
|
39
|
+
if (!await this.uvPackager.checkUvInstalled()) {
|
|
40
|
+
throw new Error('UV is not installed. Please install UV: curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
41
|
+
}
|
|
42
|
+
const tempSitePackages = path_1.default.join(constants_1.distDir, `temp-python-packages-${Date.now()}`);
|
|
43
|
+
try {
|
|
44
|
+
await this.uvPackager.packageDependencies(tempSitePackages);
|
|
45
|
+
// Pequena pausa para garantir que o filesystem sincronize
|
|
46
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
47
|
+
await this.addPackagesToArchive(archive, tempSitePackages);
|
|
48
|
+
for (const step of steps) {
|
|
49
|
+
await this.addStepToArchive(step, archive);
|
|
50
|
+
}
|
|
51
|
+
const routerTemplate = this.createRouterTemplate(steps);
|
|
52
|
+
archive.append(routerTemplate, 'router.py');
|
|
53
|
+
(0, include_static_files_1.includeStaticFiles)(steps, this.builder, archive);
|
|
54
|
+
const size = await archive.finalize();
|
|
55
|
+
return { size, path: zipName };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new Error(`Failed to build Python API router: ${error}`);
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
if (fs_1.default.existsSync(tempSitePackages)) {
|
|
62
|
+
fs_1.default.rmSync(tempSitePackages, { recursive: true, force: true });
|
|
63
|
+
}
|
|
30
64
|
}
|
|
31
|
-
archive.append(fs_1.default.createReadStream(step.filePath), path_1.default.relative(this.builder.projectDir, normalizedEntrypointPath));
|
|
32
|
-
await Promise.all(packages.map(async (packageName) => (0, add_package_to_archive_1.addPackageToArchive)(archive, sitePackagesDir, packageName)));
|
|
33
|
-
return normalizedEntrypointPath;
|
|
34
65
|
}
|
|
35
66
|
async build(step) {
|
|
36
67
|
const entrypointPath = step.filePath.replace(this.builder.projectDir, '');
|
|
37
68
|
const bundlePath = path_1.default.join('python', entrypointPath.replace(/(.*)\.py$/, '$1.zip'));
|
|
38
|
-
const normalizedEntrypointPath = entrypointPath.replace(/[.]step.py$/, '_step.py');
|
|
39
69
|
const outfile = path_1.default.join(constants_1.distDir, bundlePath);
|
|
70
|
+
this.builder.registerStep({ entrypointPath, bundlePath, step, type: 'python' });
|
|
71
|
+
this.listener.onBuildStart(step);
|
|
40
72
|
try {
|
|
41
|
-
|
|
73
|
+
if (!await this.uvPackager.checkUvInstalled()) {
|
|
74
|
+
throw new Error('UV is not installed. Please install UV: curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
75
|
+
}
|
|
42
76
|
fs_1.default.mkdirSync(path_1.default.dirname(outfile), { recursive: true });
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
77
|
+
const archive = new archiver_1.Archiver(outfile);
|
|
78
|
+
const tempSitePackages = path_1.default.join(constants_1.distDir, `temp-python-packages-${Date.now()}`);
|
|
79
|
+
try {
|
|
80
|
+
await this.uvPackager.packageDependencies(tempSitePackages);
|
|
81
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
82
|
+
await this.addStepToArchive(step, archive);
|
|
83
|
+
await this.addPackagesToArchive(archive, tempSitePackages);
|
|
84
|
+
(0, include_static_files_1.includeStaticFiles)([step], this.builder, archive);
|
|
85
|
+
const size = await archive.finalize();
|
|
86
|
+
this.listener.onBuildEnd(step, size);
|
|
51
87
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
(0, include_static_files_1.includeStaticFiles)([step], this.builder, stepArchiver);
|
|
57
|
-
if (packages.length > 0) {
|
|
58
|
-
await Promise.all(packages.map(async (packageName) => (0, add_package_to_archive_1.addPackageToArchive)(stepArchiver, sitePackagesDir, packageName)));
|
|
59
|
-
this.listener.onBuildProgress(step, `Added ${packages.length} packages to archive`);
|
|
88
|
+
finally {
|
|
89
|
+
if (fs_1.default.existsSync(tempSitePackages)) {
|
|
90
|
+
fs_1.default.rmSync(tempSitePackages, { recursive: true, force: true });
|
|
91
|
+
}
|
|
60
92
|
}
|
|
61
|
-
// Finalize the archive and wait for completion
|
|
62
|
-
const size = await stepArchiver.finalize();
|
|
63
|
-
this.builder.registerStep({ entrypointPath: stepPath, bundlePath, step, type: 'python' });
|
|
64
|
-
this.listener.onBuildEnd(step, size);
|
|
65
93
|
}
|
|
66
94
|
catch (err) {
|
|
67
95
|
this.listener.onBuildError(step, err);
|
|
68
96
|
throw err;
|
|
69
97
|
}
|
|
70
98
|
}
|
|
71
|
-
async
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
99
|
+
async addStepToArchive(step, archive) {
|
|
100
|
+
const normalizedPath = this.normalizeStepPath(step, false);
|
|
101
|
+
archive.append(fs_1.default.createReadStream(step.filePath), normalizedPath);
|
|
102
|
+
const internalFiles = await this.findInternalFiles(step.filePath);
|
|
103
|
+
for (const file of internalFiles) {
|
|
104
|
+
const fullPath = path_1.default.join(this.builder.projectDir, file);
|
|
105
|
+
if (fs_1.default.existsSync(fullPath) && fullPath !== step.filePath) {
|
|
106
|
+
const archivePath = file.replace(/\.step\.py$/, '_step.py');
|
|
107
|
+
archive.append(fs_1.default.createReadStream(fullPath), archivePath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async addPackagesToArchive(archive, sitePackagesDir) {
|
|
112
|
+
if (!fs_1.default.existsSync(sitePackagesDir)) {
|
|
113
|
+
console.warn(`Warning: Site packages directory not found: ${sitePackagesDir}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Verificar se o diretório está acessível
|
|
117
|
+
try {
|
|
118
|
+
fs_1.default.accessSync(sitePackagesDir, fs_1.default.constants.R_OK);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
console.warn(`Warning: Cannot access site packages directory: ${sitePackagesDir}`);
|
|
122
|
+
return;
|
|
86
123
|
}
|
|
87
|
-
const
|
|
124
|
+
const addDirectory = (dirPath, basePath = sitePackagesDir) => {
|
|
125
|
+
try {
|
|
126
|
+
const items = fs_1.default.readdirSync(dirPath);
|
|
127
|
+
for (const item of items) {
|
|
128
|
+
const fullPath = path_1.default.join(dirPath, item);
|
|
129
|
+
const relativePath = path_1.default.relative(basePath, fullPath);
|
|
130
|
+
if (this.shouldIgnoreFile(relativePath)) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const stat = fs_1.default.statSync(fullPath);
|
|
135
|
+
if (stat.isDirectory()) {
|
|
136
|
+
addDirectory(fullPath, basePath);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
archive.append(fs_1.default.createReadStream(fullPath), relativePath);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.warn(`Warning: Could not process file ${fullPath}: ${error}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.warn(`Warning: Could not read directory ${dirPath}: ${error}`);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
addDirectory(sitePackagesDir);
|
|
152
|
+
}
|
|
153
|
+
shouldIgnoreFile(filePath) {
|
|
154
|
+
const ignorePatterns = [
|
|
155
|
+
/\.pyc$/,
|
|
156
|
+
/\.pyo$/,
|
|
157
|
+
/\.egg$/,
|
|
158
|
+
/\.egg-info$/,
|
|
159
|
+
/__pycache__/,
|
|
160
|
+
/\.dist-info$/,
|
|
161
|
+
/^tests?\//,
|
|
162
|
+
/^docs?\//,
|
|
163
|
+
/^examples?\//,
|
|
164
|
+
/\.pytest_cache/,
|
|
165
|
+
];
|
|
166
|
+
return ignorePatterns.some((pattern) => pattern.test(filePath));
|
|
167
|
+
}
|
|
168
|
+
normalizeStepPath(step, normalizePythonModulePath) {
|
|
169
|
+
let normalizedStepPath = step.filePath
|
|
170
|
+
.replace(/[.]step.py$/, '_step.py') // Replace .step.py with _step.py
|
|
171
|
+
.replace(`${this.builder.projectDir}/`, ''); // Remove the project directory from the path
|
|
172
|
+
const pathParts = normalizedStepPath.split(path_1.default.sep).map((part) => part
|
|
173
|
+
.replace(/^[0-9]+/g, '') // Remove numeric prefixes
|
|
174
|
+
.replace(/[^a-zA-Z0-9._]/g, '_') // Replace any non-alphanumeric characters (except dots) with underscores
|
|
175
|
+
.replace(/^_/, '')); // Remove leading underscore
|
|
176
|
+
normalizedStepPath = normalizePythonModulePath
|
|
177
|
+
? pathParts.join('.') // Convert path delimiter to dot (python module separator)
|
|
178
|
+
: '/' + pathParts.join(path_1.default.sep);
|
|
179
|
+
return normalizedStepPath;
|
|
180
|
+
}
|
|
181
|
+
createRouterTemplate(steps) {
|
|
182
|
+
const imports = steps
|
|
183
|
+
.map((step, index) => {
|
|
184
|
+
const moduleName = this.getModuleName(step);
|
|
185
|
+
return `from ${moduleName} import handler as route${index}_handler, config as route${index}_config`;
|
|
186
|
+
})
|
|
187
|
+
.join('\n');
|
|
188
|
+
const routerPaths = steps
|
|
189
|
+
.map((step, index) => {
|
|
190
|
+
const method = step.config.method.toUpperCase();
|
|
191
|
+
const path = step.config.path;
|
|
192
|
+
return ` '${method} ${path}': RouterPath('${step.config.name}', '${step.config.method.toLowerCase()}', route${index}_handler, route${index}_config)`;
|
|
193
|
+
})
|
|
194
|
+
.join(',\n');
|
|
195
|
+
return fs_1.default
|
|
88
196
|
.readFileSync(path_1.default.join(__dirname, 'router_template.py'), 'utf-8')
|
|
89
|
-
.replace('# {{imports}}',
|
|
90
|
-
.
|
|
91
|
-
.join('\n'))
|
|
92
|
-
.replace('# {{router paths}}', steps
|
|
93
|
-
.map((step, index) => `'${step.config.method} ${step.config.path}': RouterPath('${step.config.name}', '${step.config.method.toLowerCase()}', route${index}_handler, route${index}_config)`)
|
|
94
|
-
.join(',\n '));
|
|
95
|
-
archive.append(file, 'router.py');
|
|
96
|
-
(0, include_static_files_1.includeStaticFiles)(steps, this.builder, archive);
|
|
97
|
-
// Finalize the archive and wait for completion
|
|
98
|
-
const size = await archive.finalize();
|
|
99
|
-
return { size, path: zipName };
|
|
197
|
+
.replace('# {{imports}}', imports)
|
|
198
|
+
.replace('# {{router paths}}', routerPaths);
|
|
100
199
|
}
|
|
101
|
-
async
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
200
|
+
async findInternalFiles(entryFile) {
|
|
201
|
+
const files = [];
|
|
202
|
+
const visited = new Set();
|
|
203
|
+
const analyzeFile = (filePath) => {
|
|
204
|
+
if (visited.has(filePath) || !fs_1.default.existsSync(filePath)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
visited.add(filePath);
|
|
208
|
+
files.push(path_1.default.relative(this.builder.projectDir, filePath));
|
|
209
|
+
try {
|
|
210
|
+
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
211
|
+
// Regex melhorada para capturar imports mais complexos
|
|
212
|
+
const importRegex = /^(?:from\s+([a-zA-Z_][a-zA-Z0-9_.]*)\s+import|import\s+([a-zA-Z_][a-zA-Z0-9_.]*))/gm;
|
|
213
|
+
let match;
|
|
214
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
215
|
+
const moduleName = match[1] || match[2]; // from X import Y ou import X
|
|
216
|
+
// Verificar diferentes formas de import
|
|
217
|
+
this.resolveModulePaths(moduleName, path_1.default.dirname(filePath)).forEach(possiblePath => {
|
|
218
|
+
if (fs_1.default.existsSync(possiblePath)) {
|
|
219
|
+
analyzeFile(possiblePath);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
113
222
|
}
|
|
114
|
-
}
|
|
115
|
-
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
console.warn(`Could not analyze file: ${filePath}`);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
analyzeFile(entryFile);
|
|
229
|
+
return files;
|
|
230
|
+
}
|
|
231
|
+
resolveModulePaths(moduleName, currentDir) {
|
|
232
|
+
const parts = moduleName.split('.');
|
|
233
|
+
const baseName = parts[0];
|
|
234
|
+
const subPath = parts.length > 1 ? path_1.default.join(...parts) : baseName;
|
|
235
|
+
return [
|
|
236
|
+
// Relativo ao arquivo atual
|
|
237
|
+
path_1.default.join(currentDir, `${baseName}.py`),
|
|
238
|
+
path_1.default.join(currentDir, baseName, '__init__.py'),
|
|
239
|
+
path_1.default.join(currentDir, `${subPath}.py`),
|
|
240
|
+
// Relativo ao diretório do projeto
|
|
241
|
+
path_1.default.join(this.builder.projectDir, `${baseName}.py`),
|
|
242
|
+
path_1.default.join(this.builder.projectDir, baseName, '__init__.py'),
|
|
243
|
+
path_1.default.join(this.builder.projectDir, `${subPath}.py`),
|
|
244
|
+
// Para utils.database -> utils/database.py
|
|
245
|
+
path_1.default.join(this.builder.projectDir, subPath + '.py'),
|
|
246
|
+
path_1.default.join(this.builder.projectDir, subPath, '__init__.py'),
|
|
247
|
+
];
|
|
248
|
+
}
|
|
249
|
+
getModuleName(step) {
|
|
250
|
+
return this.normalizeStepPath(step, true)
|
|
251
|
+
.replace(/\.py$/, '')
|
|
252
|
+
.replace(/\//g, '.');
|
|
116
253
|
}
|
|
117
254
|
}
|
|
118
255
|
exports.PythonBuilder = PythonBuilder;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface UvPackageConfig {
|
|
2
|
+
pythonVersion?: string;
|
|
3
|
+
platform?: string;
|
|
4
|
+
onlyBinary?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare const defaultUvConfig: UvPackageConfig;
|
|
7
|
+
export declare class UvPackager {
|
|
8
|
+
private readonly projectDir;
|
|
9
|
+
private readonly config;
|
|
10
|
+
constructor(projectDir: string, config?: UvPackageConfig);
|
|
11
|
+
checkUvInstalled(): Promise<boolean>;
|
|
12
|
+
packageDependencies(targetDir: string): Promise<void>;
|
|
13
|
+
private runUvCommand;
|
|
14
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.UvPackager = exports.defaultUvConfig = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
exports.defaultUvConfig = {
|
|
11
|
+
pythonVersion: '3.13',
|
|
12
|
+
platform: 'x86_64-manylinux2014',
|
|
13
|
+
onlyBinary: true
|
|
14
|
+
};
|
|
15
|
+
class UvPackager {
|
|
16
|
+
constructor(projectDir, config = exports.defaultUvConfig) {
|
|
17
|
+
this.projectDir = projectDir;
|
|
18
|
+
this.config = config;
|
|
19
|
+
}
|
|
20
|
+
async checkUvInstalled() {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
const child = (0, child_process_1.spawn)('uv', ['--version'], { stdio: 'pipe' });
|
|
23
|
+
child.on('close', (code) => resolve(code === 0));
|
|
24
|
+
child.on('error', () => resolve(false));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
async packageDependencies(targetDir) {
|
|
28
|
+
if (!fs_1.default.existsSync(targetDir)) {
|
|
29
|
+
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
const requirementsFile = path_1.default.join(this.projectDir, 'requirements.txt');
|
|
32
|
+
if (!fs_1.default.existsSync(requirementsFile)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const args = [
|
|
36
|
+
'pip', 'install',
|
|
37
|
+
'--target', targetDir,
|
|
38
|
+
'--requirement', requirementsFile,
|
|
39
|
+
'--python-version', this.config.pythonVersion || '3.13',
|
|
40
|
+
'--python-platform', this.config.platform || 'x86_64-manylinux2014',
|
|
41
|
+
'--force-reinstall'
|
|
42
|
+
];
|
|
43
|
+
if (this.config.onlyBinary) {
|
|
44
|
+
args.push('--only-binary=:all:');
|
|
45
|
+
}
|
|
46
|
+
await this.runUvCommand(args);
|
|
47
|
+
}
|
|
48
|
+
async runUvCommand(args) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const child = (0, child_process_1.spawn)('uv', args, {
|
|
51
|
+
cwd: this.projectDir,
|
|
52
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
53
|
+
});
|
|
54
|
+
let stdout = '';
|
|
55
|
+
let stderr = '';
|
|
56
|
+
child.stdout?.on('data', (data) => {
|
|
57
|
+
stdout += data.toString();
|
|
58
|
+
});
|
|
59
|
+
child.stderr?.on('data', (data) => {
|
|
60
|
+
stderr += data.toString();
|
|
61
|
+
});
|
|
62
|
+
child.on('close', (code) => {
|
|
63
|
+
if (code === 0) {
|
|
64
|
+
resolve(stdout);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
reject(new Error(`UV command failed: ${stderr || stdout}`));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
child.on('error', (error) => {
|
|
71
|
+
reject(new Error(`Failed to spawn UV: ${error.message}`));
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.UvPackager = UvPackager;
|
package/dist/cjs/dev.js
CHANGED
|
@@ -11,7 +11,6 @@ const analytics_node_1 = require("@amplitude/analytics-node");
|
|
|
11
11
|
const generate_locked_data_1 = require("./generate-locked-data");
|
|
12
12
|
const dev_watchers_1 = require("./dev-watchers");
|
|
13
13
|
const state_endpoints_1 = require("./dev/state-endpoints");
|
|
14
|
-
const endpoints_1 = require("./cloud/endpoints");
|
|
15
14
|
const activate_python_env_1 = require("./utils/activate-python-env");
|
|
16
15
|
const analytics_1 = require("./utils/analytics");
|
|
17
16
|
const version_1 = require("./version");
|
|
@@ -56,7 +55,6 @@ const dev = async (port, hostname, disableVerbose, enableMermaid) => {
|
|
|
56
55
|
}
|
|
57
56
|
watcher.init();
|
|
58
57
|
(0, state_endpoints_1.stateEndpoints)(motiaServer, state);
|
|
59
|
-
(0, endpoints_1.deployEndpoints)(motiaServer, lockedData);
|
|
60
58
|
motiaServer.server.listen(port, hostname);
|
|
61
59
|
console.log('🚀 Server ready and listening on port', port);
|
|
62
60
|
console.log(`🔗 Open http://${hostname}:${port}/ to open workbench 🛠️`);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.uvInstall = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const colors_1 = __importDefault(require("colors"));
|
|
11
|
+
const uvInstall = async ({ baseDir, isVerbose = false, pythonVersion = '3.13' }) => {
|
|
12
|
+
const projectDir = baseDir;
|
|
13
|
+
console.log('📦 Installing Python dependencies with UV...', projectDir);
|
|
14
|
+
try {
|
|
15
|
+
if (!await checkUvInstalled()) {
|
|
16
|
+
throw new Error('UV is not installed. Please install UV: curl -LsSf https://astral.sh/uv/install.sh | sh');
|
|
17
|
+
}
|
|
18
|
+
await ensureUvProject(projectDir, pythonVersion, isVerbose);
|
|
19
|
+
await installDependencies(projectDir, isVerbose);
|
|
20
|
+
console.log(colors_1.default.green('✅ Python dependencies installed successfully with UV'));
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
24
|
+
console.error('❌ UV Installation failed:', errorMessage);
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
exports.uvInstall = uvInstall;
|
|
29
|
+
async function checkUvInstalled() {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const child = (0, child_process_1.spawn)('uv', ['--version'], { stdio: 'pipe' });
|
|
32
|
+
child.on('close', (code) => {
|
|
33
|
+
resolve(code === 0);
|
|
34
|
+
});
|
|
35
|
+
child.on('error', () => {
|
|
36
|
+
resolve(false);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async function ensureUvProject(projectDir, pythonVersion, isVerbose) {
|
|
41
|
+
const pyprojectPath = path_1.default.join(projectDir, 'pyproject.toml');
|
|
42
|
+
if (!fs_1.default.existsSync(pyprojectPath)) {
|
|
43
|
+
if (isVerbose) {
|
|
44
|
+
console.log('📄 Creating pyproject.toml...');
|
|
45
|
+
}
|
|
46
|
+
await runUvCommand(['init', '--no-readme'], projectDir);
|
|
47
|
+
const pyprojectContent = generatePyprojectToml(pythonVersion);
|
|
48
|
+
fs_1.default.writeFileSync(pyprojectPath, pyprojectContent);
|
|
49
|
+
}
|
|
50
|
+
const pythonVersionFile = path_1.default.join(projectDir, '.python-version');
|
|
51
|
+
if (!fs_1.default.existsSync(pythonVersionFile)) {
|
|
52
|
+
fs_1.default.writeFileSync(pythonVersionFile, pythonVersion);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function installDependencies(projectDir, isVerbose) {
|
|
56
|
+
const coreRequirementsPath = path_1.default.join(projectDir, 'node_modules', 'motia', 'dist', 'requirements-core.txt');
|
|
57
|
+
const snapRequirementsPath = path_1.default.join(projectDir, 'node_modules', 'motia', 'dist', 'requirements-snap.txt');
|
|
58
|
+
const localRequirements = path_1.default.join(projectDir, 'requirements.txt');
|
|
59
|
+
const requirementsList = [coreRequirementsPath, snapRequirementsPath, localRequirements];
|
|
60
|
+
for (const requirement of requirementsList) {
|
|
61
|
+
if (fs_1.default.existsSync(requirement)) {
|
|
62
|
+
if (isVerbose) {
|
|
63
|
+
console.log(`📄 Installing from: ${requirement}`);
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
await runUvCommand(['add', '--requirements', requirement], projectDir);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.warn(colors_1.default.yellow(`Warning: Could not install some dependencies from ${requirement}`));
|
|
70
|
+
if (isVerbose) {
|
|
71
|
+
console.warn(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (isVerbose) {
|
|
76
|
+
console.log(colors_1.default.yellow(`⚠️ Requirements file not found: ${requirement}`));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (isVerbose) {
|
|
80
|
+
console.log('🔄 Syncing UV environment...');
|
|
81
|
+
}
|
|
82
|
+
await runUvCommand(['sync'], projectDir);
|
|
83
|
+
}
|
|
84
|
+
function generatePyprojectToml(pythonVersion) {
|
|
85
|
+
return `[project]
|
|
86
|
+
name = "motia-project"
|
|
87
|
+
version = "0.1.0"
|
|
88
|
+
description = "Motia Python project"
|
|
89
|
+
requires-python = ">=${pythonVersion}"
|
|
90
|
+
dependencies = []
|
|
91
|
+
|
|
92
|
+
[build-system]
|
|
93
|
+
requires = ["hatchling"]
|
|
94
|
+
build-backend = "hatchling.build"
|
|
95
|
+
|
|
96
|
+
[tool.uv]
|
|
97
|
+
dev-dependencies = []
|
|
98
|
+
package = false
|
|
99
|
+
|
|
100
|
+
[tool.uv.sources]
|
|
101
|
+
`;
|
|
102
|
+
}
|
|
103
|
+
async function runUvCommand(args, cwd) {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
const child = (0, child_process_1.spawn)('uv', args, {
|
|
106
|
+
cwd,
|
|
107
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
108
|
+
});
|
|
109
|
+
let stdout = '';
|
|
110
|
+
let stderr = '';
|
|
111
|
+
child.stdout?.on('data', (data) => {
|
|
112
|
+
stdout += data.toString();
|
|
113
|
+
});
|
|
114
|
+
child.stderr?.on('data', (data) => {
|
|
115
|
+
stderr += data.toString();
|
|
116
|
+
});
|
|
117
|
+
child.on('close', (code) => {
|
|
118
|
+
if (code === 0) {
|
|
119
|
+
resolve(stdout);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
reject(new Error(`UV command failed: ${stderr || stdout}`));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
child.on('error', (error) => {
|
|
126
|
+
reject(new Error(`Failed to spawn UV: ${error.message}`));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -4,9 +4,18 @@ import { BuildListener } from '../../../new-deployment/listeners/listener.types'
|
|
|
4
4
|
export declare class PythonBuilder implements StepBuilder {
|
|
5
5
|
private readonly builder;
|
|
6
6
|
private readonly listener;
|
|
7
|
+
private uvPackager;
|
|
8
|
+
private uvConfig;
|
|
7
9
|
constructor(builder: Builder, listener: BuildListener);
|
|
8
|
-
private
|
|
9
|
-
build(step: Step): Promise<void>;
|
|
10
|
+
private loadUvConfig;
|
|
10
11
|
buildApiSteps(steps: Step<ApiRouteConfig>[]): Promise<RouterBuildResult>;
|
|
11
|
-
|
|
12
|
+
build(step: Step): Promise<void>;
|
|
13
|
+
private addStepToArchive;
|
|
14
|
+
private addPackagesToArchive;
|
|
15
|
+
private shouldIgnoreFile;
|
|
16
|
+
private normalizeStepPath;
|
|
17
|
+
private createRouterTemplate;
|
|
18
|
+
private findInternalFiles;
|
|
19
|
+
private resolveModulePaths;
|
|
20
|
+
private getModuleName;
|
|
12
21
|
}
|