hologit 0.46.1 → 0.47.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/bin/cli.js +2 -2
- package/commands/project.js +8 -2
- package/jest.config.js +7 -0
- package/lib/Lens.js +55 -21
- package/lib/Repo.js +2 -2
- package/lib/SpecObject.js +2 -2
- package/package.json +15 -18
package/bin/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ module.exports = { logger };
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
// route command line
|
|
24
|
-
require('yargs')
|
|
24
|
+
require('yargs')(process.argv.slice(2))
|
|
25
25
|
.version(require('../package.json').version)
|
|
26
26
|
.option('d', {
|
|
27
27
|
alias: 'debug',
|
|
@@ -58,4 +58,4 @@ require('yargs')
|
|
|
58
58
|
})
|
|
59
59
|
.strict()
|
|
60
60
|
.help()
|
|
61
|
-
.
|
|
61
|
+
.parse();
|
package/commands/project.js
CHANGED
|
@@ -10,6 +10,11 @@ exports.builder = {
|
|
|
10
10
|
describe: 'A commit message to use if commit-branch is specified',
|
|
11
11
|
type: 'string'
|
|
12
12
|
},
|
|
13
|
+
'commit-source-parent': {
|
|
14
|
+
describe: 'Include the source commit as a second parent in the projection commit',
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
default: true
|
|
17
|
+
},
|
|
13
18
|
'ref': {
|
|
14
19
|
describe: 'Commit ref to read holobranch from',
|
|
15
20
|
default: 'HEAD'
|
|
@@ -53,6 +58,7 @@ exports.handler = async function project ({
|
|
|
53
58
|
watch = false,
|
|
54
59
|
commitTo = null,
|
|
55
60
|
commitMessage = null,
|
|
61
|
+
commitSourceParent = true,
|
|
56
62
|
cacheFrom = null,
|
|
57
63
|
cacheTo = null
|
|
58
64
|
}) {
|
|
@@ -136,7 +142,7 @@ exports.handler = async function project ({
|
|
|
136
142
|
lens,
|
|
137
143
|
commitTo,
|
|
138
144
|
commitMessage,
|
|
139
|
-
parentCommit,
|
|
145
|
+
parentCommit: commitSourceParent ? parentCommit : null,
|
|
140
146
|
fetch,
|
|
141
147
|
cacheFrom,
|
|
142
148
|
cacheTo
|
|
@@ -156,7 +162,7 @@ exports.handler = async function project ({
|
|
|
156
162
|
lens,
|
|
157
163
|
commitTo,
|
|
158
164
|
commitMessage,
|
|
159
|
-
parentCommit: newCommitHash,
|
|
165
|
+
parentCommit: commitSourceParent ? newCommitHash : null,
|
|
160
166
|
cacheFrom,
|
|
161
167
|
cacheTo
|
|
162
168
|
});
|
package/jest.config.js
ADDED
package/lib/Lens.js
CHANGED
|
@@ -110,33 +110,46 @@ class Lens extends Configurable {
|
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
async
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// check if image exists locally first
|
|
117
|
-
let imageHash;
|
|
113
|
+
async getImageHash (containerQuery) {
|
|
114
|
+
// Try local first (fastest)
|
|
118
115
|
try {
|
|
119
116
|
const inspectOutput = await Studio.execDocker(['inspect', containerQuery]);
|
|
120
117
|
const imageInfo = JSON.parse(inspectOutput)[0];
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
logger.info(`found local image: ${containerQuery}@${imageInfo.Id}`);
|
|
119
|
+
return { hash: imageInfo.Id, isLocal: true };
|
|
123
120
|
} catch (err) {
|
|
124
|
-
//
|
|
125
|
-
logger.info(`pulling image: ${containerQuery}`);
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
await Studio.execDocker(['pull', containerQuery], { $relayStdout: true });
|
|
129
|
-
const inspectOutput = await Studio.execDocker(['inspect', containerQuery]);
|
|
130
|
-
const imageInfo = JSON.parse(inspectOutput)[0];
|
|
131
|
-
imageHash = imageInfo.Id;
|
|
132
|
-
} catch (err) {
|
|
133
|
-
throw new Error(`failed to pull container image ${containerQuery}: ${err.message}`);
|
|
134
|
-
}
|
|
121
|
+
// Not found locally, try remote manifest
|
|
135
122
|
}
|
|
136
123
|
|
|
137
|
-
|
|
138
|
-
|
|
124
|
+
// Try remote manifest (doesn't pull the image)
|
|
125
|
+
try {
|
|
126
|
+
logger.info(`querying remote manifest for: ${containerQuery}`);
|
|
127
|
+
const manifestOutput = await Studio.execDocker(['manifest', 'inspect', containerQuery]);
|
|
128
|
+
const manifest = JSON.parse(manifestOutput);
|
|
129
|
+
|
|
130
|
+
// Extract digest from manifest
|
|
131
|
+
// For multi-arch images, manifest.config.digest contains the config digest
|
|
132
|
+
// For single-arch images, we may need to look at the digest field
|
|
133
|
+
const digest = manifest.config?.digest || manifest.digest;
|
|
134
|
+
|
|
135
|
+
if (!digest) {
|
|
136
|
+
throw new Error('No digest found in manifest');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Ensure the digest is in the format sha256:...
|
|
140
|
+
const imageHash = digest.startsWith('sha256:') ? digest : `sha256:${digest}`;
|
|
141
|
+
logger.info(`found remote image hash: ${containerQuery}@${imageHash}`);
|
|
142
|
+
return { hash: imageHash, isLocal: false };
|
|
143
|
+
} catch (err) {
|
|
144
|
+
throw new Error(`failed to get hash for container image ${containerQuery}: ${err.message}`);
|
|
139
145
|
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async buildSpecForContainer (inputTree, config) {
|
|
149
|
+
const { container: containerQuery } = config;
|
|
150
|
+
|
|
151
|
+
// Get image hash without pulling
|
|
152
|
+
const { hash: imageHash, isLocal } = await this.getImageHash(containerQuery);
|
|
140
153
|
|
|
141
154
|
// build spec
|
|
142
155
|
const data = {
|
|
@@ -152,7 +165,8 @@ class Lens extends Configurable {
|
|
|
152
165
|
return {
|
|
153
166
|
...await SpecObject.write(this.workspace.getRepo(), 'lens', data),
|
|
154
167
|
data,
|
|
155
|
-
type: 'container'
|
|
168
|
+
type: 'container',
|
|
169
|
+
imageIsLocal: isLocal
|
|
156
170
|
};
|
|
157
171
|
}
|
|
158
172
|
|
|
@@ -317,6 +331,26 @@ class Lens extends Configurable {
|
|
|
317
331
|
}
|
|
318
332
|
const [, sha256Hash] = containerMatch;
|
|
319
333
|
|
|
334
|
+
// Ensure image is available locally
|
|
335
|
+
try {
|
|
336
|
+
await Studio.execDocker(['inspect', sha256Hash]);
|
|
337
|
+
} catch (err) {
|
|
338
|
+
// Image not found locally, need to pull it
|
|
339
|
+
// Extract the original container query from spec to pull by name:tag
|
|
340
|
+
const containerQueryMatch = spec.container.match(/^(.+)@sha256:[a-f0-9]{64}$/);
|
|
341
|
+
if (containerQueryMatch) {
|
|
342
|
+
const containerQuery = containerQueryMatch[1];
|
|
343
|
+
logger.info(`pulling required image: ${containerQuery}`);
|
|
344
|
+
try {
|
|
345
|
+
await Studio.execDocker(['pull', containerQuery], { $relayStdout: true });
|
|
346
|
+
} catch (pullErr) {
|
|
347
|
+
throw new Error(`failed to pull container image ${containerQuery}: ${pullErr.message}`);
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
throw new Error(`cannot extract container query from spec.container: ${spec.container}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
320
354
|
// create and start container
|
|
321
355
|
const persistentDebugContainer = process.env.HOLO_DEBUG_PERSIST_CONTAINER;
|
|
322
356
|
let containerId;
|
package/lib/Repo.js
CHANGED
|
@@ -196,7 +196,7 @@ class Repo {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
async watch ({ callback }) {
|
|
199
|
-
const debounce =
|
|
199
|
+
const { default: debounce } = await import('debounce');
|
|
200
200
|
const logger = require('../lib/logger.js');
|
|
201
201
|
|
|
202
202
|
|
|
@@ -313,7 +313,7 @@ class Repo {
|
|
|
313
313
|
cancel
|
|
314
314
|
};
|
|
315
315
|
} else {
|
|
316
|
-
const chokidar =
|
|
316
|
+
const { default: chokidar } = await import('chokidar');
|
|
317
317
|
const watcher = chokidar.watch([], {
|
|
318
318
|
persistent: true,
|
|
319
319
|
cwd: this.gitDir,
|
package/lib/SpecObject.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const sortKeys = require('sort-keys');
|
|
2
1
|
const TOML = require('@iarna/toml');
|
|
3
2
|
|
|
4
3
|
|
|
@@ -8,7 +7,8 @@ const BlobObject = require('./BlobObject.js');
|
|
|
8
7
|
class SpecObject extends BlobObject {
|
|
9
8
|
|
|
10
9
|
static async write (repo, kind, data) {
|
|
11
|
-
// build ordered spec object
|
|
10
|
+
// build ordered spec object (sort-keys is ESM-only, requires dynamic import)
|
|
11
|
+
const { default: sortKeys } = await import('sort-keys');
|
|
12
12
|
const holospec = {};
|
|
13
13
|
holospec[kind] = sortKeys(data, { deep: true });
|
|
14
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hologit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Hologit automates the projection of layered composite file trees based on flat, declarative plans",
|
|
5
5
|
"repository": "https://github.com/EmergencePlatform/hologit",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -11,29 +11,29 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@iarna/toml": "^2.2.5",
|
|
13
13
|
"async-exit-hook": "^2.0.1",
|
|
14
|
-
"axios": "^1.
|
|
15
|
-
"chokidar": "^
|
|
16
|
-
"debounce": "^
|
|
17
|
-
"fb-watchman": "^2.0.
|
|
14
|
+
"axios": "^1.13.2",
|
|
15
|
+
"chokidar": "^5.0.0",
|
|
16
|
+
"debounce": "^3.0.0",
|
|
17
|
+
"fb-watchman": "^2.0.2",
|
|
18
18
|
"git-client": "^1.9.4",
|
|
19
19
|
"hab-client": "^1.1.3",
|
|
20
|
-
"handlebars": "^4.7.
|
|
21
|
-
"minimatch": "^10.
|
|
22
|
-
"mz": "^2.
|
|
20
|
+
"handlebars": "^4.7.8",
|
|
21
|
+
"minimatch": "^10.1.1",
|
|
22
|
+
"mz": "^2.7.0",
|
|
23
23
|
"mz-modules": "^2.1.0",
|
|
24
24
|
"object-squish": "^1.1.0",
|
|
25
|
-
"parse-url": "^
|
|
25
|
+
"parse-url": "^10.0.3",
|
|
26
26
|
"shell-quote-word": "^1.0.1",
|
|
27
|
-
"sort-keys": "^
|
|
27
|
+
"sort-keys": "^6.0.0",
|
|
28
28
|
"toposort": "^2.0.2",
|
|
29
|
-
"winston": "^3.
|
|
30
|
-
"yargs": "^
|
|
29
|
+
"winston": "^3.19.0",
|
|
30
|
+
"yargs": "^18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"bin": {
|
|
33
33
|
"git-holo": "./bin/cli.js"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
|
-
"node": "
|
|
36
|
+
"node": "^20.19.0 || ^22.12.0 || >=23"
|
|
37
37
|
},
|
|
38
38
|
"os": [
|
|
39
39
|
"darwin",
|
|
@@ -48,11 +48,8 @@
|
|
|
48
48
|
"projection"
|
|
49
49
|
],
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@types/jest": "^
|
|
52
|
-
"jest": "^
|
|
53
|
-
},
|
|
54
|
-
"jest": {
|
|
55
|
-
"testEnvironment": "node"
|
|
51
|
+
"@types/jest": "^30.0.0",
|
|
52
|
+
"jest": "^30.2.0"
|
|
56
53
|
},
|
|
57
54
|
"scripts": {
|
|
58
55
|
"test": "jest"
|