@guanjinke/artifact-client 1.5.1 → 1.6.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/README.md +32 -3
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +6 -5
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/stored-client.d.ts +24 -0
- package/dist/cli/stored-client.d.ts.map +1 -0
- package/dist/cli/stored-client.js +59 -0
- package/dist/cli/stored-client.js.map +1 -0
- package/dist/cli/web.d.ts +23 -0
- package/dist/cli/web.d.ts.map +1 -0
- package/dist/cli/web.js +99 -0
- package/dist/cli/web.js.map +1 -0
- package/dist/environment/builder.d.ts.map +1 -1
- package/dist/environment/builder.js +26 -13
- package/dist/environment/builder.js.map +1 -1
- package/dist/environment/catalog.d.ts.map +1 -1
- package/dist/environment/catalog.js +18 -0
- package/dist/environment/catalog.js.map +1 -1
- package/dist/environment/config.d.ts +1 -1
- package/dist/environment/config.d.ts.map +1 -1
- package/dist/environment/config.js +7 -5
- package/dist/environment/config.js.map +1 -1
- package/dist/environment/manager.d.ts +9 -0
- package/dist/environment/manager.d.ts.map +1 -1
- package/dist/environment/manager.js +34 -6
- package/dist/environment/manager.js.map +1 -1
- package/dist/environment/plan.d.ts +37 -1
- package/dist/environment/plan.d.ts.map +1 -1
- package/dist/environment/plan.js +71 -16
- package/dist/environment/plan.js.map +1 -1
- package/dist/environment/posix-process.d.ts +71 -0
- package/dist/environment/posix-process.d.ts.map +1 -0
- package/dist/environment/posix-process.js +393 -0
- package/dist/environment/posix-process.js.map +1 -0
- package/dist/environment/process.d.ts +3 -1
- package/dist/environment/process.d.ts.map +1 -1
- package/dist/environment/process.js +5 -2
- package/dist/environment/process.js.map +1 -1
- package/dist/environment/registry.d.ts.map +1 -1
- package/dist/environment/registry.js +2 -1
- package/dist/environment/registry.js.map +1 -1
- package/dist/environment/root.d.ts +24 -6
- package/dist/environment/root.d.ts.map +1 -1
- package/dist/environment/root.js +78 -24
- package/dist/environment/root.js.map +1 -1
- package/dist/environment/types.d.ts +7 -2
- package/dist/environment/types.d.ts.map +1 -1
- package/dist/environment/update.d.ts +3 -1
- package/dist/environment/update.d.ts.map +1 -1
- package/dist/environment/update.js +48 -36
- package/dist/environment/update.js.map +1 -1
- package/dist/environment/validate.d.ts.map +1 -1
- package/dist/environment/validate.js +5 -1
- package/dist/environment/validate.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/atomic.d.ts +10 -0
- package/dist/utils/atomic.d.ts.map +1 -0
- package/dist/utils/atomic.js +65 -0
- package/dist/utils/atomic.js.map +1 -0
- package/dist/utils/local-path.d.ts +14 -0
- package/dist/utils/local-path.d.ts.map +1 -1
- package/dist/utils/local-path.js +25 -0
- package/dist/utils/local-path.js.map +1 -1
- package/dist/web/api.d.ts +28 -0
- package/dist/web/api.d.ts.map +1 -0
- package/dist/web/api.js +336 -0
- package/dist/web/api.js.map +1 -0
- package/dist/web/assets.d.ts +26 -0
- package/dist/web/assets.d.ts.map +1 -0
- package/dist/web/assets.js +87 -0
- package/dist/web/assets.js.map +1 -0
- package/dist/web/http.d.ts +41 -0
- package/dist/web/http.d.ts.map +1 -0
- package/dist/web/http.js +167 -0
- package/dist/web/http.js.map +1 -0
- package/dist/web/jobs.d.ts +69 -0
- package/dist/web/jobs.d.ts.map +1 -0
- package/dist/web/jobs.js +110 -0
- package/dist/web/jobs.js.map +1 -0
- package/dist/web/providers.d.ts +12 -0
- package/dist/web/providers.d.ts.map +1 -0
- package/dist/web/providers.js +108 -0
- package/dist/web/providers.js.map +1 -0
- package/dist/web/server.d.ts +43 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +148 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/static/app.js +59 -0
- package/dist/web/static/favicon.svg +12 -0
- package/dist/web/static/index.html +15 -0
- package/dist/web/static/styles.css +1333 -0
- package/dist/web/types.d.ts +82 -0
- package/dist/web/types.d.ts.map +1 -0
- package/dist/web/types.js +3 -0
- package/dist/web/types.js.map +1 -0
- package/package.json +9 -2
|
@@ -1,15 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonicalize a directory that may not exist yet: the deepest existing
|
|
3
|
+
* ancestor is resolved (`fs.realpath`), the missing tail is appended.
|
|
4
|
+
*
|
|
5
|
+
* This is what makes the tool work on macOS, where `$TMPDIR` lives under
|
|
6
|
+
* `/var/folders/...` and `/var` is itself a symlink to `/private/var`: the
|
|
7
|
+
* stored root is the real location, so the "no linked ancestor" rule below
|
|
8
|
+
* rejects only links the operator created, and deletion later removes exactly
|
|
9
|
+
* the recorded directory instead of traversing a link.
|
|
10
|
+
*/
|
|
11
|
+
export declare function canonicalDirectory(directory: string): Promise<string>;
|
|
12
|
+
/**
|
|
13
|
+
* macOS ships `/var`, `/tmp` and `/etc` as symlinks into `/private`. Those are
|
|
14
|
+
* system links rather than operator ones, so the "no linked ancestor" rule has to
|
|
15
|
+
* let them through or `$TMPDIR` paths could never be used; the recorded root is
|
|
16
|
+
* still the canonical location, so nothing is ever operated through the link.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isSystemLinkTarget(resolved: string, platform?: NodeJS.Platform): boolean;
|
|
1
19
|
/**
|
|
2
20
|
* Verify that a directory is safe to use as an environment directory or as the
|
|
3
21
|
* unified directory that contains managed environments.
|
|
4
22
|
*
|
|
5
23
|
* Rejected locations are filesystem roots, the user profile itself, the AFM
|
|
6
|
-
* configuration directory,
|
|
7
|
-
* configuration directory, and any path with an existing linked (symlink or
|
|
8
|
-
* junction) ancestor. The check is read-only;
|
|
9
|
-
* anything and returns whether the directory already
|
|
10
|
-
* directory.
|
|
24
|
+
* configuration directory, system locations and their descendants, ancestors of
|
|
25
|
+
* the configuration directory, and any path with an existing linked (symlink or
|
|
26
|
+
* junction) ancestor other than a platform system link. The check is read-only;
|
|
27
|
+
* it never creates or removes anything and returns whether the directory already
|
|
28
|
+
* exists as a regular directory.
|
|
11
29
|
*/
|
|
12
|
-
export declare function inspectEnvironmentDirectory(directory: string, configDirectory: string): Promise<boolean>;
|
|
30
|
+
export declare function inspectEnvironmentDirectory(directory: string, configDirectory: string, platform?: NodeJS.Platform): Promise<boolean>;
|
|
13
31
|
export interface EnvironmentContainer {
|
|
14
32
|
directory: string;
|
|
15
33
|
created: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../src/environment/root.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;GAUG;AACH,wBAAsB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"root.d.ts","sourceRoot":"","sources":["../../src/environment/root.ts"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAc3E;AAUD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,OAAO,CAE1G;AAqBD;;;;;;;;;;GAUG;AACH,wBAAsB,2BAA2B,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,OAAO,CAAC,OAAO,CAAC,CAY5J;AAED,MAAM,WAAW,oBAAoB;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;CAAE;AAE9E;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAS3J;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMxF"}
|
package/dist/environment/root.js
CHANGED
|
@@ -33,6 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.canonicalDirectory = canonicalDirectory;
|
|
37
|
+
exports.isSystemLinkTarget = isSystemLinkTarget;
|
|
36
38
|
exports.inspectEnvironmentDirectory = inspectEnvironmentDirectory;
|
|
37
39
|
exports.resolveEnvironmentContainer = resolveEnvironmentContainer;
|
|
38
40
|
exports.resolveNamedEnvironmentDirectory = resolveNamedEnvironmentDirectory;
|
|
@@ -41,40 +43,67 @@ const os = __importStar(require("os"));
|
|
|
41
43
|
const path = __importStar(require("path"));
|
|
42
44
|
const registry_1 = require("./registry");
|
|
43
45
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
+
* Canonicalize a directory that may not exist yet: the deepest existing
|
|
47
|
+
* ancestor is resolved (`fs.realpath`), the missing tail is appended.
|
|
46
48
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* directory.
|
|
49
|
+
* This is what makes the tool work on macOS, where `$TMPDIR` lives under
|
|
50
|
+
* `/var/folders/...` and `/var` is itself a symlink to `/private/var`: the
|
|
51
|
+
* stored root is the real location, so the "no linked ancestor" rule below
|
|
52
|
+
* rejects only links the operator created, and deletion later removes exactly
|
|
53
|
+
* the recorded directory instead of traversing a link.
|
|
53
54
|
*/
|
|
54
|
-
async function
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
async function canonicalDirectory(directory) {
|
|
56
|
+
const absolute = path.resolve(directory);
|
|
57
|
+
const tail = [];
|
|
58
|
+
for (let current = absolute;; current = path.dirname(current)) {
|
|
59
|
+
try {
|
|
60
|
+
const resolved = await fs.realpath(current);
|
|
61
|
+
return tail.length ? path.join(resolved, ...tail.reverse()) : resolved;
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error.code !== 'ENOENT')
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
const parent = path.dirname(current);
|
|
68
|
+
if (parent === current)
|
|
69
|
+
return absolute;
|
|
70
|
+
tail.push(path.basename(current));
|
|
66
71
|
}
|
|
72
|
+
}
|
|
73
|
+
/** System locations that must never receive an environment, per platform. */
|
|
74
|
+
function systemRoots(platform = process.platform) {
|
|
75
|
+
const variables = platform === 'win32'
|
|
76
|
+
? [process.env.ProgramFiles, process.env['ProgramFiles(x86)'], process.env.SystemRoot, process.env.WINDIR]
|
|
77
|
+
: ['/usr', '/etc', '/bin', '/sbin', '/lib', '/lib64', '/boot', '/dev', '/proc', '/sys', '/opt', '/System', '/Library', '/Applications'];
|
|
78
|
+
return variables.filter((value) => typeof value === 'string' && value.trim() !== '').map(value => path.resolve(value).toLowerCase());
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* macOS ships `/var`, `/tmp` and `/etc` as symlinks into `/private`. Those are
|
|
82
|
+
* system links rather than operator ones, so the "no linked ancestor" rule has to
|
|
83
|
+
* let them through or `$TMPDIR` paths could never be used; the recorded root is
|
|
84
|
+
* still the canonical location, so nothing is ever operated through the link.
|
|
85
|
+
*/
|
|
86
|
+
function isSystemLinkTarget(resolved, platform = process.platform) {
|
|
87
|
+
return platform === 'darwin' && ['/private/var', '/private/tmp', '/private/etc', '/private/var/run'].includes(resolved);
|
|
88
|
+
}
|
|
89
|
+
/** Reject a linked or non-directory ancestor, allowing only a platform system link. */
|
|
90
|
+
async function assertRegularAncestors(requested, platform) {
|
|
67
91
|
let exists = true;
|
|
68
|
-
for (let current =
|
|
92
|
+
for (let current = requested;; current = path.dirname(current)) {
|
|
69
93
|
try {
|
|
70
94
|
const stat = await fs.lstat(current);
|
|
71
|
-
if (
|
|
95
|
+
if (stat.isSymbolicLink()) {
|
|
96
|
+
const resolved = await fs.realpath(current).catch(() => '');
|
|
97
|
+
if (!isSystemLinkTarget(resolved, platform))
|
|
98
|
+
throw new Error(`Environment root or ancestor is linked or not a directory: ${current}`);
|
|
99
|
+
}
|
|
100
|
+
else if (!stat.isDirectory())
|
|
72
101
|
throw new Error(`Environment root or ancestor is linked or not a directory: ${current}`);
|
|
73
102
|
}
|
|
74
103
|
catch (error) {
|
|
75
104
|
if (error.code !== 'ENOENT')
|
|
76
105
|
throw error;
|
|
77
|
-
if (current ===
|
|
106
|
+
if (current === requested)
|
|
78
107
|
exists = false;
|
|
79
108
|
}
|
|
80
109
|
if (current === path.dirname(current))
|
|
@@ -82,6 +111,31 @@ async function inspectEnvironmentDirectory(directory, configDirectory) {
|
|
|
82
111
|
}
|
|
83
112
|
return exists;
|
|
84
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Verify that a directory is safe to use as an environment directory or as the
|
|
116
|
+
* unified directory that contains managed environments.
|
|
117
|
+
*
|
|
118
|
+
* Rejected locations are filesystem roots, the user profile itself, the AFM
|
|
119
|
+
* configuration directory, system locations and their descendants, ancestors of
|
|
120
|
+
* the configuration directory, and any path with an existing linked (symlink or
|
|
121
|
+
* junction) ancestor other than a platform system link. The check is read-only;
|
|
122
|
+
* it never creates or removes anything and returns whether the directory already
|
|
123
|
+
* exists as a regular directory.
|
|
124
|
+
*/
|
|
125
|
+
async function inspectEnvironmentDirectory(directory, configDirectory, platform = process.platform) {
|
|
126
|
+
const requested = path.resolve(directory);
|
|
127
|
+
const root = await canonicalDirectory(requested);
|
|
128
|
+
if (root === path.parse(root).root)
|
|
129
|
+
throw new Error(`Protected environment root: ${root} is a filesystem root.`);
|
|
130
|
+
const key = root.toLowerCase();
|
|
131
|
+
const home = (await canonicalDirectory(os.homedir())).toLowerCase();
|
|
132
|
+
const config = (await canonicalDirectory(configDirectory)).toLowerCase();
|
|
133
|
+
const protectedRoots = [home, config, ...systemRoots(platform)];
|
|
134
|
+
if (protectedRoots.some(value => key === value || (value !== home && key.startsWith(value + path.sep))) || config.startsWith(key + path.sep)) {
|
|
135
|
+
throw new Error(`Protected environment root: ${root} is a system, user profile or configuration location.`);
|
|
136
|
+
}
|
|
137
|
+
return assertRegularAncestors(requested, platform);
|
|
138
|
+
}
|
|
85
139
|
/**
|
|
86
140
|
* Validate the unified directory that holds managed environments.
|
|
87
141
|
*
|
|
@@ -93,7 +147,7 @@ async function inspectEnvironmentDirectory(directory, configDirectory) {
|
|
|
93
147
|
async function resolveEnvironmentContainer(input, configDirectory, options = {}) {
|
|
94
148
|
if (typeof input !== 'string' || input.trim() === '')
|
|
95
149
|
throw new Error('Environment root must be a non-empty directory path.');
|
|
96
|
-
const directory =
|
|
150
|
+
const directory = await canonicalDirectory(input);
|
|
97
151
|
if (await inspectEnvironmentDirectory(directory, configDirectory))
|
|
98
152
|
return { directory, created: false };
|
|
99
153
|
if (!options.create)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/environment/root.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"root.js","sourceRoot":"","sources":["../../src/environment/root.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArtifactClient } from '../artifact-client';
|
|
2
|
-
export type EnvironmentModule = 'dashboard' | 'reporting' | 'analysis' | 'sheets' | 'documents';
|
|
2
|
+
export type EnvironmentModule = 'dashboard' | 'reporting' | 'analysis' | 'sheets' | 'documents' | 'collaboration';
|
|
3
3
|
export interface EnvironmentOptions {
|
|
4
4
|
root: string;
|
|
5
5
|
major: string;
|
|
@@ -13,8 +13,13 @@ export type EnvironmentClient = Pick<ArtifactClient, 'getLatestVersion' | 'listA
|
|
|
13
13
|
export interface LayoutMapping {
|
|
14
14
|
source: string;
|
|
15
15
|
destination: string;
|
|
16
|
+
/**
|
|
17
|
+
* .NET assemblies this mapping must contain. Empty for a `service` mapping:
|
|
18
|
+
* an out-of-process native service that ships no managed assembly and is
|
|
19
|
+
* loaded by the Server from its `<Services>` declaration alone.
|
|
20
|
+
*/
|
|
16
21
|
assemblies: string[];
|
|
17
|
-
role: 'plugin' | 'worker' | 'server' | 'monitor';
|
|
22
|
+
role: 'plugin' | 'worker' | 'server' | 'monitor' | 'service';
|
|
18
23
|
service?: string;
|
|
19
24
|
}
|
|
20
25
|
export interface EnvironmentArtifact {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/environment/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/environment/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,eAAe,CAAC;AAClH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACtB,OAAO,CAAC,EAAE,UAAU,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AACD,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,cAAc,EAAE,kBAAkB,GAAG,eAAe,GAAG,kBAAkB,CAAC,CAAC;AAChH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AACD,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,MAAM,CAAC;AAC/C,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACtC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AACD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AACD,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAE5D,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,gEAAgE;IAChE,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { EnvironmentRegistry } from './registry';
|
|
2
2
|
import { ProcessBackend } from './process';
|
|
3
3
|
import { EnvironmentClient, EnvironmentProgress } from './types';
|
|
4
|
+
/** Modules `update-env` may replace; exported so the web interface lists the same set. */
|
|
5
|
+
export declare const updatableModules: string[];
|
|
4
6
|
export interface ModuleUpdateSpec {
|
|
5
7
|
module: string;
|
|
6
8
|
version?: string;
|
|
@@ -81,7 +83,7 @@ export declare function parseModuleSpecs(values: string[]): ModuleUpdateSpec[];
|
|
|
81
83
|
* `Disabled`; a configuration without that node is updated through
|
|
82
84
|
* `<PluginWorkers>` alone.
|
|
83
85
|
*/
|
|
84
|
-
export declare function patchEnvironmentConfiguration(xml: string, entries: PluginEntry[]): string;
|
|
86
|
+
export declare function patchEnvironmentConfiguration(xml: string, entries: PluginEntry[], platform?: NodeJS.Platform): string;
|
|
85
87
|
/**
|
|
86
88
|
* Update selected modules of a registered environment.
|
|
87
89
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/environment/update.ts"],"names":[],"mappings":"AAOA,OAAO,EAAqB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE,OAAO,EAAE,cAAc,EAAyB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/environment/update.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.EnvironmentUpdater = void 0;
|
|
36
|
+
exports.EnvironmentUpdater = exports.updatableModules = void 0;
|
|
37
37
|
exports.parseModuleSpecs = parseModuleSpecs;
|
|
38
38
|
exports.patchEnvironmentConfiguration = patchEnvironmentConfiguration;
|
|
39
39
|
const fs = __importStar(require("fs/promises"));
|
|
@@ -45,22 +45,28 @@ const builder_1 = require("./builder");
|
|
|
45
45
|
const registry_1 = require("./registry");
|
|
46
46
|
const validate_1 = require("./validate");
|
|
47
47
|
const process_1 = require("./process");
|
|
48
|
+
const posix_process_1 = require("./posix-process");
|
|
49
|
+
const atomic_1 = require("../utils/atomic");
|
|
50
|
+
const local_path_1 = require("../utils/local-path");
|
|
48
51
|
/** Same parser options as the creation path, so a rewrite round-trips identically. */
|
|
49
52
|
const parserOptions = { ignoreAttributes: false, parseTagValue: false, processEntities: false };
|
|
50
53
|
const builderOptions = { ignoreAttributes: false, format: true, suppressEmptyNode: false };
|
|
51
|
-
const windowsPath = (value) =>
|
|
52
|
-
|
|
54
|
+
const windowsPath = (value, platform) => (0, local_path_1.nativeSeparators)(value, platform);
|
|
55
|
+
/** The separator the recorded entries use on the target platform. */
|
|
56
|
+
const separatorOf = (platform) => (platform === 'win32' ? '\\' : '/');
|
|
57
|
+
/** Modules `update-env` may replace; exported so the web interface lists the same set. */
|
|
58
|
+
exports.updatableModules = ['dashboard', 'reporting', 'sheets', 'documents', 'analysis', 'common'];
|
|
53
59
|
const installationDirectory = (root, destination) => path.join(root, ...destination.split('/'));
|
|
54
60
|
function validateUpdatableModule(module) {
|
|
55
|
-
if (updatableModules.includes(module))
|
|
61
|
+
if (exports.updatableModules.includes(module))
|
|
56
62
|
return;
|
|
57
63
|
if (module === 'server')
|
|
58
64
|
throw new Error('Module server cannot be updated: it defines the environment runtime and configuration schema. Recreate the environment with create-env instead.');
|
|
59
65
|
if (module === 'monitoring')
|
|
60
66
|
throw new Error('Module monitoring cannot be updated: it defines the configuration schema and monitor runtime. Recreate the environment with create-env instead.');
|
|
61
|
-
if (module === '
|
|
62
|
-
throw new Error('Module documents
|
|
63
|
-
throw new Error(`Unsupported module "${module}": updateable modules are dashboard, reporting, sheets, analysis and common.`);
|
|
67
|
+
if (module === 'collaboration')
|
|
68
|
+
throw new Error('Module collaboration is deployed together with documents by create-env and the Server loads it from its own configuration entry; it is not updated on its own. Update `documents`, or recreate the environment.');
|
|
69
|
+
throw new Error(`Unsupported module "${module}": updateable modules are dashboard, reporting, sheets, documents, analysis and common.`);
|
|
64
70
|
}
|
|
65
71
|
/** `all` is the only allowed pseudo-module: every configured module from remote. */
|
|
66
72
|
const allModules = 'all';
|
|
@@ -208,24 +214,24 @@ function stringList(raw) {
|
|
|
208
214
|
return list;
|
|
209
215
|
}
|
|
210
216
|
/** Replace or append one `<sys:string>` path list, matching by destination or assembly name. */
|
|
211
|
-
function rewritePathList(values, entries) {
|
|
217
|
+
function rewritePathList(values, entries, platform) {
|
|
212
218
|
const strings = values.map(value => value.trim());
|
|
213
219
|
const used = new Set();
|
|
214
220
|
const appended = [];
|
|
215
221
|
for (const entry of entries) {
|
|
216
|
-
const prefix = windowsPath(entry.destination).toLowerCase() +
|
|
222
|
+
const prefix = windowsPath(entry.destination, platform).toLowerCase() + separatorOf(platform);
|
|
217
223
|
const assemblies = new Set(entry.assemblies.map(name => name.toLowerCase()));
|
|
218
224
|
const index = strings.findIndex((value, candidate) => {
|
|
219
225
|
if (used.has(candidate))
|
|
220
226
|
return false;
|
|
221
|
-
const folded = windowsPath(value).toLowerCase();
|
|
222
|
-
return folded.startsWith(prefix) || assemblies.has(
|
|
227
|
+
const folded = windowsPath(value, platform).toLowerCase();
|
|
228
|
+
return folded.startsWith(prefix) || assemblies.has((0, local_path_1.baseNameOf)(folded));
|
|
223
229
|
});
|
|
224
230
|
if (index < 0)
|
|
225
|
-
appended.push(windowsPath(entry.path));
|
|
231
|
+
appended.push(windowsPath(entry.path, platform));
|
|
226
232
|
else {
|
|
227
233
|
used.add(index);
|
|
228
|
-
strings[index] = windowsPath(entry.path);
|
|
234
|
+
strings[index] = windowsPath(entry.path, platform);
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
237
|
return [...strings, ...appended];
|
|
@@ -242,7 +248,7 @@ function rewritePathList(values, entries) {
|
|
|
242
248
|
* `Disabled`; a configuration without that node is updated through
|
|
243
249
|
* `<PluginWorkers>` alone.
|
|
244
250
|
*/
|
|
245
|
-
function patchEnvironmentConfiguration(xml, entries) {
|
|
251
|
+
function patchEnvironmentConfiguration(xml, entries, platform = process.platform) {
|
|
246
252
|
if (typeof xml !== 'string' || /<!DOCTYPE|<!ENTITY/i.test(xml) || fast_xml_parser_1.XMLValidator.validate(xml) !== true)
|
|
247
253
|
throw new Error('Invalid environment configuration.');
|
|
248
254
|
const document = new fast_xml_parser_1.XMLParser(parserOptions).parse(xml);
|
|
@@ -254,11 +260,11 @@ function patchEnvironmentConfiguration(xml, entries) {
|
|
|
254
260
|
const plugins = server.Plugins === undefined || server.Plugins === '' ? {} : server.Plugins;
|
|
255
261
|
if (typeof plugins !== 'object' || Array.isArray(plugins))
|
|
256
262
|
throw new Error('Invalid environment configuration.');
|
|
257
|
-
const combined = rewritePathList(stringList(plugins['sys:string']), pluginEntries);
|
|
263
|
+
const combined = rewritePathList(stringList(plugins['sys:string']), pluginEntries, platform);
|
|
258
264
|
// Keep Dashboard first even when it is a local build path rather than a deployed one.
|
|
259
265
|
const dashboard = combined.findIndex(value => {
|
|
260
|
-
const folded = windowsPath(value).toLowerCase();
|
|
261
|
-
return folded.startsWith('plugins\\dashboard\\') ||
|
|
266
|
+
const folded = windowsPath(value, platform).toLowerCase();
|
|
267
|
+
return folded.startsWith(separatorOf(platform) === '\\' ? 'plugins\\dashboard\\' : 'plugins/dashboard/') || (0, local_path_1.baseNameOf)(folded) === 'wyn.dashboards.plugin.dll';
|
|
262
268
|
});
|
|
263
269
|
if (dashboard > 0)
|
|
264
270
|
combined.unshift(combined.splice(dashboard, 1)[0]);
|
|
@@ -270,7 +276,7 @@ function patchEnvironmentConfiguration(xml, entries) {
|
|
|
270
276
|
const pluginWorkers = server.PluginWorkers === undefined || server.PluginWorkers === '' ? {} : server.PluginWorkers;
|
|
271
277
|
if (typeof pluginWorkers !== 'object' || Array.isArray(pluginWorkers))
|
|
272
278
|
throw new Error('Invalid environment configuration.');
|
|
273
|
-
pluginWorkers['sys:string'] = rewritePathList(stringList(pluginWorkers['sys:string']), workers);
|
|
279
|
+
pluginWorkers['sys:string'] = rewritePathList(stringList(pluginWorkers['sys:string']), workers, platform);
|
|
274
280
|
server.PluginWorkers = pluginWorkers;
|
|
275
281
|
const services = document?.SystemConfig?.Services;
|
|
276
282
|
for (const entry of workers) {
|
|
@@ -282,8 +288,8 @@ function patchEnvironmentConfiguration(xml, entries) {
|
|
|
282
288
|
const node = service;
|
|
283
289
|
// The worker is loaded from the path list above and uses its own directory
|
|
284
290
|
// as its base directory: keep the service in step without touching Disabled.
|
|
285
|
-
node.WorkingDirectory = windowsPath(
|
|
286
|
-
node.Assembly =
|
|
291
|
+
node.WorkingDirectory = windowsPath((0, local_path_1.directoryOf)(entry.path, platform), platform);
|
|
292
|
+
node.Assembly = (0, local_path_1.baseNameOf)(entry.path);
|
|
287
293
|
}
|
|
288
294
|
}
|
|
289
295
|
const output = new fast_xml_parser_1.XMLBuilder(builderOptions).build(document);
|
|
@@ -361,7 +367,7 @@ function manifestSource(module, targets, previous) {
|
|
|
361
367
|
async function writeAtomic(file, content) {
|
|
362
368
|
const temporary = `${file}.afm-tmp`;
|
|
363
369
|
await fs.writeFile(temporary, content, 'utf8');
|
|
364
|
-
await
|
|
370
|
+
await (0, atomic_1.renameAtomic)(temporary, file);
|
|
365
371
|
}
|
|
366
372
|
const writeJsonAtomic = (file, value) => writeAtomic(file, JSON.stringify(value, null, 2) + '\n');
|
|
367
373
|
/**
|
|
@@ -469,7 +475,7 @@ async function resolveLocalSource(entry, module, assembly, input) {
|
|
|
469
475
|
if (path.extname(source).toLowerCase() !== '.dll')
|
|
470
476
|
throw new Error(`Local source must be a .dll file: ${source}.`);
|
|
471
477
|
if (assembly === undefined) {
|
|
472
|
-
const name =
|
|
478
|
+
const name = (0, local_path_1.baseNameOf)(source).toLowerCase();
|
|
473
479
|
const matches = mappings.filter(mapping => mapping.assemblies.some(known => known.toLowerCase() === name));
|
|
474
480
|
if (matches.length !== 1)
|
|
475
481
|
throw new Error(`Local source ${source} matches ${matches.length} targets of module ${module}. Expected one of ${expectedAssemblies(module).join(', ')}; select one explicitly with ${module}#<assembly>=<path>.`);
|
|
@@ -480,7 +486,7 @@ async function resolveLocalSource(entry, module, assembly, input) {
|
|
|
480
486
|
const named = mappingForAssembly(module, assembly);
|
|
481
487
|
// The explicit form exists for a build whose file name matches no assembly;
|
|
482
488
|
// a file that is another target's assembly is still a mistake.
|
|
483
|
-
const basename =
|
|
489
|
+
const basename = (0, local_path_1.baseNameOf)(source);
|
|
484
490
|
const conflicts = mappings.filter(mapping => mapping !== named.mapping && mapping.assemblies.some(known => known.toLowerCase() === basename.toLowerCase()));
|
|
485
491
|
if (conflicts.length)
|
|
486
492
|
throw new Error(`Local source ${source} is an assembly of ${conflicts.map(mapping => mapping.destination).join(', ')}, not of ${named.mapping.destination}: ${module}#${assembly}= selects ${named.mapping.destination}.`);
|
|
@@ -544,15 +550,13 @@ class EnvironmentUpdater {
|
|
|
544
550
|
constructor(dependencies = {}) {
|
|
545
551
|
this.dependencies = dependencies;
|
|
546
552
|
this.registry = dependencies.registry ?? new registry_1.EnvironmentRegistry();
|
|
547
|
-
this.processes = dependencies.processes ?? new process_1.WindowsProcessBackend();
|
|
553
|
+
this.processes = dependencies.processes ?? (process.platform === 'win32' ? new process_1.WindowsProcessBackend() : new posix_process_1.PosixProcessBackend());
|
|
548
554
|
this.platform = dependencies.platform ?? process.platform;
|
|
549
555
|
this.onProgress = dependencies.onProgress;
|
|
550
556
|
}
|
|
551
557
|
async update(name, specs, clientFactory, options = {}) {
|
|
552
558
|
const dryRun = options.dryRun === true;
|
|
553
559
|
const onProgress = options.onProgress ?? this.onProgress;
|
|
554
|
-
if (!dryRun && this.platform !== 'win32')
|
|
555
|
-
throw new Error('Environment execution is Windows-only. Use dry-run on other platforms.');
|
|
556
560
|
onProgress?.('Validating module specs');
|
|
557
561
|
let parsed = normalizeModuleSpecs(specs);
|
|
558
562
|
if (!parsed.length)
|
|
@@ -564,12 +568,13 @@ class EnvironmentUpdater {
|
|
|
564
568
|
await (0, validate_1.validateEnvironmentTree)(entry.root);
|
|
565
569
|
const manifest = await readManifest(entry.root);
|
|
566
570
|
const artifacts = [...(manifest.artifacts ?? [])];
|
|
571
|
+
const installed = new Set(artifacts.map(artifact => artifact.module));
|
|
567
572
|
const skipped = [];
|
|
568
573
|
if (parsed.some(spec => spec.module === 'all')) {
|
|
569
574
|
// `all` means every configured module from remote; modules that already
|
|
570
575
|
// point at a local developer build are left exactly as they are.
|
|
571
576
|
const localModules = new Set([...Object.keys(manifest.moduleSources ?? {}), ...(entry.localModules ?? [])]);
|
|
572
|
-
const configured = [...new Set(artifacts.map(artifact => artifact.module))].filter(module => updatableModules.includes(module)).sort();
|
|
577
|
+
const configured = [...new Set(artifacts.map(artifact => artifact.module))].filter(module => exports.updatableModules.includes(module)).sort();
|
|
573
578
|
for (const module of configured)
|
|
574
579
|
if (localModules.has(module))
|
|
575
580
|
skipped.push({ module, reason: 'local' });
|
|
@@ -582,8 +587,8 @@ class EnvironmentUpdater {
|
|
|
582
587
|
const localOverrides = new Map();
|
|
583
588
|
const selectedTargets = new Set();
|
|
584
589
|
for (const spec of parsed) {
|
|
585
|
-
if (spec.module
|
|
586
|
-
throw new Error(`Module
|
|
590
|
+
if (['sheets', 'documents'].includes(spec.module) && entry.edition !== 'en')
|
|
591
|
+
throw new Error(`Module ${spec.module} requires an EN edition environment; ${entry.name} is ${entry.edition}.`);
|
|
587
592
|
if (spec.localPath === undefined)
|
|
588
593
|
continue;
|
|
589
594
|
const resolution = await resolveLocalSource(entry, spec.module, spec.assembly, spec.localPath);
|
|
@@ -599,6 +604,14 @@ class EnvironmentUpdater {
|
|
|
599
604
|
localOverrides.set(spec.module, targets);
|
|
600
605
|
}
|
|
601
606
|
const remote = parsed.filter(spec => spec.localPath === undefined);
|
|
607
|
+
// Smart documents cannot run without the collaboration service, which
|
|
608
|
+
// create-env deploys and declares in the Server configuration alongside
|
|
609
|
+
// documents. Installing documents into an environment with no collaboration
|
|
610
|
+
// deployment would produce a broken environment, so refuse — after the
|
|
611
|
+
// edition gate above, so a CN environment still reports the EN requirement.
|
|
612
|
+
if (parsed.some(spec => spec.module === 'documents') && !installed.has('collaboration')) {
|
|
613
|
+
throw new Error(`Module documents requires the collaboration service, which ${entry.name} has not deployed. Recreate the environment with create-env: selecting documents deploys collaboration automatically.`);
|
|
614
|
+
}
|
|
602
615
|
const state = await (0, validate_1.observeRuntimeState)(entry, this.processes);
|
|
603
616
|
if (remote.length && state !== 'ready' && state !== 'stopped')
|
|
604
617
|
throw new Error(`Cannot update modules from a remote source while ${entry.name} is ${state}: deployed files may be in use. Run \`afm env stop ${entry.name}\` first.`);
|
|
@@ -607,7 +620,6 @@ class EnvironmentUpdater {
|
|
|
607
620
|
const downloads = [...(manifest.downloads ?? [])];
|
|
608
621
|
const selectedModules = manifest.selectedModules === undefined ? undefined : [...manifest.selectedModules];
|
|
609
622
|
const moduleSources = { ...(manifest.moduleSources ?? {}) };
|
|
610
|
-
const installed = new Set(artifacts.map(artifact => artifact.module));
|
|
611
623
|
const workspace = remote.length && !dryRun ? await fs.mkdtemp(path.join(path.dirname(entry.root), '.afm-env-')) : undefined;
|
|
612
624
|
const warnings = [];
|
|
613
625
|
try {
|
|
@@ -671,7 +683,7 @@ class EnvironmentUpdater {
|
|
|
671
683
|
if (stagedArtifact)
|
|
672
684
|
copies.push({ source: path.join(stagedArtifact.expanded, mapping.source), destination });
|
|
673
685
|
copiedDirectories.push(mapping.destination);
|
|
674
|
-
const assembly = stagedArtifact?.assemblies.get(mapping.destination) ?? knownAssembly(configured, mapping);
|
|
686
|
+
const assembly = stagedArtifact?.assemblies.get(mapping.destination) ?? knownAssembly(configured, mapping, this.platform);
|
|
675
687
|
// Plugins stay relative to the environment root; a worker entry does too,
|
|
676
688
|
// and its service keeps using the deployed destination as working directory.
|
|
677
689
|
if (mapping.role === 'plugin' || mapping.role === 'worker') {
|
|
@@ -702,7 +714,7 @@ class EnvironmentUpdater {
|
|
|
702
714
|
});
|
|
703
715
|
}
|
|
704
716
|
const changes = plans.map(plan => ({ module: plan.module, previous: plan.previous, next: plan.next, copiedDirectories: plan.copiedDirectories, removedDirectories: plan.removedDirectories }));
|
|
705
|
-
const configuration = patchEnvironmentConfiguration(configured, plans.flatMap(plan => plan.entries));
|
|
717
|
+
const configuration = patchEnvironmentConfiguration(configured, plans.flatMap(plan => plan.entries), this.platform);
|
|
706
718
|
const nextArtifacts = [...artifacts];
|
|
707
719
|
const nextDownloads = [...downloads];
|
|
708
720
|
for (const plan of plans) {
|
|
@@ -785,20 +797,20 @@ class EnvironmentUpdater {
|
|
|
785
797
|
}
|
|
786
798
|
exports.EnvironmentUpdater = EnvironmentUpdater;
|
|
787
799
|
/** Best-effort preview assembly for dry-run, where nothing can be extracted. */
|
|
788
|
-
function knownAssembly(xml, mapping) {
|
|
800
|
+
function knownAssembly(xml, mapping, platform) {
|
|
789
801
|
try {
|
|
790
802
|
const document = new fast_xml_parser_1.XMLParser(parserOptions).parse(xml);
|
|
791
803
|
const server = document?.SystemConfig?.Services?.Server;
|
|
792
804
|
const raw = mapping.role === 'worker' ? server?.PluginWorkers?.['sys:string'] : server?.Plugins?.['sys:string'];
|
|
793
805
|
const list = raw === undefined ? [] : Array.isArray(raw) ? raw : [raw];
|
|
794
|
-
const prefix = windowsPath(mapping.destination).toLowerCase() +
|
|
806
|
+
const prefix = windowsPath(mapping.destination, platform).toLowerCase() + separatorOf(platform);
|
|
795
807
|
for (const value of list) {
|
|
796
808
|
if (typeof value !== 'string')
|
|
797
809
|
continue;
|
|
798
|
-
const folded = windowsPath(value).toLowerCase();
|
|
810
|
+
const folded = windowsPath(value, platform).toLowerCase();
|
|
799
811
|
if (!folded.startsWith(prefix))
|
|
800
812
|
continue;
|
|
801
|
-
const name =
|
|
813
|
+
const name = (0, local_path_1.baseNameOf)(folded);
|
|
802
814
|
const match = mapping.assemblies.find(assembly => assembly.toLowerCase() === name);
|
|
803
815
|
if (match)
|
|
804
816
|
return match;
|