@git.zone/cli 3.2.1 → 4.0.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.
Files changed (125) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/classes.gitzoneconfig.js +1 -1
  3. package/dist_ts/classes.project.js +1 -1
  4. package/dist_ts/gitzone.cli.js +1 -1
  5. package/dist_ts/gitzone.logging.js +1 -1
  6. package/dist_ts/helpers.changelog.js +1 -1
  7. package/dist_ts/helpers.climode.js +1 -1
  8. package/dist_ts/helpers.smartconfig.js +61 -11
  9. package/dist_ts/helpers.smartconfigmigrations.js +1 -1
  10. package/dist_ts/helpers.tsdocker.js +1 -1
  11. package/dist_ts/helpers.workflow.js +1 -1
  12. package/dist_ts/index.js +1 -1
  13. package/dist_ts/mod_audit/index.js +1 -1
  14. package/dist_ts/mod_commit/index.js +1 -1
  15. package/dist_ts/mod_commit/mod.helpers.js +1 -1
  16. package/dist_ts/mod_commit/mod.plugins.js +1 -1
  17. package/dist_ts/mod_commit/mod.ui.js +1 -1
  18. package/dist_ts/mod_config/classes.commitconfig.js +1 -1
  19. package/dist_ts/mod_config/classes.releaseconfig.js +1 -1
  20. package/dist_ts/mod_config/index.js +2 -2
  21. package/dist_ts/mod_config/mod.plugins.js +1 -1
  22. package/dist_ts/mod_deprecate/index.js +1 -1
  23. package/dist_ts/mod_deprecate/mod.plugins.js +1 -1
  24. package/dist_ts/mod_docker/classes.dockerpruner.js +7 -1
  25. package/dist_ts/mod_docker/index.js +1 -1
  26. package/dist_ts/mod_docker/mod.plugins.js +1 -1
  27. package/dist_ts/mod_format/classes.baseformatter.js +1 -1
  28. package/dist_ts/mod_format/classes.diffreporter.js +1 -1
  29. package/dist_ts/mod_format/classes.formatcontext.js +1 -1
  30. package/dist_ts/mod_format/classes.formatplanner.js +1 -1
  31. package/dist_ts/mod_format/classes.formatstats.js +1 -1
  32. package/dist_ts/mod_format/formatters/assets.formatter.js +1 -1
  33. package/dist_ts/mod_format/formatters/cleanup.formatter.js +1 -1
  34. package/dist_ts/mod_format/formatters/copy.formatter.js +1 -1
  35. package/dist_ts/mod_format/formatters/gitignore.formatter.js +1 -1
  36. package/dist_ts/mod_format/formatters/license.formatter.js +1 -1
  37. package/dist_ts/mod_format/formatters/packagejson.formatter.js +1 -1
  38. package/dist_ts/mod_format/formatters/prettier.formatter.js +1 -1
  39. package/dist_ts/mod_format/formatters/readme.formatter.js +1 -1
  40. package/dist_ts/mod_format/formatters/smartconfig.formatter.js +1 -1
  41. package/dist_ts/mod_format/formatters/templates.formatter.js +1 -1
  42. package/dist_ts/mod_format/formatters/tsconfig.formatter.js +1 -1
  43. package/dist_ts/mod_format/index.js +1 -1
  44. package/dist_ts/mod_format/interfaces.format.js +1 -1
  45. package/dist_ts/mod_format/mod.plugins.js +1 -1
  46. package/dist_ts/mod_helpers/index.js +1 -1
  47. package/dist_ts/mod_helpers/mod.plugins.js +1 -1
  48. package/dist_ts/mod_meta/index.js +1 -1
  49. package/dist_ts/mod_meta/meta.classes.meta.js +1 -1
  50. package/dist_ts/mod_meta/meta.interfaces.js +1 -1
  51. package/dist_ts/mod_meta/meta.plugins.js +1 -1
  52. package/dist_ts/mod_open/index.js +1 -1
  53. package/dist_ts/mod_open/mod.plugins.js +1 -1
  54. package/dist_ts/mod_release/index.js +1 -1
  55. package/dist_ts/mod_release/mod.plugins.js +1 -1
  56. package/dist_ts/mod_services/classes.dockercontainer.d.ts +50 -3
  57. package/dist_ts/mod_services/classes.dockercontainer.js +646 -84
  58. package/dist_ts/mod_services/classes.globalregistry.d.ts +10 -24
  59. package/dist_ts/mod_services/classes.globalregistry.js +210 -62
  60. package/dist_ts/mod_services/classes.globalregistrystore.d.ts +48 -0
  61. package/dist_ts/mod_services/classes.globalregistrystore.js +156 -0
  62. package/dist_ts/mod_services/classes.interprocesslock.d.ts +21 -0
  63. package/dist_ts/mod_services/classes.interprocesslock.js +141 -0
  64. package/dist_ts/mod_services/classes.serviceconfiguration.d.ts +15 -12
  65. package/dist_ts/mod_services/classes.serviceconfiguration.js +188 -91
  66. package/dist_ts/mod_services/classes.servicedatamarker.d.ts +32 -7
  67. package/dist_ts/mod_services/classes.servicedatamarker.js +145 -49
  68. package/dist_ts/mod_services/classes.servicemanager.d.ts +70 -28
  69. package/dist_ts/mod_services/classes.servicemanager.js +995 -421
  70. package/dist_ts/mod_services/classes.servicenames.d.ts +8 -0
  71. package/dist_ts/mod_services/classes.servicenames.js +54 -0
  72. package/dist_ts/mod_services/classes.serviceoptions.js +1 -1
  73. package/dist_ts/mod_services/classes.servicepruner.d.ts +3 -0
  74. package/dist_ts/mod_services/classes.servicepruner.js +208 -46
  75. package/dist_ts/mod_services/helpers.js +1 -1
  76. package/dist_ts/mod_services/index.d.ts +2 -0
  77. package/dist_ts/mod_services/index.js +81 -58
  78. package/dist_ts/mod_services/mod.plugins.js +1 -1
  79. package/dist_ts/mod_standard/index.js +2 -2
  80. package/dist_ts/mod_standard/mod.plugins.js +1 -1
  81. package/dist_ts/mod_start/index.js +1 -1
  82. package/dist_ts/mod_start/mod.plugins.js +1 -1
  83. package/dist_ts/mod_template/index.js +1 -1
  84. package/dist_ts/mod_template/mod.plugins.js +1 -1
  85. package/dist_ts/mod_tools/classes.packagemanager.js +1 -1
  86. package/dist_ts/mod_tools/index.js +1 -1
  87. package/dist_ts/mod_tools/mod.plugins.js +1 -1
  88. package/dist_ts/paths.js +1 -1
  89. package/dist_ts/plugins.d.ts +3 -1
  90. package/dist_ts/plugins.js +4 -2
  91. package/dist_ts_migration/001.service-selection.d.ts +9 -0
  92. package/dist_ts_migration/001.service-selection.js +51 -0
  93. package/dist_ts_migration/002.runtime-config.d.ts +19 -0
  94. package/dist_ts_migration/002.runtime-config.js +170 -0
  95. package/dist_ts_migration/003.service-data-marker.d.ts +9 -0
  96. package/dist_ts_migration/003.service-data-marker.js +156 -0
  97. package/dist_ts_migration/004.global-registry.d.ts +13 -0
  98. package/dist_ts_migration/004.global-registry.js +165 -0
  99. package/dist_ts_migration/index.d.ts +11 -0
  100. package/dist_ts_migration/index.js +59 -0
  101. package/package.json +6 -3
  102. package/readme.hints.md +102 -25
  103. package/readme.md +123 -28
  104. package/readme.plan.md +29 -16
  105. package/ts/00_commitinfo_data.ts +1 -1
  106. package/ts/helpers.smartconfig.ts +63 -10
  107. package/ts/mod_config/index.ts +1 -1
  108. package/ts/mod_docker/classes.dockerpruner.ts +6 -0
  109. package/ts/mod_services/classes.dockercontainer.ts +912 -96
  110. package/ts/mod_services/classes.globalregistry.ts +290 -89
  111. package/ts/mod_services/classes.globalregistrystore.ts +279 -0
  112. package/ts/mod_services/classes.interprocesslock.ts +189 -0
  113. package/ts/mod_services/classes.serviceconfiguration.ts +215 -108
  114. package/ts/mod_services/classes.servicedatamarker.ts +210 -52
  115. package/ts/mod_services/classes.servicemanager.ts +1332 -512
  116. package/ts/mod_services/classes.servicenames.ts +76 -0
  117. package/ts/mod_services/classes.servicepruner.ts +310 -52
  118. package/ts/mod_services/index.ts +89 -62
  119. package/ts/mod_standard/index.ts +1 -1
  120. package/ts/plugins.ts +4 -0
  121. package/ts_migration/001.service-selection.ts +77 -0
  122. package/ts_migration/002.runtime-config.ts +218 -0
  123. package/ts_migration/003.service-data-marker.ts +216 -0
  124. package/ts_migration/004.global-registry.ts +272 -0
  125. package/ts_migration/index.ts +83 -0
@@ -1,28 +1,9 @@
1
- export interface IRegisteredProject {
2
- projectPath: string;
3
- projectName: string;
4
- containers: {
5
- mongo?: string;
6
- minio?: string;
7
- elasticsearch?: string;
8
- };
9
- ports: {
10
- mongo?: number;
11
- s3?: number;
12
- s3Console?: number;
13
- elasticsearch?: number;
14
- };
15
- enabledServices: string[];
16
- lastActive: number;
17
- }
18
- export interface IGlobalRegistryData {
19
- projects: {
20
- [projectPath: string]: IRegisteredProject;
21
- };
22
- }
1
+ import { type IRegisteredProject } from './classes.globalregistrystore.js';
2
+ export { assertCanonicalGlobalRegistryData } from './classes.globalregistrystore.js';
3
+ export type { IGlobalRegistryData, IRegisteredProject, } from './classes.globalregistrystore.js';
23
4
  export declare class GlobalRegistry {
24
5
  private static instance;
25
- private kvStore;
6
+ private store;
26
7
  private docker;
27
8
  private constructor();
28
9
  /**
@@ -36,7 +17,7 @@ export declare class GlobalRegistry {
36
17
  /**
37
18
  * Remove a project from the registry
38
19
  */
39
- unregisterProject(projectPath: string): Promise<void>;
20
+ unregisterProject(projectPathArg: string, expectedProjectArg: IRegisteredProject): Promise<void>;
40
21
  /**
41
22
  * Update the lastActive timestamp for a project
42
23
  */
@@ -47,6 +28,7 @@ export declare class GlobalRegistry {
47
28
  getAllProjects(): Promise<{
48
29
  [path: string]: IRegisteredProject;
49
30
  }>;
31
+ private readCanonicalData;
50
32
  /**
51
33
  * Check if a project is registered
52
34
  */
@@ -60,6 +42,7 @@ export declare class GlobalRegistry {
60
42
  containers: Array<{
61
43
  name: string;
62
44
  status: string;
45
+ ownership?: 'owned' | 'conflict';
63
46
  }>;
64
47
  lastActive: number;
65
48
  }>>;
@@ -70,6 +53,8 @@ export declare class GlobalRegistry {
70
53
  stopped: string[];
71
54
  failed: string[];
72
55
  }>;
56
+ private inspectRegisteredContainer;
57
+ private exactContainerExists;
73
58
  /**
74
59
  * Cheap staleness summary for a non-blocking hint after ordinary commands.
75
60
  *
@@ -90,4 +75,5 @@ export declare class GlobalRegistry {
90
75
  reason: string;
91
76
  }>;
92
77
  }>;
78
+ private withProjectServiceLocks;
93
79
  }
@@ -1,15 +1,21 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { DockerContainer } from './classes.dockercontainer.js';
3
3
  import { logger } from '../gitzone.logging.js';
4
+ import { getServiceContainerLabels, getServiceDataDirectory, hasExactServiceContainerLabels, serviceNames, } from './classes.servicedatamarker.js';
5
+ import { withServiceDataOperationLock } from './classes.interprocesslock.js';
6
+ import { GlobalRegistryStore, assertCanonicalGlobalRegistryData, } from './classes.globalregistrystore.js';
7
+ export { assertCanonicalGlobalRegistryData } from './classes.globalregistrystore.js';
8
+ const registryServiceNames = {
9
+ mongo: 'mongodb',
10
+ objectstorage: 'objectstorage',
11
+ elasticsearch: 'elasticsearch',
12
+ };
4
13
  export class GlobalRegistry {
5
14
  static instance = null;
6
- kvStore;
15
+ store;
7
16
  docker;
8
- constructor() {
9
- this.kvStore = new plugins.smartconfig.KeyValueStore({
10
- typeArg: 'userHomeDir',
11
- identityArg: 'gitzone-services',
12
- });
17
+ constructor(storeArg = new GlobalRegistryStore()) {
18
+ this.store = storeArg;
13
19
  this.docker = new DockerContainer();
14
20
  }
15
21
  /**
@@ -25,49 +31,82 @@ export class GlobalRegistry {
25
31
  * Register or update a project in the global registry
26
32
  */
27
33
  async registerProject(data) {
28
- const allData = await this.kvStore.readAll();
29
- const projects = allData.projects || {};
30
- projects[data.projectPath] = {
31
- ...data,
32
- lastActive: Date.now(),
33
- };
34
- await this.kvStore.writeKey('projects', projects);
34
+ const projectPath = plugins.path.resolve(data.projectPath);
35
+ await this.store.transact((rawData) => {
36
+ const allData = assertCanonicalGlobalRegistryData(rawData);
37
+ const projects = { ...allData.projects };
38
+ const existingLegacy = projects[projectPath]?.legacy;
39
+ projects[projectPath] = {
40
+ ...data,
41
+ projectPath,
42
+ ...(existingLegacy ? { legacy: existingLegacy } : {}),
43
+ lastActive: Date.now(),
44
+ };
45
+ return {
46
+ result: undefined,
47
+ writeData: { schemaVersion: 2, projects },
48
+ };
49
+ });
35
50
  }
36
51
  /**
37
52
  * Remove a project from the registry
38
53
  */
39
- async unregisterProject(projectPath) {
40
- const allData = await this.kvStore.readAll();
41
- const projects = allData.projects || {};
42
- if (projects[projectPath]) {
54
+ async unregisterProject(projectPathArg, expectedProjectArg) {
55
+ const projectPath = plugins.path.resolve(projectPathArg);
56
+ await this.store.transact((rawData) => {
57
+ const allData = assertCanonicalGlobalRegistryData(rawData);
58
+ const projects = { ...allData.projects };
59
+ const currentProject = projects[projectPath];
60
+ if (!currentProject) {
61
+ return { result: undefined };
62
+ }
63
+ if (JSON.stringify(currentProject) !== JSON.stringify(expectedProjectArg)) {
64
+ throw new Error(`Refusing to unregister changed global registry entry: ${projectPath}`);
65
+ }
43
66
  delete projects[projectPath];
44
- await this.kvStore.writeKey('projects', projects);
45
- }
67
+ return {
68
+ result: undefined,
69
+ writeData: { schemaVersion: 2, projects },
70
+ };
71
+ });
46
72
  }
47
73
  /**
48
74
  * Update the lastActive timestamp for a project
49
75
  */
50
76
  async touchProject(projectPath) {
51
- const allData = await this.kvStore.readAll();
52
- const projects = allData.projects || {};
53
- if (projects[projectPath]) {
54
- projects[projectPath].lastActive = Date.now();
55
- await this.kvStore.writeKey('projects', projects);
56
- }
77
+ const resolvedProjectPath = plugins.path.resolve(projectPath);
78
+ await this.store.transact((rawData) => {
79
+ const allData = assertCanonicalGlobalRegistryData(rawData);
80
+ const projects = { ...allData.projects };
81
+ const existing = projects[resolvedProjectPath];
82
+ if (!existing) {
83
+ return { result: undefined };
84
+ }
85
+ projects[resolvedProjectPath] = {
86
+ ...existing,
87
+ lastActive: Date.now(),
88
+ };
89
+ return {
90
+ result: undefined,
91
+ writeData: { schemaVersion: 2, projects },
92
+ };
93
+ });
57
94
  }
58
95
  /**
59
96
  * Get all registered projects
60
97
  */
61
98
  async getAllProjects() {
62
- const allData = await this.kvStore.readAll();
63
- return allData.projects || {};
99
+ return (await this.readCanonicalData()).projects;
100
+ }
101
+ async readCanonicalData() {
102
+ return this.store.readCanonical();
64
103
  }
65
104
  /**
66
105
  * Check if a project is registered
67
106
  */
68
107
  async isRegistered(projectPath) {
69
108
  const projects = await this.getAllProjects();
70
- return !!projects[projectPath];
109
+ return !!projects[plugins.path.resolve(projectPath)];
71
110
  }
72
111
  /**
73
112
  * Get status of all containers across all registered projects
@@ -77,8 +116,27 @@ export class GlobalRegistry {
77
116
  const result = [];
78
117
  for (const [path, project] of Object.entries(projects)) {
79
118
  const containerStatuses = [];
80
- for (const containerName of Object.values(project.containers)) {
119
+ for (const [serviceKey, containerName] of Object.entries(project.containers)) {
81
120
  if (containerName) {
121
+ if (serviceKey === 'objectstorage') {
122
+ const objectStorage = await this.inspectRegisteredContainer(project, containerName);
123
+ if (!objectStorage) {
124
+ containerStatuses.push({ name: containerName, status: 'not_exists' });
125
+ continue;
126
+ }
127
+ const expectedLabels = getServiceContainerLabels({
128
+ projectPath: project.projectPath,
129
+ service: 'objectstorage',
130
+ dataPath: getServiceDataDirectory(project.projectPath, 'objectstorage'),
131
+ });
132
+ const owned = hasExactServiceContainerLabels(objectStorage.labels, expectedLabels);
133
+ containerStatuses.push({
134
+ name: containerName,
135
+ status: objectStorage.state,
136
+ ownership: owned ? 'owned' : 'conflict',
137
+ });
138
+ continue;
139
+ }
82
140
  const status = await this.docker.getStatus(containerName);
83
141
  containerStatuses.push({ name: containerName, status });
84
142
  }
@@ -100,14 +158,60 @@ export class GlobalRegistry {
100
158
  const stopped = [];
101
159
  const failed = [];
102
160
  for (const project of Object.values(projects)) {
103
- for (const containerName of Object.values(project.containers)) {
161
+ for (const [serviceKey, containerName] of Object.entries(project.containers)) {
104
162
  if (containerName) {
105
- const status = await this.docker.getStatus(containerName);
106
- if (status === 'running') {
107
- if (await this.docker.stop(containerName)) {
108
- stopped.push(containerName);
109
- }
110
- else {
163
+ const service = registryServiceNames[serviceKey];
164
+ if (!service) {
165
+ failed.push(containerName);
166
+ continue;
167
+ }
168
+ try {
169
+ await withServiceDataOperationLock(project.projectPath, service, async () => {
170
+ const currentProjects = await this.getAllProjects();
171
+ const claims = [];
172
+ for (const [registeredPathArg, registeredProjectArg] of Object.entries(currentProjects)) {
173
+ for (const [registeredServiceKeyArg, registeredNameArg] of Object.entries(registeredProjectArg.containers)) {
174
+ const registeredService = registryServiceNames[registeredServiceKeyArg];
175
+ if (registeredService && registeredNameArg === containerName) {
176
+ claims.push({
177
+ projectPath: plugins.path.resolve(registeredPathArg),
178
+ service: registeredService,
179
+ });
180
+ }
181
+ }
182
+ }
183
+ const projectPath = plugins.path.resolve(project.projectPath);
184
+ const currentProject = Object.entries(currentProjects).find(([registeredPathArg]) => plugins.path.resolve(registeredPathArg) === projectPath)?.[1];
185
+ if (!currentProject || currentProject.containers[serviceKey] !== containerName) {
186
+ throw new Error('Registry container claim changed before stop');
187
+ }
188
+ const inspection = await this.inspectRegisteredContainer(currentProject, containerName);
189
+ if (!inspection) {
190
+ return;
191
+ }
192
+ const expectedLabels = getServiceContainerLabels({
193
+ projectPath,
194
+ service,
195
+ dataPath: getServiceDataDirectory(projectPath, service),
196
+ });
197
+ const labelOwned = hasExactServiceContainerLabels(inspection.labels, expectedLabels);
198
+ const hasGitZoneLabels = Object.keys(inspection.labels).some((keyArg) => keyArg.startsWith('git.zone.'));
199
+ const registryOwned = service !== 'objectstorage' &&
200
+ !hasGitZoneLabels &&
201
+ claims.length === 1 &&
202
+ claims[0].projectPath === projectPath &&
203
+ claims[0].service === service;
204
+ if (!labelOwned && !registryOwned) {
205
+ throw new Error('Container ownership conflict');
206
+ }
207
+ if (inspection.running) {
208
+ await this.docker.execArgv(['stop', inspection.id], { timeoutMs: 60_000 });
209
+ stopped.push(containerName);
210
+ }
211
+ });
212
+ }
213
+ catch {
214
+ if (!failed.includes(containerName)) {
111
215
  failed.push(containerName);
112
216
  }
113
217
  }
@@ -116,6 +220,28 @@ export class GlobalRegistry {
116
220
  }
117
221
  return { stopped, failed };
118
222
  }
223
+ async inspectRegisteredContainer(projectArg, containerNameArg) {
224
+ const ids = await this.docker.listIds([`name=^/${containerNameArg}$`]);
225
+ if (ids.length === 0) {
226
+ return undefined;
227
+ }
228
+ const inspections = (await this.docker.inspectMany(ids)).filter((inspection) => inspection.name === containerNameArg);
229
+ if (inspections.length !== 1) {
230
+ throw new Error(`Docker returned ambiguous ObjectStorage identity for ${projectArg.projectPath}.`);
231
+ }
232
+ return inspections[0];
233
+ }
234
+ async exactContainerExists(containerNameArg) {
235
+ const ids = await this.docker.listIds([`name=^/${containerNameArg}$`]);
236
+ if (ids.length === 0) {
237
+ return false;
238
+ }
239
+ const inspections = (await this.docker.inspectMany(ids)).filter((inspection) => inspection.name === containerNameArg);
240
+ if (inspections.length !== 1) {
241
+ throw new Error(`Docker returned ambiguous container identity for ${containerNameArg}.`);
242
+ }
243
+ return true;
244
+ }
119
245
  /**
120
246
  * Cheap staleness summary for a non-blocking hint after ordinary commands.
121
247
  *
@@ -145,35 +271,57 @@ export class GlobalRegistry {
145
271
  const projects = await this.getAllProjects();
146
272
  const removed = [];
147
273
  const kept = [];
148
- for (const [projectPath, project] of Object.entries(projects)) {
149
- if (await plugins.smartfs.directory(projectPath).exists()) {
150
- continue;
151
- }
152
- // Same rule ServicePruner enforces: for containers created before labels
153
- // existed, this registry entry is the only thing that can still identify
154
- // them. Dropping it while one exists would hide the container from prune,
155
- // `stop -g` and `cleanup -g` alike, leaving it running forever under
156
- // `restart: unless-stopped`.
157
- const survivingContainers = [];
158
- for (const containerName of Object.values(project.containers)) {
159
- if (!containerName) {
160
- continue;
274
+ for (const projectPath of Object.keys(projects)) {
275
+ await this.withProjectServiceLocks(projectPath, async () => {
276
+ if (await plugins.smartfs.directory(projectPath).exists()) {
277
+ return;
161
278
  }
162
- if ((await this.docker.getStatus(containerName)) !== 'not_exists') {
163
- survivingContainers.push(containerName);
279
+ const currentProject = Object.entries(await this.getAllProjects()).find(([registeredPathArg]) => plugins.path.resolve(registeredPathArg) === plugins.path.resolve(projectPath))?.[1];
280
+ if (!currentProject) {
281
+ return;
164
282
  }
165
- }
166
- if (survivingContainers.length > 0) {
167
- kept.push({
168
- projectPath,
169
- reason: `container(s) still exist: ${survivingContainers.join(', ')}`,
170
- });
171
- continue;
172
- }
173
- await this.unregisterProject(projectPath);
174
- removed.push(projectPath);
283
+ if (currentProject.legacy?.minioContainer) {
284
+ kept.push({
285
+ projectPath,
286
+ reason: `preserved legacy MinIO container reference: ${currentProject.legacy.minioContainer}`,
287
+ });
288
+ return;
289
+ }
290
+ // Same rule ServicePruner enforces: for containers created before labels
291
+ // existed, this registry entry is the only thing that can still identify
292
+ // them. Re-read under all service locks so a concurrent start cannot
293
+ // appear between the Docker check and compare-delete.
294
+ const survivingContainers = [];
295
+ for (const containerName of Object.values(currentProject.containers)) {
296
+ if (containerName && (await this.exactContainerExists(containerName))) {
297
+ survivingContainers.push(containerName);
298
+ }
299
+ }
300
+ const labeledIds = await this.docker.listIds([
301
+ `label=git.zone.project-path=${plugins.path.resolve(projectPath)}`,
302
+ ]);
303
+ if (labeledIds.length > 0) {
304
+ survivingContainers.push('project-labeled container');
305
+ }
306
+ if (survivingContainers.length > 0) {
307
+ kept.push({
308
+ projectPath,
309
+ reason: `container(s) still exist: ${survivingContainers.join(', ')}`,
310
+ });
311
+ return;
312
+ }
313
+ await this.unregisterProject(projectPath, currentProject);
314
+ removed.push(projectPath);
315
+ });
175
316
  }
176
317
  return { removed, kept };
177
318
  }
319
+ async withProjectServiceLocks(projectPathArg, actionArg, serviceIndexArg = 0) {
320
+ const service = serviceNames[serviceIndexArg];
321
+ if (!service) {
322
+ return actionArg();
323
+ }
324
+ return withServiceDataOperationLock(projectPathArg, service, () => this.withProjectServiceLocks(projectPathArg, actionArg, serviceIndexArg + 1));
325
+ }
178
326
  }
179
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5nbG9iYWxyZWdpc3RyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL21vZF9zZXJ2aWNlcy9jbGFzc2VzLmdsb2JhbHJlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUF3Qi9DLE1BQU0sT0FBTyxjQUFjO0lBQ2pCLE1BQU0sQ0FBQyxRQUFRLEdBQTBCLElBQUksQ0FBQztJQUM5QyxPQUFPLENBQXlEO0lBQ2hFLE1BQU0sQ0FBa0I7SUFFaEM7UUFDRSxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUM7WUFDbkQsT0FBTyxFQUFFLGFBQWE7WUFDdEIsV0FBVyxFQUFFLGtCQUFrQjtTQUNoQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUM7SUFDdEMsQ0FBQztJQUVEOztPQUVHO0lBQ0ksTUFBTSxDQUFDLFdBQVc7UUFDdkIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUM3QixjQUFjLENBQUMsUUFBUSxHQUFHLElBQUksY0FBYyxFQUFFLENBQUM7UUFDakQsQ0FBQztRQUNELE9BQU8sY0FBYyxDQUFDLFFBQVEsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsZUFBZSxDQUFDLElBQTRDO1FBQ3ZFLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUM3QyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQztRQUV4QyxRQUFRLENBQUMsSUFBSSxDQUFDLFdBQVcs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
327
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5nbG9iYWxyZWdpc3RyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL21vZF9zZXJ2aWNlcy9jbGFzc2VzLmdsb2JhbHJlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxlQUFlLEVBQThCLE1BQU0sOEJBQThCLENBQUM7QUFDM0YsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIsdUJBQXVCLEVBQ3ZCLDhCQUE4QixFQUM5QixZQUFZLEdBRWIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN4QyxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQztBQUM3RSxPQUFPLEVBQ0wsbUJBQW1CLEVBQ25CLGlDQUFpQyxHQUdsQyxNQUFNLGtDQUFrQyxDQUFDO0FBRTFDLE9BQU8sRUFBRSxpQ0FBaUMsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBTXJGLE1BQU0sb0JBQW9CLEdBQWlDO0lBQ3pELEtBQUssRUFBRSxTQUFTO0lBQ2hCLGFBQWEsRUFBRSxlQUFlO0lBQzlCLGFBQWEsRUFBRSxlQUFlO0NBQy9CLENBQUM7QUFFRixNQUFNLE9BQU8sY0FBYztJQUNqQixNQUFNLENBQUMsUUFBUSxHQUEwQixJQUFJLENBQUM7SUFDOUMsS0FBSyxDQUFzQjtJQUMzQixNQUFNLENBQWtCO0lBRWhDLFlBQW9CLFdBQWdDLElBQUksbUJBQW1CLEVBQUU7UUFDM0UsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUM7UUFDdEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO0lBQ3RDLENBQUM7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxXQUFXO1FBQ3ZCLElBQUksQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDN0Is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
@@ -0,0 +1,48 @@
1
+ export interface IRegisteredProject {
2
+ projectPath: string;
3
+ projectName: string;
4
+ containers: {
5
+ mongo?: string;
6
+ objectstorage?: string;
7
+ elasticsearch?: string;
8
+ };
9
+ ports: {
10
+ mongo?: number;
11
+ s3?: number;
12
+ s3Ui?: number;
13
+ elasticsearch?: number;
14
+ };
15
+ legacy?: {
16
+ /** Preserved migration evidence. Never passed to an active lifecycle operation. */
17
+ minioContainer?: string;
18
+ };
19
+ enabledServices: string[];
20
+ lastActive: number;
21
+ }
22
+ export interface IGlobalRegistryData {
23
+ schemaVersion: 2;
24
+ projects: {
25
+ [projectPath: string]: IRegisteredProject;
26
+ };
27
+ }
28
+ /** Validate the canonical runtime schema after startup migrations have completed. */
29
+ export declare const assertCanonicalGlobalRegistryData: (dataArg: unknown) => IGlobalRegistryData;
30
+ export interface IGlobalRegistryTransactionResult<T> {
31
+ result: T;
32
+ writeData?: IGlobalRegistryData;
33
+ }
34
+ export interface IGlobalRegistryStoreOptions {
35
+ filePath?: string;
36
+ lockTimeoutMs?: number;
37
+ lockPollMs?: number;
38
+ }
39
+ /** Raw, atomically replaced registry storage shared by runtime and migrations. */
40
+ export declare class GlobalRegistryStore {
41
+ readonly filePath: string;
42
+ private readonly lock;
43
+ constructor(optionsArg?: IGlobalRegistryStoreOptions);
44
+ readRaw(): Promise<unknown>;
45
+ readCanonical(): Promise<IGlobalRegistryData>;
46
+ transact<T>(operationArg: (rawDataArg: unknown) => Promise<IGlobalRegistryTransactionResult<T>> | IGlobalRegistryTransactionResult<T>): Promise<T>;
47
+ private writeAtomic;
48
+ }