gitarsenal-cli 1.2.7 → 1.3.1
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/bin/gitarsenal.js +301 -20
- package/lib/sandbox.js +8 -8
- package/package.json +2 -2
- package/python/emoji_fix_patch.py +79 -0
- package/python/modal_logs_patch.py +86 -0
- package/python/test_modalSandboxScript.py +113 -143
- package/python/test_modalSandboxScript.py.bak +2742 -0
- package/python/test_modalSandboxScript.py.emoji_backup +2742 -0
- package/scripts/postinstall.js +1 -1
- package/python/__pycache__/credentials_manager.cpython-313.pyc +0 -0
- package/python/__pycache__/gitarsenal_proxy_client.cpython-313.pyc +0 -0
- package/python/__pycache__/setup_modal_token.cpython-313.pyc +0 -0
- package/python/__pycache__/test_modalSandboxScript.cpython-313.pyc +0 -0
package/bin/gitarsenal.js
CHANGED
@@ -7,7 +7,7 @@ const ora = require('ora');
|
|
7
7
|
const path = require('path');
|
8
8
|
const { version } = require('../package.json');
|
9
9
|
const { checkDependencies } = require('../lib/dependencies');
|
10
|
-
const {
|
10
|
+
const { runContainer } = require('../lib/sandbox');
|
11
11
|
const updateNotifier = require('update-notifier');
|
12
12
|
const pkg = require('../package.json');
|
13
13
|
const boxen = require('boxen');
|
@@ -16,27 +16,86 @@ const boxen = require('boxen');
|
|
16
16
|
updateNotifier({ pkg }).notify();
|
17
17
|
|
18
18
|
// Display banner
|
19
|
-
console.log(boxen(chalk.bold.green('GitArsenal CLI') + '\n' + chalk.blue('Create
|
19
|
+
console.log(boxen(chalk.bold.green('GitArsenal CLI') + '\n' + chalk.blue('Create GPU-accelerated development environments'), {
|
20
20
|
padding: 1,
|
21
21
|
margin: 1,
|
22
22
|
borderStyle: 'round',
|
23
23
|
borderColor: 'green'
|
24
24
|
}));
|
25
25
|
|
26
|
-
// Set up
|
26
|
+
// Set up main command
|
27
27
|
program
|
28
28
|
.version(version)
|
29
|
-
.description('
|
29
|
+
.description('GitArsenal CLI - Create GPU-accelerated development environments');
|
30
|
+
|
31
|
+
// Container command
|
32
|
+
const containerCmd = program
|
33
|
+
.command('container')
|
34
|
+
.description('Create a container with a GitHub repository')
|
35
|
+
.option('-g, --gpu <type>', 'GPU type (A10G, A100, H100, T4, L4, L40S, V100)', 'A10G')
|
36
|
+
.option('-r, --repo-url <url>', 'GitHub repository URL')
|
37
|
+
.option('-v, --volume-name <name>', 'Name of persistent volume')
|
38
|
+
.option('-s, --setup-commands <commands...>', 'Setup commands to run in the container')
|
39
|
+
.option('-y, --yes', 'Skip confirmation prompts')
|
40
|
+
.option('-m, --manual', 'Disable automatic setup command detection')
|
41
|
+
.action(async (options) => {
|
42
|
+
await runContainerCommand(options);
|
43
|
+
});
|
44
|
+
|
45
|
+
// Keys management command
|
46
|
+
const keysCmd = program
|
47
|
+
.command('keys')
|
48
|
+
.description('Manage API keys for services');
|
49
|
+
|
50
|
+
keysCmd
|
51
|
+
.command('add')
|
52
|
+
.description('Add an API key')
|
53
|
+
.option('-s, --service <service>', 'Service name (openai, wandb, huggingface)')
|
54
|
+
.option('-k, --key <key>', 'API key (if not provided, will prompt)')
|
55
|
+
.action(async (options) => {
|
56
|
+
await handleKeysAdd(options);
|
57
|
+
});
|
58
|
+
|
59
|
+
keysCmd
|
60
|
+
.command('list')
|
61
|
+
.description('List saved API keys')
|
62
|
+
.action(async () => {
|
63
|
+
await handleKeysList();
|
64
|
+
});
|
65
|
+
|
66
|
+
keysCmd
|
67
|
+
.command('view')
|
68
|
+
.description('View a specific API key (masked)')
|
69
|
+
.option('-s, --service <service>', 'Service name')
|
70
|
+
.action(async (options) => {
|
71
|
+
await handleKeysView(options);
|
72
|
+
});
|
73
|
+
|
74
|
+
keysCmd
|
75
|
+
.command('delete')
|
76
|
+
.description('Delete an API key')
|
77
|
+
.option('-s, --service <service>', 'Service name')
|
78
|
+
.action(async (options) => {
|
79
|
+
await handleKeysDelete(options);
|
80
|
+
});
|
81
|
+
|
82
|
+
// For backward compatibility, support running without a subcommand
|
83
|
+
program
|
30
84
|
.option('-r, --repo <url>', 'GitHub repository URL')
|
31
|
-
.option('-g, --gpu <type>', 'GPU type (A10G, A100, H100, T4, V100)', 'A10G')
|
85
|
+
.option('-g, --gpu <type>', 'GPU type (A10G, A100, H100, T4, L4, L40S, V100)', 'A10G')
|
32
86
|
.option('-v, --volume <n>', 'Name of persistent volume')
|
33
87
|
.option('-y, --yes', 'Skip confirmation prompts')
|
34
88
|
.option('-m, --manual', 'Disable automatic setup command detection')
|
35
|
-
.
|
89
|
+
.action(async (options) => {
|
90
|
+
// If options are provided directly, run the container command
|
91
|
+
if (options.repo || process.argv.length <= 3) {
|
92
|
+
await runContainerCommand(options);
|
93
|
+
}
|
94
|
+
});
|
36
95
|
|
37
|
-
|
96
|
+
program.parse(process.argv);
|
38
97
|
|
39
|
-
async function
|
98
|
+
async function runContainerCommand(options) {
|
40
99
|
try {
|
41
100
|
// Check for required dependencies
|
42
101
|
const spinner = ora('Checking dependencies...').start();
|
@@ -49,11 +108,12 @@ async function main() {
|
|
49
108
|
spinner.succeed('Dependencies checked');
|
50
109
|
|
51
110
|
// If repo URL not provided, prompt for it
|
52
|
-
let repoUrl = options.repo;
|
111
|
+
let repoUrl = options.repoUrl || options.repo;
|
53
112
|
let gpuType = options.gpu;
|
54
|
-
let volumeName = options.volume;
|
113
|
+
let volumeName = options.volumeName || options.volume;
|
55
114
|
let skipConfirmation = options.yes;
|
56
115
|
let useApi = !options.manual;
|
116
|
+
let setupCommands = options.setupCommands || [];
|
57
117
|
|
58
118
|
if (!repoUrl) {
|
59
119
|
const answers = await inquirer.prompt([
|
@@ -68,7 +128,7 @@ async function main() {
|
|
68
128
|
}
|
69
129
|
|
70
130
|
// Prompt for GPU type if not specified
|
71
|
-
if (!
|
131
|
+
if (!gpuType) {
|
72
132
|
const gpuAnswers = await inquirer.prompt([
|
73
133
|
{
|
74
134
|
type: 'list',
|
@@ -79,6 +139,8 @@ async function main() {
|
|
79
139
|
{ name: 'A100 (40GB VRAM)', value: 'A100' },
|
80
140
|
{ name: 'H100 (80GB VRAM)', value: 'H100' },
|
81
141
|
{ name: 'T4 (16GB VRAM)', value: 'T4' },
|
142
|
+
{ name: 'L4 (24GB VRAM)', value: 'L4' },
|
143
|
+
{ name: 'L40S (48GB VRAM)', value: 'L40S' },
|
82
144
|
{ name: 'V100 (16GB VRAM)', value: 'V100' }
|
83
145
|
],
|
84
146
|
default: 'A10G'
|
@@ -111,7 +173,7 @@ async function main() {
|
|
111
173
|
}
|
112
174
|
|
113
175
|
// Ask about setup command detection if not specified via CLI
|
114
|
-
if (!options.manual && !options.yes) {
|
176
|
+
if (!options.manual && !options.yes && setupCommands.length === 0) {
|
115
177
|
const apiAnswers = await inquirer.prompt([
|
116
178
|
{
|
117
179
|
type: 'confirm',
|
@@ -124,10 +186,8 @@ async function main() {
|
|
124
186
|
useApi = apiAnswers.useApi;
|
125
187
|
}
|
126
188
|
|
127
|
-
|
128
|
-
|
129
|
-
// Only prompt for custom commands if auto-detection is disabled
|
130
|
-
if (!useApi) {
|
189
|
+
// Only prompt for custom commands if auto-detection is disabled and no commands provided
|
190
|
+
if (!useApi && setupCommands.length === 0) {
|
131
191
|
const setupAnswers = await inquirer.prompt([
|
132
192
|
{
|
133
193
|
type: 'confirm',
|
@@ -156,7 +216,7 @@ async function main() {
|
|
156
216
|
}
|
157
217
|
|
158
218
|
// Show configuration summary
|
159
|
-
console.log(chalk.bold('\n📋
|
219
|
+
console.log(chalk.bold('\n📋 Container Configuration:'));
|
160
220
|
console.log(chalk.cyan('Repository URL: ') + repoUrl);
|
161
221
|
console.log(chalk.cyan('GPU Type: ') + gpuType);
|
162
222
|
console.log(chalk.cyan('Volume: ') + (volumeName || 'None'));
|
@@ -189,8 +249,8 @@ async function main() {
|
|
189
249
|
}
|
190
250
|
}
|
191
251
|
|
192
|
-
// Run the
|
193
|
-
await
|
252
|
+
// Run the container
|
253
|
+
await runContainer({
|
194
254
|
repoUrl,
|
195
255
|
gpuType,
|
196
256
|
volumeName,
|
@@ -204,4 +264,225 @@ async function main() {
|
|
204
264
|
}
|
205
265
|
}
|
206
266
|
|
207
|
-
|
267
|
+
async function handleKeysAdd(options) {
|
268
|
+
try {
|
269
|
+
const spinner = ora('Adding API key...').start();
|
270
|
+
|
271
|
+
let service = options.service;
|
272
|
+
let key = options.key;
|
273
|
+
|
274
|
+
if (!service) {
|
275
|
+
spinner.stop();
|
276
|
+
const serviceAnswer = await inquirer.prompt([
|
277
|
+
{
|
278
|
+
type: 'list',
|
279
|
+
name: 'service',
|
280
|
+
message: 'Select service:',
|
281
|
+
choices: [
|
282
|
+
{ name: 'OpenAI', value: 'openai' },
|
283
|
+
{ name: 'Weights & Biases', value: 'wandb' },
|
284
|
+
{ name: 'Hugging Face', value: 'huggingface' }
|
285
|
+
]
|
286
|
+
}
|
287
|
+
]);
|
288
|
+
service = serviceAnswer.service;
|
289
|
+
}
|
290
|
+
|
291
|
+
if (!key) {
|
292
|
+
spinner.stop();
|
293
|
+
const keyAnswer = await inquirer.prompt([
|
294
|
+
{
|
295
|
+
type: 'password',
|
296
|
+
name: 'key',
|
297
|
+
message: `Enter ${service} API key:`,
|
298
|
+
mask: '*'
|
299
|
+
}
|
300
|
+
]);
|
301
|
+
key = keyAnswer.key;
|
302
|
+
}
|
303
|
+
|
304
|
+
// Call Python script to add the key
|
305
|
+
const { spawn } = require('child_process');
|
306
|
+
const scriptPath = require('../lib/sandbox').getPythonScriptPath();
|
307
|
+
|
308
|
+
const pythonProcess = spawn('python', [
|
309
|
+
scriptPath,
|
310
|
+
'keys',
|
311
|
+
'add',
|
312
|
+
'--service', service,
|
313
|
+
'--key', key
|
314
|
+
], { stdio: 'pipe' });
|
315
|
+
|
316
|
+
let output = '';
|
317
|
+
pythonProcess.stdout.on('data', (data) => {
|
318
|
+
output += data.toString();
|
319
|
+
});
|
320
|
+
|
321
|
+
pythonProcess.stderr.on('data', (data) => {
|
322
|
+
output += data.toString();
|
323
|
+
});
|
324
|
+
|
325
|
+
pythonProcess.on('close', (code) => {
|
326
|
+
if (code === 0) {
|
327
|
+
spinner.succeed(`API key for ${service} added successfully`);
|
328
|
+
} else {
|
329
|
+
spinner.fail(`Failed to add API key: ${output}`);
|
330
|
+
}
|
331
|
+
});
|
332
|
+
|
333
|
+
} catch (error) {
|
334
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
335
|
+
process.exit(1);
|
336
|
+
}
|
337
|
+
}
|
338
|
+
|
339
|
+
async function handleKeysList() {
|
340
|
+
try {
|
341
|
+
const spinner = ora('Fetching API keys...').start();
|
342
|
+
|
343
|
+
// Call Python script to list keys
|
344
|
+
const { spawn } = require('child_process');
|
345
|
+
const scriptPath = require('../lib/sandbox').getPythonScriptPath();
|
346
|
+
|
347
|
+
const pythonProcess = spawn('python', [
|
348
|
+
scriptPath,
|
349
|
+
'keys',
|
350
|
+
'list'
|
351
|
+
], { stdio: 'inherit' });
|
352
|
+
|
353
|
+
pythonProcess.on('close', (code) => {
|
354
|
+
if (code !== 0) {
|
355
|
+
spinner.fail('Failed to list API keys');
|
356
|
+
} else {
|
357
|
+
spinner.stop();
|
358
|
+
}
|
359
|
+
});
|
360
|
+
|
361
|
+
} catch (error) {
|
362
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
363
|
+
process.exit(1);
|
364
|
+
}
|
365
|
+
}
|
366
|
+
|
367
|
+
async function handleKeysView(options) {
|
368
|
+
try {
|
369
|
+
const spinner = ora('Viewing API key...').start();
|
370
|
+
|
371
|
+
let service = options.service;
|
372
|
+
|
373
|
+
if (!service) {
|
374
|
+
spinner.stop();
|
375
|
+
const serviceAnswer = await inquirer.prompt([
|
376
|
+
{
|
377
|
+
type: 'list',
|
378
|
+
name: 'service',
|
379
|
+
message: 'Select service:',
|
380
|
+
choices: [
|
381
|
+
{ name: 'OpenAI', value: 'openai' },
|
382
|
+
{ name: 'Weights & Biases', value: 'wandb' },
|
383
|
+
{ name: 'Hugging Face', value: 'huggingface' }
|
384
|
+
]
|
385
|
+
}
|
386
|
+
]);
|
387
|
+
service = serviceAnswer.service;
|
388
|
+
}
|
389
|
+
|
390
|
+
// Call Python script to view the key
|
391
|
+
const { spawn } = require('child_process');
|
392
|
+
const scriptPath = require('../lib/sandbox').getPythonScriptPath();
|
393
|
+
|
394
|
+
const pythonProcess = spawn('python', [
|
395
|
+
scriptPath,
|
396
|
+
'keys',
|
397
|
+
'view',
|
398
|
+
'--service', service
|
399
|
+
], { stdio: 'inherit' });
|
400
|
+
|
401
|
+
pythonProcess.on('close', (code) => {
|
402
|
+
if (code !== 0) {
|
403
|
+
spinner.fail(`Failed to view API key for ${service}`);
|
404
|
+
} else {
|
405
|
+
spinner.stop();
|
406
|
+
}
|
407
|
+
});
|
408
|
+
|
409
|
+
} catch (error) {
|
410
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
411
|
+
process.exit(1);
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
async function handleKeysDelete(options) {
|
416
|
+
try {
|
417
|
+
const spinner = ora('Deleting API key...').start();
|
418
|
+
|
419
|
+
let service = options.service;
|
420
|
+
|
421
|
+
if (!service) {
|
422
|
+
spinner.stop();
|
423
|
+
const serviceAnswer = await inquirer.prompt([
|
424
|
+
{
|
425
|
+
type: 'list',
|
426
|
+
name: 'service',
|
427
|
+
message: 'Select service:',
|
428
|
+
choices: [
|
429
|
+
{ name: 'OpenAI', value: 'openai' },
|
430
|
+
{ name: 'Weights & Biases', value: 'wandb' },
|
431
|
+
{ name: 'Hugging Face', value: 'huggingface' }
|
432
|
+
]
|
433
|
+
}
|
434
|
+
]);
|
435
|
+
service = serviceAnswer.service;
|
436
|
+
}
|
437
|
+
|
438
|
+
// Confirm deletion
|
439
|
+
spinner.stop();
|
440
|
+
const confirmAnswer = await inquirer.prompt([
|
441
|
+
{
|
442
|
+
type: 'confirm',
|
443
|
+
name: 'confirm',
|
444
|
+
message: `Are you sure you want to delete the API key for ${service}?`,
|
445
|
+
default: false
|
446
|
+
}
|
447
|
+
]);
|
448
|
+
|
449
|
+
if (!confirmAnswer.confirm) {
|
450
|
+
console.log(chalk.yellow('Operation cancelled by user.'));
|
451
|
+
return;
|
452
|
+
}
|
453
|
+
|
454
|
+
spinner.start();
|
455
|
+
|
456
|
+
// Call Python script to delete the key
|
457
|
+
const { spawn } = require('child_process');
|
458
|
+
const scriptPath = require('../lib/sandbox').getPythonScriptPath();
|
459
|
+
|
460
|
+
const pythonProcess = spawn('python', [
|
461
|
+
scriptPath,
|
462
|
+
'keys',
|
463
|
+
'delete',
|
464
|
+
'--service', service
|
465
|
+
], { stdio: 'pipe' });
|
466
|
+
|
467
|
+
let output = '';
|
468
|
+
pythonProcess.stdout.on('data', (data) => {
|
469
|
+
output += data.toString();
|
470
|
+
});
|
471
|
+
|
472
|
+
pythonProcess.stderr.on('data', (data) => {
|
473
|
+
output += data.toString();
|
474
|
+
});
|
475
|
+
|
476
|
+
pythonProcess.on('close', (code) => {
|
477
|
+
if (code === 0) {
|
478
|
+
spinner.succeed(`API key for ${service} deleted successfully`);
|
479
|
+
} else {
|
480
|
+
spinner.fail(`Failed to delete API key: ${output}`);
|
481
|
+
}
|
482
|
+
});
|
483
|
+
|
484
|
+
} catch (error) {
|
485
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
486
|
+
process.exit(1);
|
487
|
+
}
|
488
|
+
}
|
package/lib/sandbox.js
CHANGED
@@ -26,8 +26,8 @@ function getPythonScriptPath() {
|
|
26
26
|
}
|
27
27
|
|
28
28
|
/**
|
29
|
-
* Run the
|
30
|
-
* @param {Object} options -
|
29
|
+
* Run the container with the given options
|
30
|
+
* @param {Object} options - Container options
|
31
31
|
* @param {string} options.repoUrl - GitHub repository URL
|
32
32
|
* @param {string} options.gpuType - GPU type
|
33
33
|
* @param {string} options.volumeName - Volume name
|
@@ -35,7 +35,7 @@ function getPythonScriptPath() {
|
|
35
35
|
* @param {boolean} options.useApi - Whether to use the API to fetch setup commands
|
36
36
|
* @returns {Promise<void>}
|
37
37
|
*/
|
38
|
-
async function
|
38
|
+
async function runContainer(options) {
|
39
39
|
const { repoUrl, gpuType, volumeName, setupCommands = [], useApi = true } = options;
|
40
40
|
|
41
41
|
// Get the path to the Python script
|
@@ -74,7 +74,7 @@ async function runModalSandbox(options) {
|
|
74
74
|
console.log(chalk.dim(`\nExecuting: python ${args.join(' ')}`));
|
75
75
|
|
76
76
|
// Start the spinner
|
77
|
-
const spinner = ora('Launching
|
77
|
+
const spinner = ora('Launching container...').start();
|
78
78
|
|
79
79
|
try {
|
80
80
|
// Run the Python script
|
@@ -86,10 +86,10 @@ async function runModalSandbox(options) {
|
|
86
86
|
return new Promise((resolve, reject) => {
|
87
87
|
pythonProcess.on('close', (code) => {
|
88
88
|
if (code === 0) {
|
89
|
-
spinner.succeed('
|
89
|
+
spinner.succeed('Container launched successfully');
|
90
90
|
resolve();
|
91
91
|
} else {
|
92
|
-
spinner.fail(`
|
92
|
+
spinner.fail(`Container launch failed with exit code ${code}`);
|
93
93
|
reject(new Error(`Process exited with code ${code}`));
|
94
94
|
}
|
95
95
|
});
|
@@ -101,12 +101,12 @@ async function runModalSandbox(options) {
|
|
101
101
|
});
|
102
102
|
});
|
103
103
|
} catch (error) {
|
104
|
-
spinner.fail(`Error launching
|
104
|
+
spinner.fail(`Error launching container: ${error.message}`);
|
105
105
|
throw error;
|
106
106
|
}
|
107
107
|
}
|
108
108
|
|
109
109
|
module.exports = {
|
110
|
-
|
110
|
+
runContainer,
|
111
111
|
getPythonScriptPath
|
112
112
|
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "gitarsenal-cli",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.3.1",
|
4
4
|
"description": "CLI tool for creating Modal sandboxes with GitHub repositories",
|
5
5
|
"main": "index.js",
|
6
6
|
"bin": {
|
@@ -34,4 +34,4 @@
|
|
34
34
|
"engines": {
|
35
35
|
"node": ">=14.0.0"
|
36
36
|
}
|
37
|
-
}
|
37
|
+
}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
This script removes emojis from the test_modalSandboxScript.py file to fix syntax errors.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import re
|
7
|
+
import sys
|
8
|
+
import shutil
|
9
|
+
from pathlib import Path
|
10
|
+
|
11
|
+
def remove_emojis(script_path):
|
12
|
+
"""
|
13
|
+
Remove emojis from the Python script to fix syntax errors.
|
14
|
+
"""
|
15
|
+
print(f"Removing emojis from {script_path}...")
|
16
|
+
|
17
|
+
# Make a backup of the original file
|
18
|
+
backup_path = f"{script_path}.emoji_backup"
|
19
|
+
shutil.copy2(script_path, backup_path)
|
20
|
+
|
21
|
+
# Read the file
|
22
|
+
with open(script_path, 'r', encoding='utf-8', errors='ignore') as f:
|
23
|
+
content = f.read()
|
24
|
+
|
25
|
+
# Emoji pattern - matches most common emoji characters
|
26
|
+
emoji_pattern = re.compile(
|
27
|
+
"["
|
28
|
+
"\U0001F1E0-\U0001F1FF" # flags (iOS)
|
29
|
+
"\U0001F300-\U0001F5FF" # symbols & pictographs
|
30
|
+
"\U0001F600-\U0001F64F" # emoticons
|
31
|
+
"\U0001F680-\U0001F6FF" # transport & map symbols
|
32
|
+
"\U0001F700-\U0001F77F" # alchemical symbols
|
33
|
+
"\U0001F780-\U0001F7FF" # Geometric Shapes
|
34
|
+
"\U0001F800-\U0001F8FF" # Supplemental Arrows-C
|
35
|
+
"\U0001F900-\U0001F9FF" # Supplemental Symbols and Pictographs
|
36
|
+
"\U0001FA00-\U0001FA6F" # Chess Symbols
|
37
|
+
"\U0001FA70-\U0001FAFF" # Symbols and Pictographs Extended-A
|
38
|
+
"\U00002702-\U000027B0" # Dingbats
|
39
|
+
"\U000024C2-\U0001F251"
|
40
|
+
"]+", flags=re.UNICODE)
|
41
|
+
|
42
|
+
# Simply remove all emojis
|
43
|
+
content = emoji_pattern.sub('', content)
|
44
|
+
|
45
|
+
# Fix common syntax issues after emoji removal
|
46
|
+
content = re.sub(r'print\(\s*\)', r'print()', content)
|
47
|
+
content = re.sub(r'print\(\s*"', r'print("', content)
|
48
|
+
|
49
|
+
# Fix specific syntax errors
|
50
|
+
content = re.sub(r'print\(\s*container\'s', r'print("container\'s', content)
|
51
|
+
|
52
|
+
# Write the modified content back to the file
|
53
|
+
with open(script_path, 'w', encoding='utf-8') as f:
|
54
|
+
f.write(content)
|
55
|
+
|
56
|
+
print(f"Emoji removal complete. Original file backed up to {backup_path}")
|
57
|
+
return True
|
58
|
+
|
59
|
+
def main():
|
60
|
+
"""
|
61
|
+
Main entry point for the script.
|
62
|
+
"""
|
63
|
+
# Get the path to the script
|
64
|
+
script_dir = Path(__file__).parent
|
65
|
+
script_path = script_dir / "test_modalSandboxScript.py"
|
66
|
+
|
67
|
+
if not script_path.exists():
|
68
|
+
print(f"Error: Script not found at {script_path}")
|
69
|
+
return 1
|
70
|
+
|
71
|
+
try:
|
72
|
+
remove_emojis(script_path)
|
73
|
+
return 0
|
74
|
+
except Exception as e:
|
75
|
+
print(f"Error removing emojis: {e}")
|
76
|
+
return 1
|
77
|
+
|
78
|
+
if __name__ == "__main__":
|
79
|
+
sys.exit(main())
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
This script patches the test_modalSandboxScript.py file to replace "modal" with "container" in the logs.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
import re
|
8
|
+
import sys
|
9
|
+
import shutil
|
10
|
+
from pathlib import Path
|
11
|
+
|
12
|
+
def patch_modal_logs(script_path):
|
13
|
+
"""
|
14
|
+
Patch the Python script to replace "modal" with "container" in the logs.
|
15
|
+
"""
|
16
|
+
print(f"Patching {script_path} to replace 'modal' with 'container' in logs...")
|
17
|
+
|
18
|
+
# Make a backup of the original file
|
19
|
+
backup_path = f"{script_path}.bak"
|
20
|
+
shutil.copy2(script_path, backup_path)
|
21
|
+
|
22
|
+
# Read the file
|
23
|
+
with open(script_path, 'r', encoding='utf-8') as f:
|
24
|
+
content = f.read()
|
25
|
+
|
26
|
+
# Define replacements
|
27
|
+
replacements = [
|
28
|
+
# Function names
|
29
|
+
(r'def create_modal_sandbox', r'def create_container'),
|
30
|
+
(r'def create_modal_ssh_container', r'def create_ssh_container'),
|
31
|
+
|
32
|
+
# Log messages - case sensitive replacements
|
33
|
+
(r'Modal sandbox', r'Container'),
|
34
|
+
(r'Modal authentication', r'Container authentication'),
|
35
|
+
(r'Modal token', r'Container token'),
|
36
|
+
(r'Modal package', r'Container package'),
|
37
|
+
(r'Modal operations', r'Container operations'),
|
38
|
+
|
39
|
+
# Log messages - case insensitive replacements (lowercase)
|
40
|
+
(r'modal sandbox', r'container'),
|
41
|
+
(r'modal authentication', r'container authentication'),
|
42
|
+
(r'modal token', r'container token'),
|
43
|
+
(r'modal package', r'container package'),
|
44
|
+
(r'modal operations', r'container operations'),
|
45
|
+
|
46
|
+
# Keep function calls to modal library intact but change logs
|
47
|
+
(r'print\([\'"](.*)modal(.*)[\'"]', r'print(\1container\2'),
|
48
|
+
(r'log\([\'"](.*)modal(.*)[\'"]', r'log(\1container\2'),
|
49
|
+
(r'logger\.info\([\'"](.*)modal(.*)[\'"]', r'logger.info(\1container\2'),
|
50
|
+
(r'logger\.error\([\'"](.*)modal(.*)[\'"]', r'logger.error(\1container\2'),
|
51
|
+
(r'logger\.warning\([\'"](.*)modal(.*)[\'"]', r'logger.warning(\1container\2'),
|
52
|
+
(r'logger\.debug\([\'"](.*)modal(.*)[\'"]', r'logger.debug(\1container\2'),
|
53
|
+
]
|
54
|
+
|
55
|
+
# Apply replacements
|
56
|
+
for pattern, replacement in replacements:
|
57
|
+
content = re.sub(pattern, replacement, content, flags=re.IGNORECASE)
|
58
|
+
|
59
|
+
# Write the modified content back to the file
|
60
|
+
with open(script_path, 'w', encoding='utf-8') as f:
|
61
|
+
f.write(content)
|
62
|
+
|
63
|
+
print(f"Patching complete. Original file backed up to {backup_path}")
|
64
|
+
return True
|
65
|
+
|
66
|
+
def main():
|
67
|
+
"""
|
68
|
+
Main entry point for the script.
|
69
|
+
"""
|
70
|
+
# Get the path to the script
|
71
|
+
script_dir = Path(__file__).parent
|
72
|
+
script_path = script_dir / "test_modalSandboxScript.py"
|
73
|
+
|
74
|
+
if not script_path.exists():
|
75
|
+
print(f"Error: Script not found at {script_path}")
|
76
|
+
return 1
|
77
|
+
|
78
|
+
try:
|
79
|
+
patch_modal_logs(script_path)
|
80
|
+
return 0
|
81
|
+
except Exception as e:
|
82
|
+
print(f"Error patching file: {e}")
|
83
|
+
return 1
|
84
|
+
|
85
|
+
if __name__ == "__main__":
|
86
|
+
sys.exit(main())
|