@guanjinke/artifact-client 1.3.0 → 1.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 +135 -1
- package/dist/cli/config-manager.d.ts +15 -0
- package/dist/cli/config-manager.d.ts.map +1 -1
- package/dist/cli/config-manager.js +31 -0
- package/dist/cli/config-manager.js.map +1 -1
- package/dist/cli/environment.d.ts +6 -0
- package/dist/cli/environment.d.ts.map +1 -0
- package/dist/cli/environment.js +134 -0
- package/dist/cli/environment.js.map +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +160 -2
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/environment/archive.d.ts +7 -0
- package/dist/environment/archive.d.ts.map +1 -0
- package/dist/environment/archive.js +132 -0
- package/dist/environment/archive.js.map +1 -0
- package/dist/environment/builder.d.ts +6 -0
- package/dist/environment/builder.d.ts.map +1 -0
- package/dist/environment/builder.js +323 -0
- package/dist/environment/builder.js.map +1 -0
- package/dist/environment/catalog.d.ts +9 -0
- package/dist/environment/catalog.d.ts.map +1 -0
- package/dist/environment/catalog.js +35 -0
- package/dist/environment/catalog.js.map +1 -0
- package/dist/environment/config.d.ts +8 -0
- package/dist/environment/config.d.ts.map +1 -0
- package/dist/environment/config.js +60 -0
- package/dist/environment/config.js.map +1 -0
- package/dist/environment/manager.d.ts +43 -0
- package/dist/environment/manager.d.ts.map +1 -0
- package/dist/environment/manager.js +383 -0
- package/dist/environment/manager.js.map +1 -0
- package/dist/environment/plan.d.ts +10 -0
- package/dist/environment/plan.d.ts.map +1 -0
- package/dist/environment/plan.js +131 -0
- package/dist/environment/plan.js.map +1 -0
- package/dist/environment/process.d.ts +94 -0
- package/dist/environment/process.d.ts.map +1 -0
- package/dist/environment/process.js +381 -0
- package/dist/environment/process.js.map +1 -0
- package/dist/environment/registry.d.ts +45 -0
- package/dist/environment/registry.d.ts.map +1 -0
- package/dist/environment/registry.js +157 -0
- package/dist/environment/registry.js.map +1 -0
- package/dist/environment/root.d.ts +33 -0
- package/dist/environment/root.d.ts.map +1 -0
- package/dist/environment/root.js +119 -0
- package/dist/environment/root.js.map +1 -0
- package/dist/environment/types.d.ts +66 -0
- package/dist/environment/types.d.ts.map +1 -0
- package/dist/environment/types.js +3 -0
- package/dist/environment/types.js.map +1 -0
- package/dist/environment/update.d.ts +85 -0
- package/dist/environment/update.d.ts.map +1 -0
- package/dist/environment/update.js +644 -0
- package/dist/environment/update.js.map +1 -0
- package/dist/environment/validate.d.ts +36 -0
- package/dist/environment/validate.d.ts.map +1 -0
- package/dist/environment/validate.js +147 -0
- package/dist/environment/validate.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -56,9 +56,13 @@ const minors = await client.listMinorVersions('myPlugin', '1.0');
|
|
|
56
56
|
|
|
57
57
|
// List artifacts in a specific version
|
|
58
58
|
const artifacts = await client.listArtifacts('myPlugin', '1.0.5');
|
|
59
|
+
// [{ name: 'bundle.zip', path: '...' }, ...]
|
|
60
|
+
|
|
61
|
+
// ... including each file's size
|
|
62
|
+
const artifactsWithSize = await client.listArtifacts('myPlugin', '1.0.5', { includeSize: true });
|
|
59
63
|
// [{ name: 'bundle.zip', path: '...', sizeMB: 12.5 }, ...]
|
|
60
64
|
|
|
61
|
-
// Upload an artifact into a version directory (a plain write: no major version
|
|
65
|
+
// Upload an artifact into a version directory (a plain write: no major version
|
|
62
66
|
// pointer is touched)
|
|
63
67
|
await client.uploadArtifact('myPlugin', '1.0.6', 'bundle.zip', './dist/bundle.zip');
|
|
64
68
|
|
|
@@ -224,6 +228,136 @@ A **product major version** (主版本号) is a label rather than a semver:
|
|
|
224
228
|
| `downloadArtifact(plugin, version, fileName, localDir)` | Download by name |
|
|
225
229
|
| `downloadVersion(plugin, version, localDir)` | Download all artifacts for a version |
|
|
226
230
|
|
|
231
|
+
## Create a Wyn Environment
|
|
232
|
+
|
|
233
|
+
`create-env` resolves and assembles a **fresh Windows embedded environment** without installing Windows services or starting anything. It supports product labels `9.1`, `9.1-*` and `dev`. Dry-run reports `schema: "pending"`; execution reads the monitoring bundle's XML template and accepts only verified V91/9.1 or V100/10.0, with matching Monitor XSD assets. Missing Server XSD assets produce a warning rather than preventing assembly. Numeric artifact versions never determine the schema. Other numeric product majors fail explicitly.
|
|
234
|
+
|
|
235
|
+
A resolved dry-run is not proof that independently published packages are compatible. Some dev Server packages omit `xsd/V100/Wyn.conf.xsd`, while the Monitor template selects V100. Wyn's configuration reader falls back to ordinary XML deserialization when its XSD assets are absent. Assembly therefore records and returns a warning for missing Server XSD rather than rejecting that combination or copying schemas from another package. Monitor's matching XSD remains required. This does not verify the Server assembly's XML reader compatibility or successful runtime startup.
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
# Core environment only; Server, Account, Dataset, AnalysisModel and CotWorker are automatic
|
|
240
|
+
afm oss create-env D:/wyn-core --name wyn-core --major 9.1
|
|
241
|
+
|
|
242
|
+
# Resolve exact per-module artifacts; no downloads or filesystem writes
|
|
243
|
+
afm oss create-env D:/wyn-test --name wyn-test --major 9.1 --modules dashboard,reporting --dry-run
|
|
244
|
+
afm az create-env D:/wyn-test --name wyn-test --major dev --modules analysis --edition en --dry-run
|
|
245
|
+
|
|
246
|
+
# Assemble a fresh environment (Windows only)
|
|
247
|
+
afm oss create-env D:/wyn-test --name wyn-test --major 9.1 --modules dashboard reporting --port 51980
|
|
248
|
+
|
|
249
|
+
# With a configured environment root (afm env root D:/wyn-envs) the path is optional:
|
|
250
|
+
afm oss create-env --name wyn-test --major 9.1
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
The default edition is `cn`, profile is `embedded`, and Web/embedded identity port is `51980`. The core Wyn components—Server, Account, Dataset, AnalysisModel and CotWorker—are always included and do not need to be listed in `--modules`. Optional modules are `dashboard`, `reporting` and EN-only `sheets`. `documents` is deliberately rejected until its CollaborationService dependency and embedded configuration are verified. Monitoring is also always included to run the environment. Dashboard no longer requires a separate AnalysisModel selection. Module names may be space- or comma-separated. Each plugin resolves its major once, and only its exact runtime ZIP is selected: unrelated language, styles and support archives are never selected by size.
|
|
254
|
+
|
|
255
|
+
Saved credentials and inline credential flags work as with other commands. This command honors saved `basePrefix` and `--base-prefix`; an explicit empty string selects the container/bucket root. Provider defaults are Azure `plugin_artifacts` and OSS root. Existing commands retain their current prefix behavior. The JSON plan includes exact remote object names and mappings, not credentials or a SAS URL.
|
|
256
|
+
|
|
257
|
+
Console progress is written to stderr with elapsed time and artifact counts: version resolution, download, SHA256, ZIP validation/extraction, directory assembly, configuration generation and publication. Long stages emit a waiting message every 15 seconds; this is not a byte percentage. Stdout remains a single JSON plan/result, so redirecting stdout preserves machine-readable output. Library callers can opt into the same stage messages using the third `buildEnvironmentPlan` argument or `executeEnvironmentPlan`'s `onProgress` dependency; library calls remain silent by default.
|
|
258
|
+
|
|
259
|
+
The target must be absent or empty, must not be a filesystem root or protected installed/system location, and must not have a linked/reparse-point ancestor. There is no overwrite or force option. Download, streaming ZIP extraction, assembly verification and configuration generation happen in owned sibling temporary directories. ZIP paths, case-insensitive conflicts, links, reserved Windows names and resource limits are checked for every entry, including unused support files. The defaults cap each archive at 100,000 entries and 20 GiB uncompressed. Final files are published exclusively without replacing racing files; failure removes only owned paths and preserves unrelated data.
|
|
260
|
+
|
|
261
|
+
Server-root `appsettings.json` and `appsettings.Development.json` are excluded from deployment (case-insensitive) so bundled startup overrides cannot affect the generated environment. This does not remove Monitor settings, nested helper settings or other environment-specific settings, and does not modify the downloaded ZIP or existing environments.
|
|
262
|
+
|
|
263
|
+
The canonical editable configuration is `<root>/conf/Wyn.conf`. `<root>/Monitor/conf` is a Windows directory junction to it because the monitoring process resolves configuration from its own working directory. Other monitoring-bundle `conf` files are preserved in the canonical directory. The environment contains explicit plugin/embedded worker lists, actual assembly names (including known reporting naming variants), SQLite server databases and DuckDB warehouse settings. Monitored worker services are disabled to avoid parallel launches while embedded Server loads the deployed worker assemblies.
|
|
264
|
+
|
|
265
|
+
`environment.lock.json` records selections, independent resolved versions, SHA256 hashes of downloaded ZIPs and runtime framework requirements read from required `.runtimeconfig.json` files. No host license, database or sample data is copied. Optional theme recompilation/styles-cache, additional language archives, bootstrap/sample provisioning, standalone identity patches and service installation are outside this command. Successful assembly is **not** proof of license validity, database initialization or successful runtime startup. Review the generated requirements and provide the appropriate .NET runtimes and licensing before starting anything manually.
|
|
266
|
+
|
|
267
|
+
### Environment Library API
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { ArtifactClient, buildEnvironmentPlan, executeEnvironmentPlan } from '@guanjinke/artifact-client';
|
|
271
|
+
|
|
272
|
+
const client = new ArtifactClient('oss', { keyId: 'id', key: 'secret' });
|
|
273
|
+
const plan = await buildEnvironmentPlan({
|
|
274
|
+
root: 'D:/wyn-test', major: '9.1', modules: ['dashboard'],
|
|
275
|
+
}, client);
|
|
276
|
+
// Planning never downloads or writes; execution uses these exact resolved versions.
|
|
277
|
+
const result = await executeEnvironmentPlan(plan, { client });
|
|
278
|
+
console.log(result.root, result.requirements);
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Both APIs accept the existing client through a small typed interface, enabling cloud-independent testing. Execution defaults to the host platform; the optional injected platform is intended for isolated layout tests, not a claim of cross-platform Wyn support.
|
|
282
|
+
|
|
283
|
+
## Update an Existing Environment
|
|
284
|
+
|
|
285
|
+
`update-env` replaces selected modules of an already registered environment, or points a module at a local developer build without copying any files:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
afm oss update-env <name> --modules <spec...> [--dry-run]
|
|
289
|
+
afm az update-env <name> --modules <spec...> [--dry-run]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Specs are space- or comma-separated, and each entry has one of these forms:
|
|
293
|
+
|
|
294
|
+
| Spec | Meaning |
|
|
295
|
+
| --- | --- |
|
|
296
|
+
| `all` | every configured module from remote, skipping modules that have a local source |
|
|
297
|
+
| `dashboard` | latest artifact of that module for the environment's recorded major |
|
|
298
|
+
| `dashboard:0.1.12345` | pinned version |
|
|
299
|
+
| `dashboard=D:\build\Wyn.Dashboards.Plugin.dll` | local source (no download, no copy) |
|
|
300
|
+
|
|
301
|
+
`all` must be used alone and covers exactly the modules that are both updateable and currently installed in that environment (`common`, `analysis`, plus any of `dashboard`/`reporting`/`sheets` it has). Modules with a local source are skipped and reported (manifest `moduleSources`, registry `localModules`, the result's `skipped` list and a stderr line); `server` and `monitoring` are never included. Because `all` only selects remote specs, it follows the remote state rule below and requires the environment to be `ready` or `stopped`. If nothing is left to update the command fails without writing.
|
|
302
|
+
|
|
303
|
+
A spec may not combine a pinned version with a local source, duplicate modules in one call are refused, and the module name must be `dashboard`, `reporting`, `sheets`, `analysis` or `common`. `server` and `monitoring` are refused because they define the runtime and configuration schema (recreate the environment instead), `documents` stays unsupported, and `sheets` still requires an `en` edition environment. Updating a module that was never installed installs it: its plugin entry is added and the module is listed in the registry; a remote spec also adds the manifest artifact/download entries, while a local spec records only `moduleSources`/`localModules` (there is no downloaded artifact to describe).
|
|
304
|
+
|
|
305
|
+
Remote updates resolve exactly one exact artifact name for the resolved version, download into a sibling staging workspace (`<dirname(root)>/.afm-env-*`), verify its SHA256, extract and validate it, check every mapping's source directory and that exactly one runtime assembly is present, and only then replace the module's deployed directories (`Plugins/<X>`, its worker directories, and `<root>/Web Contents` when the dashboard archive contains it). The plugin entry is rewritten as the normal relative `Plugins\<dest>\<assembly>` path and the deployment is recorded in the manifest and registry.
|
|
306
|
+
|
|
307
|
+
Local source behavior is configuration-only:
|
|
308
|
+
|
|
309
|
+
* Nothing is copied into or out of the environment.
|
|
310
|
+
* The already deployed `Plugins/<destination>` directory is deleted so the stale artifact cannot be loaded twice; the worker directories are left alone.
|
|
311
|
+
* `<root>/conf/Wyn.conf` `<Server><Plugins>` is rewritten to the **absolute** local DLL path (forward slashes are normalized) so the Server loads the developer build directly.
|
|
312
|
+
* The override is recorded in `environment.lock.json` `moduleSources` and in the registry as `localModules` (shown by `env list` in a `local` column); `dashboard`, `reporting`, `analysis` and `sheets` are supported. `common` deploys two plugin directories and is rejected for local sources. A directory may be given instead of a DLL when it contains exactly one of the module's known plugin assemblies, and the DLL must be outside the deployed plugin directory.
|
|
313
|
+
* Only configuration changed, so the environment must be **restarted** (`afm env restart <name>`) to load the build; the CLI never restarts it automatically.
|
|
314
|
+
* Switching a module back to a remote spec deletes the override, restores the relative entry and copies the freshly downloaded artifact again.
|
|
315
|
+
|
|
316
|
+
Configuration rewriting always parses `<root>/conf/Wyn.conf`, mutates only the `Plugins` `sys:string` list (a single string or an array are both accepted), rebuilds it with the same options the creation path uses, and validates the result with `XMLValidator` before writing. Dashboard stays the first `Plugins` entry and unrelated entries keep their order.
|
|
317
|
+
|
|
318
|
+
State rules: a remote update requires the observed state `ready` or `stopped`; `running`/`unknown` are refused with a request to run `afm env stop <name>` first, because the deployed files may be in use. A local-only update may run while the environment is `running` (the CLI then reports that a restart is required), but `unknown` is always refused. `--dry-run` performs the spec, ownership, tree and state validation plus remote resolution, prints the planned changes and downloads or writes nothing. Progress and the restart reminder go to stderr; stdout remains a single JSON result. JSON and configuration writes go through `<file>.afm-tmp` followed by an atomic rename, and the staging workspace is always removed. Unlike `create`/`start`/`stop`/`restart`, `update-env` does not take the per-environment lifecycle lock — those state rules are its only guard, so do not run an update concurrently with a lifecycle command for the same environment.
|
|
319
|
+
|
|
320
|
+
## Managed Local Environments
|
|
321
|
+
|
|
322
|
+
Create a named environment with `node dist/cli.js oss create-env D:/wyn/demo --name demo --major 9.1` (use `az` similarly). `--name` is required for managed creation and names are case-insensitively unique. The environment path is optional once a unified environment root is configured (see below). `--port` defaults to `51980`; reserved or occupied ports fail without automatic reassignment. `--dry-run` checks options, registry conflicts and TCP availability without reserving or writing files.
|
|
323
|
+
|
|
324
|
+
### Unified Environment Root
|
|
325
|
+
|
|
326
|
+
Configure one directory for all environments so the path no longer has to be typed:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
afm env root D:/wyn-envs # validate, create if missing and remember the directory
|
|
330
|
+
afm env root # print the configured directory (path on stdout)
|
|
331
|
+
afm env root --json # script-friendly state: configured/root/exists/configPath
|
|
332
|
+
afm env root --unset # forget it; <root> is required again
|
|
333
|
+
|
|
334
|
+
# No path needed: creates D:/wyn-envs/demo
|
|
335
|
+
afm oss create-env --name demo --major 9.1
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
The setting is stored as an absolute path in `~/.afm/config.json` (`AFM_CONFIG_DIR` redirects the directory) alongside credentials, so it is per OS user/profile; credentials and other settings are preserved when it is set or cleared. Every new environment is created at `<environment root>/<name>`, and the name must be a single safe directory segment (`A-Za-z0-9`, `.`, `_`, `-`, max 64 characters), so it can never escape the root.
|
|
339
|
+
|
|
340
|
+
The configured directory is re-validated on every use. It must not be a filesystem root, the user profile itself, the AFM configuration directory or one of its descendants, or a Windows/Program Files/SystemRoot location, and no existing ancestor may be a symlink or junction. `afm env root <path>` creates a missing directory and verifies it is a regular directory; `--dry-run` validates the configured root without creating anything. An explicit `<root>` argument still wins over the configured root; when it points outside the configured directory a note is printed to stderr and the environment is still registered normally.
|
|
341
|
+
|
|
342
|
+
Registered environments live in `~/.afm/environments.json` (set `AFM_CONFIG_DIR` for an isolated profile); credentials and the optional unified environment root remain in `config.json`. Use `node dist/cli.js env list [--json]` (the table shows a `local` column listing modules with a local build override; the JSON rows carry `localModules`), `env root [<path>] [--unset] [--json]`, `env start <name> [--foreground|--background]`, `env stop <name>`, and `env restart <name>`. Background output is appended to `<root>/logs/server.stdout.log` and `server.stderr.log`; foreground Ctrl+C stops the verified monitor process tree before returning.
|
|
343
|
+
|
|
344
|
+
Start defaults to foreground. Restart preserves the previous mode, falling back to foreground. A stopped environment keeps its reserved port until deletion. List includes only environments registered for the current user/profile; in table mode it also prints the configured environment root (if any) to stderr. Lifecycle stages, verified monitor PID/mode and background log paths are printed to stderr; stdout remains available for inherited foreground output or list JSON.
|
|
345
|
+
|
|
346
|
+
Background mode starts the monitor in its own hidden console through a short launcher, then confirms the monitor by its exact command line (absolute DLL, `--RunAsMonitor`) before recording it; the recorded process is independent of the CLI, and its stdout/stderr are appended to the log files. This is required because `Wyn.Server` assigns `Console.Title` at the top of `Main` and throws `IOException` without an attached console, while a process that merely inherits the CLI's console does not outlive the CLI. Foreground mode inherits the terminal's console and stdio, so run it from a real console; if a start fails, the error includes the monitor's last log output and, when the log shows the `Console.Title` failure, points at that call. Command execution still uses the OS process query (`Get-CimInstance`); if that query is unavailable or fails twice, start/stop report an uncertain state instead of guessing.
|
|
347
|
+
|
|
348
|
+
`env delete <name> --yes` stops the verified monitor, removes the owned environment directory and then removes its registry record. Without `--yes`, deletion requires a TTY confirmation. Existing directories created before managed registration are not adopted.
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
Registered states are `creating`, `ready`, `running` and `stopped`. List checks live identity and also reports `unknown`, `identity-mismatch`, `missing` and `broken`; `running` means a verified monitor process, not HTTP readiness. Start/stop/restart are serialized per environment. Names, ports and overlapping roots are reserved atomically before cloud access; interrupted creation remains visible rather than silently releasing an active reservation. Creator command lines are stored as digests so inline credentials are not persisted.
|
|
352
|
+
|
|
353
|
+
Startup requires the owned marker and manifest, Server DLL/runtimeconfig, and a configuration port matching the registry. Stop verifies PID, creation timestamp, executable and exact argument tokens, then uses forced Windows `taskkill /T /F` tree termination and confirms captured descendants exited. A final process identity recheck reduces PID reuse risk; Windows native process handles/Job Objects are not used, so hostile process reuse between inspection and `taskkill` is outside this guarantee. Unknown identity or failed tree confirmation retains the record and refuses deletion. Uncertain startup cleanup keeps a recovery identity in the registry and reports failure. If registry persistence also fails, it attempts to write `<root>/.afm-runtime-recovery.json`; any such file makes lifecycle operations uncertain and requires manual recovery. Durable identity storage cannot be guaranteed if both registry and environment filesystems are unwritable. A manual relative `dotnet Wyn.Server.dll` launch cannot be safely attributed from CIM metadata, so such an ambiguous candidate makes list/stop/delete report `unknown` and refuse; a start is still allowed because environments are only ever launched with an absolute DLL path, so that process cannot be the one being replaced.
|
|
354
|
+
|
|
355
|
+
Deletion preserves the ownership marker and manifest while removing other payload entries. If payload removal fails, the registry and metadata remain for retry. If the final directory removal fails (for example an editor or terminal still has the folder open), the command retries briefly, then attempts exclusive metadata restoration and reports an actionable error that names the processes whose command line mentions the directory, states that metadata and the registry record were retained, and asks for the same `env delete <name>` command to be re-run after those holders are closed; it does not silently unregister a partial directory.
|
|
356
|
+
|
|
357
|
+
Locks are exclusive and bounded, with no automatic stale-lock deletion. A terminated CLI can leave `registry.lock` or `env-<uuid>.lock` in the configuration directory. Recover manually only after positively establishing that its owning operation is no longer active; elapsed age alone is not sufficient. Reservation/process recovery may require manual inspection when Windows denies process metadata. No command automatically adopts old environments or scans arbitrary Wyn installs.
|
|
358
|
+
|
|
359
|
+
The standalone `buildEnvironmentPlan`/`executeEnvironmentPlan` APIs retain their previous behavior without global registration; managed callers can use `EnvironmentManager` and inject registry/process/port adapters for isolated tests. Runtime management is Windows-only; metadata planning/listing can run elsewhere but unavailable process inspection is reported as uncertain.
|
|
360
|
+
|
|
227
361
|
## License
|
|
228
362
|
|
|
229
363
|
MIT
|
|
@@ -32,4 +32,19 @@ export declare function saveOSSConfig(config: OSSConfig): void;
|
|
|
32
32
|
* Clear all stored configuration.
|
|
33
33
|
*/
|
|
34
34
|
export declare function clearConfig(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Read the unified environment root, i.e. the directory that holds managed
|
|
37
|
+
* environments. Returns undefined when it has not been configured.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getEnvironmentRoot(): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Persist the unified environment root. The path is stored as an absolute path
|
|
42
|
+
* so later `create-env` calls do not depend on the current working directory.
|
|
43
|
+
* Credentials and other settings in the config file are preserved.
|
|
44
|
+
*/
|
|
45
|
+
export declare function setEnvironmentRoot(directory: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Remove the unified environment root setting. Other settings are preserved.
|
|
48
|
+
*/
|
|
49
|
+
export declare function clearEnvironmentRoot(): void;
|
|
35
50
|
//# sourceMappingURL=config-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAK7D;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAYD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAWtC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAIrD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
|
|
1
|
+
{"version":3,"file":"config-manager.d.ts","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAK7D;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAYD;;;GAGG;AACH,wBAAgB,UAAU,IAAI,SAAS,CAWtC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAGnD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAIrD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAGvD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAK1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAI3C"}
|
|
@@ -40,6 +40,9 @@ exports.writeConfig = writeConfig;
|
|
|
40
40
|
exports.saveAzureConfig = saveAzureConfig;
|
|
41
41
|
exports.saveOSSConfig = saveOSSConfig;
|
|
42
42
|
exports.clearConfig = clearConfig;
|
|
43
|
+
exports.getEnvironmentRoot = getEnvironmentRoot;
|
|
44
|
+
exports.setEnvironmentRoot = setEnvironmentRoot;
|
|
45
|
+
exports.clearEnvironmentRoot = clearEnvironmentRoot;
|
|
43
46
|
const fs = __importStar(require("fs"));
|
|
44
47
|
const path = __importStar(require("path"));
|
|
45
48
|
const os = __importStar(require("os"));
|
|
@@ -118,4 +121,32 @@ function clearConfig() {
|
|
|
118
121
|
ensureConfigDir();
|
|
119
122
|
writeConfig({});
|
|
120
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Read the unified environment root, i.e. the directory that holds managed
|
|
126
|
+
* environments. Returns undefined when it has not been configured.
|
|
127
|
+
*/
|
|
128
|
+
function getEnvironmentRoot() {
|
|
129
|
+
const configured = readConfig().environmentRoot;
|
|
130
|
+
return typeof configured === 'string' && configured.trim() !== '' ? path.resolve(configured) : undefined;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Persist the unified environment root. The path is stored as an absolute path
|
|
134
|
+
* so later `create-env` calls do not depend on the current working directory.
|
|
135
|
+
* Credentials and other settings in the config file are preserved.
|
|
136
|
+
*/
|
|
137
|
+
function setEnvironmentRoot(directory) {
|
|
138
|
+
if (typeof directory !== 'string' || directory.trim() === '')
|
|
139
|
+
throw new Error('Environment root must be a non-empty directory path.');
|
|
140
|
+
const config = readConfig();
|
|
141
|
+
config.environmentRoot = path.resolve(directory);
|
|
142
|
+
writeConfig(config);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Remove the unified environment root setting. Other settings are preserved.
|
|
146
|
+
*/
|
|
147
|
+
function clearEnvironmentRoot() {
|
|
148
|
+
const config = readConfig();
|
|
149
|
+
delete config.environmentRoot;
|
|
150
|
+
writeConfig(config);
|
|
151
|
+
}
|
|
121
152
|
//# sourceMappingURL=config-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,oCAGC;AAMD,sCAEC;AAgBD,gCAWC;AAKD,kCAGC;AAKD,0CAIC;AAKD,sCAIC;AAKD,kCAGC;
|
|
1
|
+
{"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/cli/config-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { EnvironmentManager } from '../environment/manager';
|
|
3
|
+
import { EnvironmentRecord } from '../environment/registry';
|
|
4
|
+
export declare function confirmDeletion(entry: EnvironmentRecord, yes: boolean): Promise<boolean>;
|
|
5
|
+
export declare function addEnvironmentCommands(program: Command, factory?: () => EnvironmentManager): void;
|
|
6
|
+
//# sourceMappingURL=environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../../src/cli/environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAW,MAAM,yBAAyB,CAAC;AAQrE,wBAAsB,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAO9F;AA0CD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,MAAM,kBAAoG,GAAG,IAAI,CAoBlL"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.confirmDeletion = confirmDeletion;
|
|
37
|
+
exports.addEnvironmentCommands = addEnvironmentCommands;
|
|
38
|
+
const commander_1 = require("commander");
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const readline_1 = require("readline");
|
|
41
|
+
const manager_1 = require("../environment/manager");
|
|
42
|
+
const root_1 = require("../environment/root");
|
|
43
|
+
const config_manager_1 = require("./config-manager");
|
|
44
|
+
function runMode(options) {
|
|
45
|
+
if (options.foreground && options.background)
|
|
46
|
+
throw new Error('--foreground and --background are mutually exclusive.');
|
|
47
|
+
return options.background ? 'background' : 'foreground';
|
|
48
|
+
}
|
|
49
|
+
async function confirmDeletion(entry, yes) {
|
|
50
|
+
console.error(`Delete environment directory ${entry.root} and registry record after stopping it?`);
|
|
51
|
+
if (yes)
|
|
52
|
+
return true;
|
|
53
|
+
if (!process.stdin.isTTY)
|
|
54
|
+
throw new Error('Noninteractive deletion requires --yes.');
|
|
55
|
+
const input = (0, readline_1.createInterface)({ input: process.stdin, output: process.stderr });
|
|
56
|
+
try {
|
|
57
|
+
return await new Promise(resolve => { input.once('close', () => resolve(false)); input.question('Type yes to continue: ', answer => resolve(answer.trim().toLowerCase() === 'yes')); });
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
input.close();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Show or configure the unified directory that holds managed environments.
|
|
65
|
+
* Stored in the CLI config file so `create-env` can omit the environment path.
|
|
66
|
+
*/
|
|
67
|
+
function addRootCommand(env) {
|
|
68
|
+
env.command('root')
|
|
69
|
+
.description('Show or set the unified directory that holds managed environments')
|
|
70
|
+
.argument('[path]', 'Directory for new environments; each environment is created at <path>/<name>')
|
|
71
|
+
.option('--unset', 'Forget the configured environment root')
|
|
72
|
+
.option('--json', 'Output JSON')
|
|
73
|
+
.action(async (target, options) => {
|
|
74
|
+
if (options.unset) {
|
|
75
|
+
if (target)
|
|
76
|
+
throw new Error('Pass either <path> or --unset, not both.');
|
|
77
|
+
(0, config_manager_1.clearEnvironmentRoot)();
|
|
78
|
+
console.error('Environment root cleared. New environments must pass <root> explicitly until one is configured again.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (target !== undefined) {
|
|
82
|
+
const container = await (0, root_1.resolveEnvironmentContainer)(target, (0, config_manager_1.getConfigDir)(), { create: true });
|
|
83
|
+
(0, config_manager_1.setEnvironmentRoot)(container.directory);
|
|
84
|
+
console.log(container.directory);
|
|
85
|
+
console.error(`Environment root ${container.created ? 'created at' : 'set to'} ${container.directory}`);
|
|
86
|
+
console.error(`Stored in ${(0, config_manager_1.getConfigPath)()}`);
|
|
87
|
+
console.error(`New environments are created at ${path.join(container.directory, '<name>')}`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const configured = (0, config_manager_1.getEnvironmentRoot)();
|
|
91
|
+
if (configured === undefined) {
|
|
92
|
+
if (options.json) {
|
|
93
|
+
console.log(JSON.stringify({ configured: false, root: null, configPath: (0, config_manager_1.getConfigPath)() }, null, 2));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
console.error('No environment root configured.');
|
|
97
|
+
console.error('Set one with: afm env root <path>');
|
|
98
|
+
console.error('Then create environments without a path, e.g. `afm oss create-env --name demo --major 9.1`.');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const exists = await (0, root_1.inspectEnvironmentDirectory)(configured, (0, config_manager_1.getConfigDir)());
|
|
102
|
+
if (options.json) {
|
|
103
|
+
console.log(JSON.stringify({ configured: true, root: configured, exists, configPath: (0, config_manager_1.getConfigPath)() }, null, 2));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
console.log(configured);
|
|
107
|
+
console.error(`Stored in ${(0, config_manager_1.getConfigPath)()}`);
|
|
108
|
+
console.error(exists ? `New environments are created at ${path.join(configured, '<name>')}` : 'The directory is missing and will be created on the next create-env.');
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function addEnvironmentCommands(program, factory = () => new manager_1.EnvironmentManager({ onProgress: message => console.error(message) })) {
|
|
112
|
+
const env = new commander_1.Command('env').description('Manage registered local Wyn environments');
|
|
113
|
+
env.command('list').option('--json', 'Output JSON').action(async (options) => {
|
|
114
|
+
const rows = await factory().list();
|
|
115
|
+
if (options.json)
|
|
116
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
117
|
+
else {
|
|
118
|
+
const configured = (0, config_manager_1.getEnvironmentRoot)();
|
|
119
|
+
console.error(configured ? `Environment root: ${configured}` : 'No environment root configured; set one with `afm env root <path>`.');
|
|
120
|
+
console.table(rows.map(row => ({ name: row.name, state: row.observedState, port: row.port, edition: row.edition, major: row.major, root: row.root, local: (row.localModules ?? []).join(','), PID: row.observedState === 'running' || row.observedState === 'unknown' ? row.run?.pid ?? '' : '', problem: row.problem ?? '' })));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
addRootCommand(env);
|
|
124
|
+
env.command('start').argument('<name>').option('--foreground').option('--background')
|
|
125
|
+
.action(async (name, options) => { const mode = runMode(options); console.error(`Starting ${name} (${mode})...`); await factory().start(name, mode); });
|
|
126
|
+
env.command('restart').argument('<name>').option('--foreground').option('--background')
|
|
127
|
+
.action(async (name, options) => { const mode = options.foreground || options.background ? runMode(options) : undefined; console.error(`Restarting ${name} (${mode ?? 'previous mode or foreground'})...`); await factory().restart(name, mode); });
|
|
128
|
+
env.command('stop').argument('<name>').action(async (name) => { console.error(`Stopping ${name}...`); await factory().stop(name); });
|
|
129
|
+
env.command('delete').argument('<name>').option('-y, --yes')
|
|
130
|
+
.action(async (name, options) => { const deleted = await factory().delete(name, entry => confirmDeletion(entry, !!options.yes)); if (!deleted)
|
|
131
|
+
console.error('Deletion cancelled.'); });
|
|
132
|
+
program.addCommand(env);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"environment.js","sourceRoot":"","sources":["../../src/cli/environment.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC;;;GAGG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAiCvC"}
|
package/dist/cli/setup.js
CHANGED
|
@@ -1,11 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.createProgram = createProgram;
|
|
4
37
|
const commander_1 = require("commander");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
5
39
|
const artifact_client_1 = require("../artifact-client");
|
|
6
40
|
const config_manager_1 = require("./config-manager");
|
|
7
41
|
const version_1 = require("./version");
|
|
8
42
|
const semver_1 = require("../utils/semver");
|
|
43
|
+
const plan_1 = require("../environment/plan");
|
|
44
|
+
const manager_1 = require("../environment/manager");
|
|
45
|
+
const update_1 = require("../environment/update");
|
|
46
|
+
const root_1 = require("../environment/root");
|
|
47
|
+
const environment_1 = require("./environment");
|
|
9
48
|
/**
|
|
10
49
|
* Build and configure the CLI program.
|
|
11
50
|
* Returns the configured Command instance.
|
|
@@ -30,12 +69,122 @@ function createProgram() {
|
|
|
30
69
|
.description('Aliyun OSS operations');
|
|
31
70
|
addSharedCommands(ossProgram, 'oss');
|
|
32
71
|
program.addCommand(ossProgram);
|
|
72
|
+
(0, environment_1.addEnvironmentCommands)(program);
|
|
33
73
|
return program;
|
|
34
74
|
}
|
|
35
75
|
/**
|
|
36
76
|
* Add shared commands to a storage-specific program ('az' or 'oss').
|
|
37
77
|
*/
|
|
38
78
|
function addSharedCommands(program, type) {
|
|
79
|
+
program
|
|
80
|
+
.command('create-env')
|
|
81
|
+
.description('Plan or assemble a fresh Windows Wyn embedded environment (core server, account, dataset, analysis model and cot worker are automatic)')
|
|
82
|
+
.argument('[root]', 'Environment directory; defaults to <configured environment root>/<name>')
|
|
83
|
+
.requiredOption('--name <name>', 'Registered environment name')
|
|
84
|
+
.requiredOption('--major <major>', '9.1, 9.1-* or dev')
|
|
85
|
+
.option('--modules <names...>', 'Optional modules: dashboard, reporting, sheets (comma-separated also accepted)')
|
|
86
|
+
.option('--edition <edition>', 'cn or en', 'cn')
|
|
87
|
+
.option('--profile <profile>', 'embedded', 'embedded')
|
|
88
|
+
.option('--port <port>', 'Web and embedded identity port', '51980')
|
|
89
|
+
.option('--dry-run', 'Resolve remote artifacts without writing or downloading')
|
|
90
|
+
.option('--base-prefix <prefix>', 'Override saved storage prefix (empty means bucket/container root)')
|
|
91
|
+
.option('--sasurl <url>', 'Azure SAS URL')
|
|
92
|
+
.option('--keyid <id>', 'OSS Key ID')
|
|
93
|
+
.option('--key <key>', 'OSS Key Secret')
|
|
94
|
+
.option('--bucket <bucket>', 'OSS bucket')
|
|
95
|
+
.option('--region <region>', 'OSS region')
|
|
96
|
+
.action(async (rootArgument, options) => {
|
|
97
|
+
const configuredRoot = (0, config_manager_1.getEnvironmentRoot)();
|
|
98
|
+
const root = rootArgument ?? (configuredRoot === undefined ? undefined : (0, root_1.resolveNamedEnvironmentDirectory)(configuredRoot, options.name));
|
|
99
|
+
if (root === undefined)
|
|
100
|
+
throw new Error('No environment root configured: pass <root> or set a default with `afm env root <path>`.');
|
|
101
|
+
const input = { root, major: options.major, modules: options.modules, edition: options.edition, profile: options.profile, port: Number(options.port), dryRun: options.dryRun };
|
|
102
|
+
const started = Date.now();
|
|
103
|
+
let currentStage = 'Validating environment options and target directory';
|
|
104
|
+
let stageStarted = started;
|
|
105
|
+
const onProgress = (message) => {
|
|
106
|
+
currentStage = message;
|
|
107
|
+
stageStarted = Date.now();
|
|
108
|
+
console.error(`[create-env +${Math.floor((stageStarted - started) / 1000)}s] ${message}`);
|
|
109
|
+
};
|
|
110
|
+
const absoluteRoot = path.resolve(input.root);
|
|
111
|
+
console.error(`[create-env] Environment directory: ${absoluteRoot}${rootArgument === undefined ? ' (from the configured environment root)' : ''}`);
|
|
112
|
+
if (rootArgument !== undefined && configuredRoot !== undefined) {
|
|
113
|
+
const relative = path.relative(configuredRoot, absoluteRoot);
|
|
114
|
+
if (relative.startsWith('..') || path.isAbsolute(relative))
|
|
115
|
+
console.error(`[create-env] Note: ${absoluteRoot} is outside the configured environment root ${configuredRoot}.`);
|
|
116
|
+
}
|
|
117
|
+
onProgress(currentStage);
|
|
118
|
+
const heartbeat = setInterval(() => {
|
|
119
|
+
console.error(`[create-env +${Math.floor((Date.now() - started) / 1000)}s] Still working (${Math.floor((Date.now() - stageStarted) / 1000)}s): ${currentStage}`);
|
|
120
|
+
}, 15000);
|
|
121
|
+
heartbeat.unref();
|
|
122
|
+
try {
|
|
123
|
+
await (0, plan_1.validateEnvironmentOptions)(input);
|
|
124
|
+
if (configuredRoot !== undefined) {
|
|
125
|
+
const container = await (0, root_1.resolveEnvironmentContainer)(configuredRoot, (0, config_manager_1.getConfigDir)(), { create: !options.dryRun });
|
|
126
|
+
if (container.created)
|
|
127
|
+
console.error(`[create-env] Created environment root: ${container.directory}`);
|
|
128
|
+
}
|
|
129
|
+
const manager = new manager_1.EnvironmentManager();
|
|
130
|
+
const result = await manager.create(options.name, input, () => createClient(type, options, true), onProgress);
|
|
131
|
+
if (options.dryRun) {
|
|
132
|
+
onProgress(`Dry-run complete: ${'artifacts' in result ? result.artifacts.length : 0} artifacts resolved; nothing downloaded or written`);
|
|
133
|
+
console.log(JSON.stringify(result, null, 2));
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
onProgress('Complete');
|
|
137
|
+
console.log(JSON.stringify(result, null, 2));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
clearInterval(heartbeat);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
// --- update-env ---
|
|
145
|
+
program
|
|
146
|
+
.command('update-env')
|
|
147
|
+
.description('Update selected modules of a registered environment; a local DLL source points the Server at the developer build instead of copying files')
|
|
148
|
+
.argument('<name>', 'Registered environment name')
|
|
149
|
+
.requiredOption('--modules <specs...>', 'Module specs: all, dashboard, dashboard:0.1.12345 or dashboard=D:\\path\\Wyn.Dashboards.Plugin.dll (comma-separated also accepted)')
|
|
150
|
+
.option('--dry-run', 'Validate state and resolve remote versions without writing, downloading or deleting anything')
|
|
151
|
+
.option('--base-prefix <prefix>', 'Override saved storage prefix (empty means bucket/container root)')
|
|
152
|
+
.option('--sasurl <url>', 'Azure SAS URL')
|
|
153
|
+
.option('--keyid <id>', 'OSS Key ID')
|
|
154
|
+
.option('--key <key>', 'OSS Key Secret')
|
|
155
|
+
.option('--bucket <bucket>', 'OSS bucket')
|
|
156
|
+
.option('--region <region>', 'OSS region')
|
|
157
|
+
.action(async (name, options) => {
|
|
158
|
+
const started = Date.now();
|
|
159
|
+
let currentStage = 'Validating module specs';
|
|
160
|
+
let stageStarted = started;
|
|
161
|
+
const onProgress = (message) => {
|
|
162
|
+
currentStage = message;
|
|
163
|
+
stageStarted = Date.now();
|
|
164
|
+
console.error(`[update-env +${Math.floor((stageStarted - started) / 1000)}s] ${message}`);
|
|
165
|
+
};
|
|
166
|
+
const heartbeat = setInterval(() => {
|
|
167
|
+
console.error(`[update-env +${Math.floor((Date.now() - started) / 1000)}s] Still working (${Math.floor((Date.now() - stageStarted) / 1000)}s): ${currentStage}`);
|
|
168
|
+
}, 15000);
|
|
169
|
+
heartbeat.unref();
|
|
170
|
+
try {
|
|
171
|
+
// Local-only updates never construct a cloud client; the factory is only
|
|
172
|
+
// called when a remote spec actually has to be resolved.
|
|
173
|
+
let client;
|
|
174
|
+
const clientFactory = () => { client ??= createClient(type, options, true); return client; };
|
|
175
|
+
const updater = new update_1.EnvironmentUpdater();
|
|
176
|
+
const result = await updater.update(name, options.modules, clientFactory, { dryRun: options.dryRun, onProgress });
|
|
177
|
+
onProgress(result.dryRun ? `Dry-run complete: ${result.changes.length} module(s) validated; nothing downloaded or written` : 'Complete');
|
|
178
|
+
if ((result.skipped ?? []).length)
|
|
179
|
+
console.error(`[update-env] local modules skipped (not updated from artifacts): ${(result.skipped ?? []).map(item => item.module).join(', ')}`);
|
|
180
|
+
if (!result.dryRun)
|
|
181
|
+
console.error(`[update-env] ${result.name} must be restarted to load the change: afm env restart ${result.name}`);
|
|
182
|
+
console.log(JSON.stringify(result, null, 2));
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
clearInterval(heartbeat);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
39
188
|
// --- login ---
|
|
40
189
|
program
|
|
41
190
|
.command('login')
|
|
@@ -400,23 +549,31 @@ function addSharedCommands(program, type) {
|
|
|
400
549
|
/**
|
|
401
550
|
* Create an ArtifactClient based on CLI options and stored config.
|
|
402
551
|
*/
|
|
403
|
-
function createClient(type, cliOptions) {
|
|
552
|
+
function createClient(type, cliOptions, environment = false) {
|
|
404
553
|
const storedConfig = (0, config_manager_1.readConfig)();
|
|
405
554
|
const stored = storedConfig[type];
|
|
555
|
+
const prefix = environment ? cliOptions.basePrefix ?? stored?.basePrefix : undefined;
|
|
556
|
+
if (prefix !== undefined && (typeof prefix !== 'string' || /[?:\\\x00-\x1f]/.test(prefix) || prefix.startsWith('/') || prefix.split('/').some((p) => p === '..' || p === '.')))
|
|
557
|
+
throw new Error('Invalid storage base prefix.');
|
|
558
|
+
const basePrefix = prefix === undefined ? undefined : prefix.replace(/\/+$/, '');
|
|
406
559
|
if (type === 'az') {
|
|
407
560
|
const azStored = stored;
|
|
408
561
|
const sasUrl = cliOptions.sasurl || azStored?.sasUrl;
|
|
409
562
|
if (!sasUrl) {
|
|
563
|
+
if (environment)
|
|
564
|
+
throw new Error('Azure SAS URL is required. Provide --sasurl or run "afm az login".');
|
|
410
565
|
console.error('Error: Azure SAS URL is required. Provide --sasurl or run "afm az login".');
|
|
411
566
|
process.exit(1);
|
|
412
567
|
}
|
|
413
|
-
return new artifact_client_1.ArtifactClient('az', { sasUrl });
|
|
568
|
+
return new artifact_client_1.ArtifactClient('az', { sasUrl, ...(basePrefix !== undefined ? { basePrefix } : {}) });
|
|
414
569
|
}
|
|
415
570
|
else {
|
|
416
571
|
const ossStored = stored;
|
|
417
572
|
const keyId = cliOptions.keyid || ossStored?.keyId;
|
|
418
573
|
const key = cliOptions.key || ossStored?.key;
|
|
419
574
|
if (!keyId || !key) {
|
|
575
|
+
if (environment)
|
|
576
|
+
throw new Error('OSS key ID and key are required. Provide --keyid and --key or run "afm oss login".');
|
|
420
577
|
console.error('Error: OSS key ID and key are required. Provide --keyid and --key or run "afm oss login".');
|
|
421
578
|
process.exit(1);
|
|
422
579
|
}
|
|
@@ -425,6 +582,7 @@ function createClient(type, cliOptions) {
|
|
|
425
582
|
key,
|
|
426
583
|
bucket: cliOptions.bucket || ossStored?.bucket,
|
|
427
584
|
region: cliOptions.region || ossStored?.region,
|
|
585
|
+
...(basePrefix !== undefined ? { basePrefix } : {}),
|
|
428
586
|
});
|
|
429
587
|
}
|
|
430
588
|
}
|