@factorialco/fcode-cli 3.2.0 ā 3.4.0
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/README.md +1 -1
- package/dist/commands/i18n/status.js +9 -0
- package/dist/commands/modules/pull.js +5 -4
- package/dist/commands/modules/push.js +1 -1
- package/dist/commands/modules/status.js +9 -0
- package/dist/commands/processes/pull.js +5 -4
- package/dist/commands/processes/push.js +1 -1
- package/dist/commands/processes/status.js +9 -0
- package/dist/commands/runtime-env.js +2 -2
- package/dist/core/commands/resource-command.d.ts +4 -1
- package/dist/core/commands/resource-command.js +9 -2
- package/dist/core/dependencies/javascript-env-dependencies.js +4 -4
- package/dist/core/dependencies/python-env-dependencies.js +5 -4
- package/dist/core/executors/execution-task.js +1 -1
- package/dist/core/executors/javascript-execution-task.js +21 -17
- package/dist/core/executors/python-execution-task.js +11 -10
- package/dist/core/resource-pusher.js +13 -7
- package/dist/core/types.d.ts +76 -3
- package/dist/core/types.js +33 -6
- package/dist/repositories/locale.js +5 -3
- package/dist/repositories/process.js +20 -2
- package/dist/repositories/script-library.js +3 -2
- package/dist/runtime/libs/python/fcode/datastore.py +3 -1
- package/dist/services/fcode-graphql-client.d.ts +45 -7
- package/dist/services/fcode-graphql-client.js +264 -46
- package/dist/services/skills-installer.js +2 -2
- package/dist/services/version-pull-reporter.d.ts +20 -0
- package/dist/services/version-pull-reporter.js +33 -0
- package/dist/utils/child-process.d.ts +26 -0
- package/dist/utils/child-process.js +60 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ $ npm install -g @factorialco/fcode-cli
|
|
|
20
20
|
$ fcode COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ fcode (--version)
|
|
23
|
-
@factorialco/fcode-cli/3.
|
|
23
|
+
@factorialco/fcode-cli/3.4.0 linux-x64 node-v22.22.3
|
|
24
24
|
$ fcode --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ fcode COMMAND
|
|
@@ -7,6 +7,7 @@ const cli_1 = require("../../utils/cli");
|
|
|
7
7
|
class I18nStatus extends i18n_command_1.default {
|
|
8
8
|
async resourcesTableLog(resources) {
|
|
9
9
|
const hasInherited = resources.some((resource) => resource.resolvingTeamSlug);
|
|
10
|
+
const hasDeleted = resources.some((resource) => resource.deletion);
|
|
10
11
|
cli_1.cli.table(resources, {
|
|
11
12
|
locale: {
|
|
12
13
|
// The identifier, not the slug: an inherited file is tracked as `en.inherited`, and the
|
|
@@ -24,6 +25,14 @@ class I18nStatus extends i18n_command_1.default {
|
|
|
24
25
|
header: 'inherited',
|
|
25
26
|
},
|
|
26
27
|
}),
|
|
28
|
+
...(hasDeleted && {
|
|
29
|
+
deleted: {
|
|
30
|
+
get(resource) {
|
|
31
|
+
return (0, colorize_resource_1.colorizeByStatus)(resource.deletion ? `šŖ¦ kept by ${resource.deletion.retainingVersionTags.join(', ')}` : '', resource.status);
|
|
32
|
+
},
|
|
33
|
+
header: 'deleted',
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
27
36
|
status: {
|
|
28
37
|
get({ status }) {
|
|
29
38
|
return (0, colorize_resource_1.colorizeByStatus)(status, status);
|
|
@@ -4,13 +4,14 @@ const color_1 = require("@oclif/color");
|
|
|
4
4
|
const modules_command_1 = require("../../core/commands/modules-command");
|
|
5
5
|
const types_1 = require("../../core/types");
|
|
6
6
|
const cli_1 = require("../../utils/cli");
|
|
7
|
+
const version_pull_reporter_1 = require("../../services/version-pull-reporter");
|
|
7
8
|
class ModulesPull extends modules_command_1.default {
|
|
8
9
|
async pullVersioned() {
|
|
9
10
|
const scriptLibraries = (await this._resourceRepository.findAll()).filter((scriptLibrary) => scriptLibrary.id);
|
|
10
11
|
const scriptLibraryRepository = this._resourceRepository;
|
|
11
|
-
const
|
|
12
|
+
const pulls = [];
|
|
12
13
|
for (const scriptLibrary of scriptLibraries) {
|
|
13
|
-
|
|
14
|
+
pulls.push((0, version_pull_reporter_1.trackVersionPull)(scriptLibrary.slug, this._versionedResourceQuery(scriptLibrary.id).then(async (remoteVersions) => {
|
|
14
15
|
const remoteVersionTags = new Set(remoteVersions.map((v) => v.tag));
|
|
15
16
|
// Remove local versions that were deleted in remote
|
|
16
17
|
for (const localTag of scriptLibraryRepository.getLocalVersionTags(scriptLibrary)) {
|
|
@@ -26,10 +27,10 @@ class ModulesPull extends modules_command_1.default {
|
|
|
26
27
|
await scriptLibraryRepository.saveVersion(scriptLibrary, versionedScriptLibrary);
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
|
-
}));
|
|
30
|
+
})));
|
|
30
31
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
31
32
|
}
|
|
32
|
-
await
|
|
33
|
+
await (0, version_pull_reporter_1.reportFailedVersionPulls)(pulls, 'module');
|
|
33
34
|
}
|
|
34
35
|
async run() {
|
|
35
36
|
await super.pullResources();
|
|
@@ -6,7 +6,7 @@ const types_1 = require("../../core/types");
|
|
|
6
6
|
const cli_1 = require("../../utils/cli");
|
|
7
7
|
class ModulesPush extends modules_command_1.default {
|
|
8
8
|
async pushVersioned() {
|
|
9
|
-
const scriptLibraries = (await this._resourceRepository.findAll()).filter((
|
|
9
|
+
const scriptLibraries = (await this._resourceRepository.findAll()).filter((scriptLibrary) => scriptLibrary.id && !scriptLibrary.deletion);
|
|
10
10
|
const scriptLibraryRepository = this._resourceRepository;
|
|
11
11
|
const allPromises = [];
|
|
12
12
|
for (const scriptLibrary of scriptLibraries) {
|
|
@@ -7,6 +7,7 @@ const cli_1 = require("../../utils/cli");
|
|
|
7
7
|
class ModulesStatus extends modules_command_1.default {
|
|
8
8
|
async resourcesTableLog(resources) {
|
|
9
9
|
const hasInherited = resources.some((resource) => resource.resolvingTeamSlug);
|
|
10
|
+
const hasDeleted = resources.some((resource) => resource.deletion);
|
|
10
11
|
cli_1.cli.table(resources, {
|
|
11
12
|
name: {
|
|
12
13
|
get({ slug, status }) {
|
|
@@ -22,6 +23,14 @@ class ModulesStatus extends modules_command_1.default {
|
|
|
22
23
|
header: 'inherited',
|
|
23
24
|
},
|
|
24
25
|
}),
|
|
26
|
+
...(hasDeleted && {
|
|
27
|
+
deleted: {
|
|
28
|
+
get(resource) {
|
|
29
|
+
return (0, colorize_resource_1.colorizeByStatus)(resource.deletion ? `šŖ¦ kept by ${resource.deletion.retainingVersionTags.join(', ')}` : '', resource.status);
|
|
30
|
+
},
|
|
31
|
+
header: 'deleted',
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
25
34
|
status: {
|
|
26
35
|
get({ status }) {
|
|
27
36
|
return (0, colorize_resource_1.colorizeByStatus)(status, status);
|
|
@@ -5,13 +5,14 @@ const processes_command_1 = require("../../core/commands/processes-command");
|
|
|
5
5
|
const types_1 = require("../../core/types");
|
|
6
6
|
const cli_1 = require("../../utils/cli");
|
|
7
7
|
const settings_1 = require("../../config/settings");
|
|
8
|
+
const version_pull_reporter_1 = require("../../services/version-pull-reporter");
|
|
8
9
|
class ProcessesPull extends processes_command_1.default {
|
|
9
10
|
async pullVersioned() {
|
|
10
11
|
const processes = await this.getRemoteResources();
|
|
11
12
|
const processRepository = this._resourceRepository;
|
|
12
|
-
const
|
|
13
|
+
const pulls = [];
|
|
13
14
|
for (const process of processes) {
|
|
14
|
-
|
|
15
|
+
pulls.push((0, version_pull_reporter_1.trackVersionPull)(process.slug, this._versionedResourceQuery(process.id).then(async (remoteVersions) => {
|
|
15
16
|
const remoteVersionTags = new Set(remoteVersions.map((v) => v.tag));
|
|
16
17
|
// Remove local versions that were deleted in remote
|
|
17
18
|
for (const localTag of processRepository.getLocalVersionTags(process)) {
|
|
@@ -27,10 +28,10 @@ class ProcessesPull extends processes_command_1.default {
|
|
|
27
28
|
await processRepository.saveVersion(process, versionedProcess);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
}));
|
|
31
|
+
})));
|
|
31
32
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
32
33
|
}
|
|
33
|
-
await
|
|
34
|
+
await (0, version_pull_reporter_1.reportFailedVersionPulls)(pulls, 'process');
|
|
34
35
|
}
|
|
35
36
|
async run() {
|
|
36
37
|
await super.pullResources();
|
|
@@ -7,7 +7,7 @@ const cli_1 = require("../../utils/cli");
|
|
|
7
7
|
const settings_1 = require("../../config/settings");
|
|
8
8
|
class ProcessesPush extends processes_command_1.default {
|
|
9
9
|
async pushVersioned() {
|
|
10
|
-
const processes = (await this._resourceRepository.findAll()).filter((process) => process.id);
|
|
10
|
+
const processes = (await this._resourceRepository.findAll()).filter((process) => process.id && !process.deletion);
|
|
11
11
|
const processRepository = this._resourceRepository;
|
|
12
12
|
const allPromises = [];
|
|
13
13
|
for (const process of processes) {
|
|
@@ -7,6 +7,7 @@ const cli_1 = require("../../utils/cli");
|
|
|
7
7
|
class ProcessesStatus extends processes_command_1.default {
|
|
8
8
|
async resourcesTableLog(resources) {
|
|
9
9
|
const hasInherited = resources.some((resource) => resource.resolvingTeamSlug);
|
|
10
|
+
const hasDeleted = resources.some((resource) => resource.deletion);
|
|
10
11
|
cli_1.cli.table(resources, {
|
|
11
12
|
slug: {
|
|
12
13
|
get(resource) {
|
|
@@ -40,6 +41,14 @@ class ProcessesStatus extends processes_command_1.default {
|
|
|
40
41
|
header: 'inherited',
|
|
41
42
|
},
|
|
42
43
|
}),
|
|
44
|
+
...(hasDeleted && {
|
|
45
|
+
deleted: {
|
|
46
|
+
get(resource) {
|
|
47
|
+
return (0, colorize_resource_1.colorizeByStatus)(resource.deletion ? `šŖ¦ kept by ${resource.deletion.retainingVersionTags.join(', ')}` : '', resource.status);
|
|
48
|
+
},
|
|
49
|
+
header: 'deleted',
|
|
50
|
+
},
|
|
51
|
+
}),
|
|
43
52
|
status: {
|
|
44
53
|
get({ status }) {
|
|
45
54
|
return (0, colorize_resource_1.colorizeByStatus)(status, status);
|
|
@@ -21,10 +21,10 @@ class RuntimeEnv extends core_1.Command {
|
|
|
21
21
|
console.log('DEPENDENCIES_PATH=' + dependenciesPath);
|
|
22
22
|
console.log('LIBRARY_PATH=' + libraryPath);
|
|
23
23
|
if (language === 'PYTHON') {
|
|
24
|
-
console.log('PYTHONPATH=' + [dependenciesPath, libraryPath, process.cwd()].join(
|
|
24
|
+
console.log('PYTHONPATH=' + [dependenciesPath, libraryPath, process.cwd()].join(path.delimiter));
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
27
|
-
console.log('NODE_PATH=' + [dependenciesPath, libraryPath, process.cwd()].join(
|
|
27
|
+
console.log('NODE_PATH=' + [dependenciesPath, libraryPath, process.cwd()].join(path.delimiter));
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -38,7 +38,10 @@ export default abstract class ResourceCommand<R extends Resource> extends ApiCli
|
|
|
38
38
|
* whole set to place a change in context; `diffable` is only what a status says has changed.
|
|
39
39
|
*/
|
|
40
40
|
protected diffSections(diffable: Array<ResourcePair<R>>, allPairs: Array<ResourcePair<R>>): Array<DiffSection>;
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Names the resource a patch belongs to, flagging an inherited one as the parent's to fix and a
|
|
43
|
+
* deleted one as kept only for its versions.
|
|
44
|
+
*/
|
|
42
45
|
protected diffLabel(pair: ResourcePair<R>): string;
|
|
43
46
|
/**
|
|
44
47
|
* Prints a unified diff of everything that differs between the workspace and the cloud, and
|
|
@@ -107,11 +107,18 @@ class ResourceCommand extends api_client_command_1.default {
|
|
|
107
107
|
files: this._diffFilesFor(pair),
|
|
108
108
|
}));
|
|
109
109
|
}
|
|
110
|
-
/**
|
|
110
|
+
/**
|
|
111
|
+
* Names the resource a patch belongs to, flagging an inherited one as the parent's to fix and a
|
|
112
|
+
* deleted one as kept only for its versions.
|
|
113
|
+
*/
|
|
111
114
|
diffLabel(pair) {
|
|
112
115
|
const label = `${pair.status} ${this._resourceRepository._repositoryName}/${pair.slug}`;
|
|
113
116
|
const inheritedTeam = (0, resource_differ_1.inheritedFrom)(pair);
|
|
114
|
-
|
|
117
|
+
if (inheritedTeam) {
|
|
118
|
+
return `${label} š inherited from '${inheritedTeam}' (read-only ā run pull to update)`;
|
|
119
|
+
}
|
|
120
|
+
const deletion = (pair.remote ?? pair.local)?.deletion;
|
|
121
|
+
return deletion ? `${label} šŖ¦ deleted, kept by ${deletion.retainingVersionTags.join(', ')} (read-only ā run pull to update)` : label;
|
|
115
122
|
}
|
|
116
123
|
/**
|
|
117
124
|
* Prints a unified diff of everything that differs between the workspace and the cloud, and
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const node_child_process_1 = require("node:child_process");
|
|
4
3
|
const fs = require("node:fs");
|
|
5
4
|
const path = require("node:path");
|
|
6
5
|
const env_dependencies_command_1 = require("./env-dependencies-command");
|
|
6
|
+
const child_process_1 = require("../../utils/child-process");
|
|
7
7
|
class JavaScriptEnvDependencies extends env_dependencies_command_1.default {
|
|
8
8
|
get programmingLanguage() {
|
|
9
9
|
return 'JAVASCRIPT';
|
|
@@ -33,7 +33,7 @@ class JavaScriptEnvDependencies extends env_dependencies_command_1.default {
|
|
|
33
33
|
// Backward compatibility
|
|
34
34
|
const pnpmPath = await this.ensurePnpm();
|
|
35
35
|
return new Promise((resolve, reject) => {
|
|
36
|
-
const proc = (0,
|
|
36
|
+
const proc = (0, child_process_1.spawnCommand)(pnpmPath, ['install', '--no-dev'], {
|
|
37
37
|
cwd: installationPath,
|
|
38
38
|
stdio: 'inherit',
|
|
39
39
|
});
|
|
@@ -54,10 +54,10 @@ class JavaScriptEnvDependencies extends env_dependencies_command_1.default {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
async ensurePnpm() {
|
|
57
|
-
const pnpmPath = path.join(this.envPath, 'node_modules', '
|
|
57
|
+
const pnpmPath = (0, child_process_1.binShimPath)(path.join(this.envPath, 'node_modules'), 'pnpm');
|
|
58
58
|
if (!fs.existsSync(pnpmPath)) {
|
|
59
59
|
return new Promise((resolve, reject) => {
|
|
60
|
-
const proc = (0,
|
|
60
|
+
const proc = (0, child_process_1.spawnCommand)('npm', ['install', '--prefix', this.envPath, 'pnpm'], {
|
|
61
61
|
cwd: this.envPath,
|
|
62
62
|
stdio: 'inherit',
|
|
63
63
|
});
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const node_child_process_1 = require("node:child_process");
|
|
4
4
|
const fs = require("node:fs");
|
|
5
|
-
const path = require("node:path");
|
|
6
5
|
const env_dependencies_command_1 = require("./env-dependencies-command");
|
|
7
6
|
const cli_1 = require("../../utils/cli");
|
|
7
|
+
const child_process_1 = require("../../utils/child-process");
|
|
8
8
|
class PythonEnvDependencies extends env_dependencies_command_1.default {
|
|
9
9
|
get programmingLanguage() {
|
|
10
10
|
return 'PYTHON';
|
|
@@ -12,7 +12,8 @@ class PythonEnvDependencies extends env_dependencies_command_1.default {
|
|
|
12
12
|
async createEnv() {
|
|
13
13
|
try {
|
|
14
14
|
await new Promise((resolve, reject) => {
|
|
15
|
-
|
|
15
|
+
const python = process.platform === 'win32' ? 'python' : 'python3';
|
|
16
|
+
(0, node_child_process_1.exec)(`${python} -m venv ${JSON.stringify(this.envPath)}`, (error) => {
|
|
16
17
|
if (error) {
|
|
17
18
|
reject(error);
|
|
18
19
|
}
|
|
@@ -68,8 +69,8 @@ import json
|
|
|
68
69
|
`;
|
|
69
70
|
}
|
|
70
71
|
async ensureUv() {
|
|
71
|
-
const uvPath =
|
|
72
|
-
const pipPath =
|
|
72
|
+
const uvPath = (0, child_process_1.venvExecutablePath)(this.envPath, 'uv');
|
|
73
|
+
const pipPath = (0, child_process_1.venvExecutablePath)(this.envPath, 'pip');
|
|
73
74
|
if (!fs.existsSync(uvPath)) {
|
|
74
75
|
return new Promise((resolve, reject) => {
|
|
75
76
|
const proc = (0, node_child_process_1.spawn)(pipPath, ['install', '--force-reinstall', 'uv'], {
|
|
@@ -127,7 +127,7 @@ class ExecutionTask {
|
|
|
127
127
|
const exportVars = {
|
|
128
128
|
...createFilesResult,
|
|
129
129
|
FCODE_DEPENDENCIES_PATH: this._dependenciesPath,
|
|
130
|
-
FCODE_EXECUTION_PATH: [createFilesResult.FCODE_LIBRARY_PATH, this._dependenciesPath].filter((p) => p).join(
|
|
130
|
+
FCODE_EXECUTION_PATH: [createFilesResult.FCODE_LIBRARY_PATH, this._dependenciesPath].filter((p) => p).join(path.delimiter),
|
|
131
131
|
};
|
|
132
132
|
fs.writeFileSync(path.join(this._tempDir, 'METADATA'), Object.entries(exportVars)
|
|
133
133
|
.map(([key, value]) => `${key}=${value}`)
|
|
@@ -6,6 +6,7 @@ const fs = require("node:fs");
|
|
|
6
6
|
const path = require("node:path");
|
|
7
7
|
const execution_task_1 = require("./execution-task");
|
|
8
8
|
const source_code_sanitizer_1 = require("./source-code-sanitizer");
|
|
9
|
+
const child_process_1 = require("../../utils/child-process");
|
|
9
10
|
/**
|
|
10
11
|
* Task which handles native executions using child_process.
|
|
11
12
|
*/
|
|
@@ -18,11 +19,11 @@ class JavaScriptExecutionTask extends execution_task_1.default {
|
|
|
18
19
|
const fcodeLibPath = path.join(__dirname, '..', '..', 'runtime', 'libs', 'node');
|
|
19
20
|
const nodeModulesPath = path.join(this._dependenciesPath, 'node_modules');
|
|
20
21
|
const forked = (0, node_child_process_1.fork)(path.resolve(this._execFilePath), {
|
|
21
|
-
env: {
|
|
22
|
+
env: (0, child_process_1.childEnv)({
|
|
22
23
|
FORCE_COLOR: 'true',
|
|
23
|
-
NODE_PATH: [nodeModulesPath, nodePath, fcodeLibPath].filter((p) => p).join(
|
|
24
|
+
NODE_PATH: [nodeModulesPath, nodePath, fcodeLibPath].filter((p) => p).join(path.delimiter),
|
|
24
25
|
PATH: process.env.PATH,
|
|
25
|
-
},
|
|
26
|
+
}),
|
|
26
27
|
silent: false,
|
|
27
28
|
});
|
|
28
29
|
return new Promise((resolve, reject) => {
|
|
@@ -45,7 +46,7 @@ class JavaScriptExecutionTask extends execution_task_1.default {
|
|
|
45
46
|
if (this._options.hookFilePath) {
|
|
46
47
|
const fn = this._options.hookFunction ?? 'main';
|
|
47
48
|
return `
|
|
48
|
-
const _hooksModule = require(
|
|
49
|
+
const _hooksModule = require(${JSON.stringify(this._options.hookFilePath)})
|
|
49
50
|
const main = typeof _hooksModule['${fn}'] === 'function'
|
|
50
51
|
? _hooksModule['${fn}']
|
|
51
52
|
: async () => undefined`;
|
|
@@ -56,7 +57,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
56
57
|
}
|
|
57
58
|
processPath.push('index.js');
|
|
58
59
|
const fullPath = path.join(...processPath);
|
|
59
|
-
return `const { main }= require(
|
|
60
|
+
return `const { main }= require(${JSON.stringify(fullPath)})`;
|
|
60
61
|
}
|
|
61
62
|
async _createExecutionFiles(tempDir) {
|
|
62
63
|
if (!this._options.silent) {
|
|
@@ -64,7 +65,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
64
65
|
? process.stdout.write(JSON.stringify({ timestamp: new Date().toISOString(), level: 'DEBUG', message: `Creating execution files for '${this._process.slug}' in ${tempDir}` }) + '\n')
|
|
65
66
|
: console.debug(`Creating execution files for '${this._process.slug}' in ${tempDir}`);
|
|
66
67
|
}
|
|
67
|
-
const execFilePath = `${
|
|
68
|
+
const execFilePath = path.join(tempDir, `${this._process.slug}.js`);
|
|
68
69
|
const metadata = this.getMetadata();
|
|
69
70
|
const execution = metadata.execution;
|
|
70
71
|
execution.id = '00000000-0000-0000-0000-000000000000';
|
|
@@ -117,7 +118,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
117
118
|
const version = typeof tagOrOptions === 'string'
|
|
118
119
|
? tagOrOptions
|
|
119
120
|
: (tagOrOptions && typeof tagOrOptions === 'object' ? tagOrOptions.version : undefined);
|
|
120
|
-
let modulePath = require('path').join(
|
|
121
|
+
let modulePath = require('path').join(${JSON.stringify(process.cwd())}, 'modules', moduleName);
|
|
121
122
|
if(version) {
|
|
122
123
|
modulePath = require('path').join(modulePath, 'versions', version)
|
|
123
124
|
}
|
|
@@ -151,7 +152,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
151
152
|
datastore: {
|
|
152
153
|
async save(datastore) {
|
|
153
154
|
return new Promise((resolve, reject) => {
|
|
154
|
-
require('fs').writeFile(require('path').join(
|
|
155
|
+
require('fs').writeFile(require('path').join(${JSON.stringify(process.cwd())}, 'datastore.json'), JSON.stringify(datastore, null, 2), (err) => {
|
|
155
156
|
if (err) {
|
|
156
157
|
reject(err)
|
|
157
158
|
}
|
|
@@ -161,7 +162,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
161
162
|
},
|
|
162
163
|
getAll() {
|
|
163
164
|
try {
|
|
164
|
-
return require(require('path').join(
|
|
165
|
+
return require(require('path').join(${JSON.stringify(process.cwd())}, 'datastore.json'));
|
|
165
166
|
} catch (e) {
|
|
166
167
|
return {}
|
|
167
168
|
}
|
|
@@ -172,7 +173,10 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
172
173
|
}
|
|
173
174
|
throw new Error('Invalid argument type')
|
|
174
175
|
},
|
|
175
|
-
async set(key, value) {
|
|
176
|
+
async set(key, value, encrypted) {
|
|
177
|
+
if (encrypted !== undefined && typeof encrypted !== 'boolean') {
|
|
178
|
+
throw new Error('Invalid encrypted flag. Encrypted must be a boolean.')
|
|
179
|
+
}
|
|
176
180
|
if ((typeof key === 'string' || typeof key === 'number') && (typeof value === 'string' || typeof value === 'number')) {
|
|
177
181
|
const datastore = this.getAll()
|
|
178
182
|
datastore[key] = value
|
|
@@ -235,7 +239,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
try {
|
|
238
|
-
const storageDir = path.join(
|
|
242
|
+
const storageDir = path.join(${JSON.stringify(process.cwd())}, 'storage')
|
|
239
243
|
if (!fs.existsSync(storageDir)) {
|
|
240
244
|
fs.mkdirSync(storageDir)
|
|
241
245
|
}
|
|
@@ -338,7 +342,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
338
342
|
throw new Error('Storage list failed: prefix must be a string')
|
|
339
343
|
}
|
|
340
344
|
|
|
341
|
-
const storageDir = path.join(
|
|
345
|
+
const storageDir = path.join(${JSON.stringify(process.cwd())}, 'storage')
|
|
342
346
|
|
|
343
347
|
if (!fs.existsSync(storageDir)) {
|
|
344
348
|
return []
|
|
@@ -410,7 +414,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
410
414
|
return reject(new Error('Storage download failed: filename cannot be empty'))
|
|
411
415
|
}
|
|
412
416
|
|
|
413
|
-
const filePath = path.join(
|
|
417
|
+
const filePath = path.join(${JSON.stringify(process.cwd())}, 'storage', filename)
|
|
414
418
|
|
|
415
419
|
if (!fs.existsSync(filePath)) {
|
|
416
420
|
return reject(new Error(\`Storage download failed: file not found - \${filename}\`))
|
|
@@ -448,7 +452,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
448
452
|
return reject(new Error('Storage delete failed: filename cannot be empty'))
|
|
449
453
|
}
|
|
450
454
|
|
|
451
|
-
const filePath = path.join(
|
|
455
|
+
const filePath = path.join(${JSON.stringify(process.cwd())}, 'storage', filename)
|
|
452
456
|
|
|
453
457
|
if (!fs.existsSync(filePath)) {
|
|
454
458
|
return reject(new Error(\`Storage delete failed: file not found - \${filename}\`))
|
|
@@ -463,7 +467,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
463
467
|
fs.unlinkSync(filePath)
|
|
464
468
|
|
|
465
469
|
let dir = path.dirname(filePath)
|
|
466
|
-
const storageDir = path.join(
|
|
470
|
+
const storageDir = path.join(${JSON.stringify(process.cwd())}, 'storage')
|
|
467
471
|
|
|
468
472
|
while (dir !== storageDir && dir !== path.dirname(dir)) {
|
|
469
473
|
try {
|
|
@@ -501,7 +505,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
501
505
|
throw new Error('Storage createSignedUrl failed: expiresInSeconds must be an integer between 1 and 604800')
|
|
502
506
|
}
|
|
503
507
|
|
|
504
|
-
const filePath = path.join(
|
|
508
|
+
const filePath = path.join(${JSON.stringify(process.cwd())}, 'storage', filename)
|
|
505
509
|
|
|
506
510
|
if (!fs.existsSync(filePath)) {
|
|
507
511
|
throw new Error(\`Storage createSignedUrl failed: file not found - \${filename}\`)
|
|
@@ -532,7 +536,7 @@ const main = typeof _hooksModule['${fn}'] === 'function'
|
|
|
532
536
|
},
|
|
533
537
|
variables: (() => {
|
|
534
538
|
const fs = require('fs');
|
|
535
|
-
const localEnvPath = require('path').join(
|
|
539
|
+
const localEnvPath = require('path').join(${JSON.stringify(process.cwd())}, 'variables.local.env');
|
|
536
540
|
const baseVars = ${JSON.stringify(metadata.variables, null, 2)};
|
|
537
541
|
const readLocal = () => { try { return fs.readFileSync(localEnvPath, 'utf8') } catch { return '' } };
|
|
538
542
|
const parseEnv = (text) => {
|
|
@@ -7,15 +7,16 @@ const errors_1 = require("../errors");
|
|
|
7
7
|
const execution_task_1 = require("./execution-task");
|
|
8
8
|
const workspace_1 = require("../../config/workspace");
|
|
9
9
|
const source_code_sanitizer_1 = require("./source-code-sanitizer");
|
|
10
|
+
const child_process_1 = require("../../utils/child-process");
|
|
10
11
|
class PythonExecutionTask extends execution_task_1.default {
|
|
11
12
|
async run() {
|
|
12
13
|
if (!this._execFilePath) {
|
|
13
14
|
this.prepare();
|
|
14
15
|
}
|
|
15
16
|
const venvPath = (0, workspace_1.baseDependenciesPath)(this._programmingLanguage);
|
|
16
|
-
const forked = (0, node_child_process_1.spawn)(
|
|
17
|
+
const forked = (0, node_child_process_1.spawn)((0, child_process_1.venvPythonPath)(venvPath), ['-u', path.resolve(this._execFilePath)], {
|
|
17
18
|
stdio: 'inherit',
|
|
18
|
-
env: {},
|
|
19
|
+
env: (0, child_process_1.childEnv)({}),
|
|
19
20
|
});
|
|
20
21
|
return new Promise((resolve, reject) => {
|
|
21
22
|
forked.on('exit', (code) => {
|
|
@@ -76,7 +77,7 @@ _builtins.print = _json_print
|
|
|
76
77
|
return `import fcode as _imported_fcode_module
|
|
77
78
|
${jsonLogsSetup}
|
|
78
79
|
import importlib.util as _importlib_util
|
|
79
|
-
_spec = _importlib_util.spec_from_file_location("hooks",
|
|
80
|
+
_spec = _importlib_util.spec_from_file_location("hooks", ${JSON.stringify(this._options.hookFilePath)})
|
|
80
81
|
_hooks_module = _importlib_util.module_from_spec(_spec)
|
|
81
82
|
_spec.loader.exec_module(_hooks_module)
|
|
82
83
|
_hook_fn = getattr(_hooks_module, '${fn}', None)
|
|
@@ -143,8 +144,8 @@ if (hasattr(process, 'main')):
|
|
|
143
144
|
? process.stdout.write(JSON.stringify({ timestamp: new Date().toISOString(), level: 'DEBUG', message: `Creating execution files for '${this._process.slug}' in ${tempDir}` }) + '\n')
|
|
144
145
|
: console.debug(`Creating execution files for '${this._process.slug}' in ${tempDir}`);
|
|
145
146
|
}
|
|
146
|
-
const execFilePath = `${
|
|
147
|
-
const libraryFilePath =
|
|
147
|
+
const execFilePath = path.join(tempDir, `${this._process.slug}.py`);
|
|
148
|
+
const libraryFilePath = path.join(tempDir, 'initialize_params.py');
|
|
148
149
|
fs.writeFileSync(libraryFilePath, JSON.stringify(this.getMetadata()));
|
|
149
150
|
fs.writeFileSync(execFilePath, `
|
|
150
151
|
import sys
|
|
@@ -152,13 +153,13 @@ import os
|
|
|
152
153
|
import json
|
|
153
154
|
import traceback
|
|
154
155
|
|
|
155
|
-
sys.path.append(
|
|
156
|
-
sys.path.append(
|
|
156
|
+
sys.path.append(${JSON.stringify(this._dependenciesPath)})
|
|
157
|
+
sys.path.append(${JSON.stringify(path.join(__dirname, '..', '..', 'runtime', 'libs', 'python'))})
|
|
157
158
|
|
|
158
159
|
os.environ['FCODE_LOG_LEVEL'] = '${this._options.logLevel}'
|
|
159
|
-
os.environ['FCODE_RUNTIME_METADATA_PATH'] =
|
|
160
|
-
os.environ['FCODE_RETURN_FILE'] =
|
|
161
|
-
os.environ['FCODE_ERROR_FILE'] =
|
|
160
|
+
os.environ['FCODE_RUNTIME_METADATA_PATH'] = ${JSON.stringify(libraryFilePath)}
|
|
161
|
+
os.environ['FCODE_RETURN_FILE'] = ${JSON.stringify(this.returnValueFilePath)}
|
|
162
|
+
os.environ['FCODE_ERROR_FILE'] = ${JSON.stringify(this.errorValueFilePath)}
|
|
162
163
|
${this._options.jsonLogs ? `os.environ['FCODE_JSON_LOGS'] = 'true'` : ''}
|
|
163
164
|
${Object.entries(this.getVariablesObject()).map(([key, value]) => `if '${key}' not in os.environ: os.environ['${key}'] = ${JSON.stringify(value)}`).join('\n')}
|
|
164
165
|
|
|
@@ -15,14 +15,16 @@ class ResourcePusher {
|
|
|
15
15
|
}
|
|
16
16
|
async push(remoteResources, localResources, force) {
|
|
17
17
|
cli_1.default.log(`\nš©ļø Pushing ${this._repository._repositoryName}...`);
|
|
18
|
-
|
|
18
|
+
// Neither an inherited resource nor a deleted one the cloud keeps for its versions is pushed:
|
|
19
|
+
// the first is the parent's, the second only exists through what was already published.
|
|
20
|
+
for (const resource of localResources.filter((resource) => (0, types_1.isReadOnly)(resource))) {
|
|
19
21
|
if (await resource_checker_1.default.localResourceHasBeenModified(undefined, resource)) {
|
|
20
|
-
cli_1.default.log(color_1.default.red(`šØ '${resource.slug}' is
|
|
22
|
+
cli_1.default.log(color_1.default.red(`šØ '${resource.slug}' is ${(0, types_1.readOnlyReason)(resource)} and is read-only. ` +
|
|
21
23
|
`Run 'fcode ${this._repository._repositoryName}:pull' to restore it before pushing.`));
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
|
-
localResources = localResources.filter((resource) => !
|
|
25
|
-
remoteResources = remoteResources.filter((resource) => !
|
|
26
|
+
localResources = localResources.filter((resource) => !(0, types_1.isReadOnly)(resource));
|
|
27
|
+
remoteResources = remoteResources.filter((resource) => !(0, types_1.isReadOnly)(resource));
|
|
26
28
|
if (this._repository._repositoryName === 'variables') {
|
|
27
29
|
const localVariables = localResources;
|
|
28
30
|
const remoteVariables = remoteResources;
|
|
@@ -115,11 +117,12 @@ class ResourcePusher {
|
|
|
115
117
|
}
|
|
116
118
|
async removeResource(resource) {
|
|
117
119
|
try {
|
|
120
|
+
let removed;
|
|
118
121
|
if (this._repository._repositoryName === 'processes') {
|
|
119
|
-
await this._fcodeGraphQLClient.removeProcess(resource.id);
|
|
122
|
+
removed = await this._fcodeGraphQLClient.removeProcess(resource.id);
|
|
120
123
|
}
|
|
121
124
|
if (this._repository._repositoryName === 'modules') {
|
|
122
|
-
await this._fcodeGraphQLClient.removeScriptLibrary(resource.id);
|
|
125
|
+
removed = await this._fcodeGraphQLClient.removeScriptLibrary(resource.id);
|
|
123
126
|
}
|
|
124
127
|
if (this._repository._repositoryName === 'variables') {
|
|
125
128
|
await this._fcodeGraphQLClient.removeVariable(resource.id);
|
|
@@ -127,7 +130,10 @@ class ResourcePusher {
|
|
|
127
130
|
if (this._repository._repositoryName === 'i18n') {
|
|
128
131
|
// By identifier, not slug: an inherited locale is tracked under a qualified slug, and only
|
|
129
132
|
// this workspace's own locales ā where the two coincide ā ever reach a remote delete.
|
|
130
|
-
await this._fcodeGraphQLClient.removeLocale(resource.locale);
|
|
133
|
+
removed = await this._fcodeGraphQLClient.removeLocale(resource.locale);
|
|
134
|
+
}
|
|
135
|
+
if (removed?.deletedAt) {
|
|
136
|
+
cli_1.default.log(color_1.default.yellow(`š '${resource.slug}' is kept as deleted: workspace version(s) ${removed.retainingVersionTags.join(', ')} still contain it.`));
|
|
131
137
|
}
|
|
132
138
|
this._repository.removeMetadata(resource.slug);
|
|
133
139
|
}
|