@lage-run/hasher 1.4.0 → 1.5.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/CHANGELOG.json +22 -1
- package/CHANGELOG.md +11 -2
- package/lib/TargetHasher.d.ts +1 -3
- package/lib/TargetHasher.js +14 -66
- package/lib/__tests__/TargetHasher.test.js +19 -0
- package/lib/expandInputPatterns.d.ts +3 -0
- package/lib/expandInputPatterns.js +47 -0
- package/lib/getInputFiles.d.ts +4 -0
- package/lib/getInputFiles.js +23 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +16 -3
- package/package.json +2 -2
package/CHANGELOG.json
CHANGED
|
@@ -2,7 +2,28 @@
|
|
|
2
2
|
"name": "@lage-run/hasher",
|
|
3
3
|
"entries": [
|
|
4
4
|
{
|
|
5
|
-
"date": "
|
|
5
|
+
"date": "Fri, 27 Sep 2024 20:03:27 GMT",
|
|
6
|
+
"version": "1.5.0",
|
|
7
|
+
"tag": "@lage-run/hasher_v1.5.0",
|
|
8
|
+
"comments": {
|
|
9
|
+
"minor": [
|
|
10
|
+
{
|
|
11
|
+
"author": "kchau@microsoft.com",
|
|
12
|
+
"package": "@lage-run/hasher",
|
|
13
|
+
"commit": "2919f9041f931dc6ef65017f7aedb9fef9dab66d",
|
|
14
|
+
"comment": "exposes getInputFiles, packageTrees"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"author": "beachball",
|
|
18
|
+
"package": "@lage-run/hasher",
|
|
19
|
+
"comment": "Bump @lage-run/globby to v14.1.0",
|
|
20
|
+
"commit": "not available"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"date": "Wed, 25 Sep 2024 20:28:10 GMT",
|
|
6
27
|
"version": "1.4.0",
|
|
7
28
|
"tag": "@lage-run/hasher_v1.4.0",
|
|
8
29
|
"comments": {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
# Change Log - @lage-run/hasher
|
|
2
2
|
|
|
3
|
-
<!-- This log was last generated on
|
|
3
|
+
<!-- This log was last generated on Fri, 27 Sep 2024 20:03:27 GMT and should not be manually modified. -->
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## 1.5.0
|
|
8
|
+
|
|
9
|
+
Fri, 27 Sep 2024 20:03:27 GMT
|
|
10
|
+
|
|
11
|
+
### Minor changes
|
|
12
|
+
|
|
13
|
+
- exposes getInputFiles, packageTrees (kchau@microsoft.com)
|
|
14
|
+
- Bump @lage-run/globby to v14.1.0
|
|
15
|
+
|
|
7
16
|
## 1.4.0
|
|
8
17
|
|
|
9
|
-
Wed, 25 Sep 2024 20:
|
|
18
|
+
Wed, 25 Sep 2024 20:28:10 GMT
|
|
10
19
|
|
|
11
20
|
### Minor changes
|
|
12
21
|
|
package/lib/TargetHasher.d.ts
CHANGED
|
@@ -45,14 +45,12 @@ export declare class TargetHasher {
|
|
|
45
45
|
lockInfo: ParsedLock | undefined;
|
|
46
46
|
targetHashes: Record<string, string>;
|
|
47
47
|
dependencyMap: DependencyMap;
|
|
48
|
-
memoizedEnvGlobResults: Map<string, string[]>;
|
|
49
|
-
getMemorizedEnvGlobResults(envGlob: string[]): Promise<string[]>;
|
|
50
48
|
getPackageInfos(workspacePackages: WorkspaceInfo): PackageInfos;
|
|
51
|
-
expandInputPatterns(patterns: string[], target: Target): Record<string, string[]>;
|
|
52
49
|
constructor(options: TargetHasherOptions);
|
|
53
50
|
ensureInitialized(): void;
|
|
54
51
|
initialize(): Promise<void>;
|
|
55
52
|
hash(target: Target): Promise<string>;
|
|
56
53
|
writeTargetHashesManifest(): void;
|
|
54
|
+
getEnvironmentGlobHashes(root: string, target: Target): Promise<Record<string, string>>;
|
|
57
55
|
cleanup(): Promise<void>;
|
|
58
56
|
}
|
package/lib/TargetHasher.js
CHANGED
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "TargetHasher", {
|
|
|
9
9
|
}
|
|
10
10
|
});
|
|
11
11
|
const _globhasher = require("glob-hasher");
|
|
12
|
-
const
|
|
12
|
+
const _globby = require("@lage-run/globby");
|
|
13
13
|
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
|
|
14
14
|
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
|
|
15
15
|
const _workspacetools = require("workspace-tools");
|
|
@@ -19,6 +19,7 @@ const _resolveInternalDependencies = require("./resolveInternalDependencies.js")
|
|
|
19
19
|
const _resolveExternalDependencies = require("./resolveExternalDependencies.js");
|
|
20
20
|
const _FileHasher = require("./FileHasher.js");
|
|
21
21
|
const _PackageTree = require("./PackageTree.js");
|
|
22
|
+
const _getInputFiles = require("./getInputFiles.js");
|
|
22
23
|
function _define_property(obj, key, value) {
|
|
23
24
|
if (key in obj) {
|
|
24
25
|
Object.defineProperty(obj, key, {
|
|
@@ -38,17 +39,6 @@ function _interop_require_default(obj) {
|
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
class TargetHasher {
|
|
41
|
-
async getMemorizedEnvGlobResults(envGlob) {
|
|
42
|
-
const key = envGlob.join("\0ENV_GLOB\0");
|
|
43
|
-
const { root } = this.options;
|
|
44
|
-
if (!this.memoizedEnvGlobResults.has(key)) {
|
|
45
|
-
const files = await (0, _fastglob.default)(envGlob, {
|
|
46
|
-
cwd: root
|
|
47
|
-
});
|
|
48
|
-
this.memoizedEnvGlobResults.set(key, files);
|
|
49
|
-
}
|
|
50
|
-
return this.memoizedEnvGlobResults.get(key) ?? [];
|
|
51
|
-
}
|
|
52
42
|
getPackageInfos(workspacePackages) {
|
|
53
43
|
const { root } = this.options;
|
|
54
44
|
const packageInfos = {};
|
|
@@ -72,43 +62,6 @@ class TargetHasher {
|
|
|
72
62
|
}
|
|
73
63
|
return packageInfos;
|
|
74
64
|
}
|
|
75
|
-
expandInputPatterns(patterns, target) {
|
|
76
|
-
const expandedPatterns = {};
|
|
77
|
-
for (const pattern of patterns){
|
|
78
|
-
if (pattern.startsWith("^") || pattern.startsWith("!^")) {
|
|
79
|
-
const matchPattern = pattern.replace("^", "");
|
|
80
|
-
// get all the packages that are transitive deps and add them to the list
|
|
81
|
-
const queue = [
|
|
82
|
-
target.packageName
|
|
83
|
-
];
|
|
84
|
-
const visited = new Set();
|
|
85
|
-
while(queue.length > 0){
|
|
86
|
-
const pkg = queue.pop();
|
|
87
|
-
if (visited.has(pkg)) {
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
visited.add(pkg);
|
|
91
|
-
if (pkg !== target.packageName) {
|
|
92
|
-
expandedPatterns[pkg] = expandedPatterns[pkg] ?? [];
|
|
93
|
-
expandedPatterns[pkg].push(matchPattern);
|
|
94
|
-
}
|
|
95
|
-
if (this.dependencyMap.dependencies.has(pkg)) {
|
|
96
|
-
const deps = this.dependencyMap.dependencies.get(pkg);
|
|
97
|
-
if (deps) {
|
|
98
|
-
for (const dep of deps){
|
|
99
|
-
queue.push(dep);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
} else {
|
|
105
|
-
const pkg = target.packageName;
|
|
106
|
-
expandedPatterns[pkg] = expandedPatterns[pkg] ?? [];
|
|
107
|
-
expandedPatterns[pkg].push(pattern);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return expandedPatterns;
|
|
111
|
-
}
|
|
112
65
|
ensureInitialized() {
|
|
113
66
|
if (!this.initializedPromise) {
|
|
114
67
|
throw new Error("TargetHasher is not initialized");
|
|
@@ -121,7 +74,9 @@ class TargetHasher {
|
|
|
121
74
|
return;
|
|
122
75
|
}
|
|
123
76
|
this.initializedPromise = Promise.all([
|
|
124
|
-
this.fileHasher.readManifest().then(()=>
|
|
77
|
+
this.fileHasher.readManifest().then(()=>(0, _globby.globAsync)(environmentGlob, {
|
|
78
|
+
cwd: root
|
|
79
|
+
})).then((files)=>this.fileHasher.hash(files)).then((hash)=>this.globalInputsHash = hash),
|
|
125
80
|
(0, _workspacetools.getWorkspacesAsync)(root).then((workspaceInfo)=>this.workspaceInfo = workspaceInfo).then(()=>{
|
|
126
81
|
this.packageInfos = this.getPackageInfos(this.workspaceInfo);
|
|
127
82
|
this.dependencyMap = (0, _workspacetools.createDependencyMap)(this.packageInfos, {
|
|
@@ -142,9 +97,6 @@ class TargetHasher {
|
|
|
142
97
|
if (this.logger !== undefined) {
|
|
143
98
|
const globalInputsHash = (0, _hashStrings.hashStrings)(Object.values(this.globalInputsHash ?? {}));
|
|
144
99
|
this.logger.verbose(`Global inputs hash: ${globalInputsHash}`);
|
|
145
|
-
// Log global input hashs to log file
|
|
146
|
-
const globalInputsHashJson = JSON.stringify(this.globalInputsHash, null, 2);
|
|
147
|
-
this.logger.silly(globalInputsHashJson);
|
|
148
100
|
}
|
|
149
101
|
}
|
|
150
102
|
async hash(target) {
|
|
@@ -154,7 +106,7 @@ class TargetHasher {
|
|
|
154
106
|
if (!target.inputs) {
|
|
155
107
|
throw new Error("Root-level targets must have `inputs` defined if it has cache enabled.");
|
|
156
108
|
}
|
|
157
|
-
const files = await (0,
|
|
109
|
+
const files = await (0, _globby.globAsync)(target.inputs, {
|
|
158
110
|
cwd: root
|
|
159
111
|
});
|
|
160
112
|
const fileFashes = (0, _globhasher.hash)(files, {
|
|
@@ -178,19 +130,11 @@ class TargetHasher {
|
|
|
178
130
|
...internalDeps,
|
|
179
131
|
...externalDeps
|
|
180
132
|
].sort();
|
|
181
|
-
const
|
|
182
|
-
"**/*"
|
|
183
|
-
];
|
|
184
|
-
const packagePatterns = this.expandInputPatterns(inputs, target);
|
|
185
|
-
const files = [];
|
|
186
|
-
for (const [pkg, patterns] of Object.entries(packagePatterns)){
|
|
187
|
-
const packageFiles = this.packageTree.getPackageFiles(pkg, patterns);
|
|
188
|
-
files.push(...packageFiles);
|
|
189
|
-
}
|
|
133
|
+
const files = (0, _getInputFiles.getInputFiles)(target, this.dependencyMap, this.packageTree);
|
|
190
134
|
const fileHashes = this.fileHasher.hash(files) ?? {}; // this list is sorted by file name
|
|
191
135
|
// get target hashes
|
|
192
136
|
const targetDepHashes = target.dependencies?.sort().map((targetDep)=>this.targetHashes[targetDep]);
|
|
193
|
-
const globalFileHashes =
|
|
137
|
+
const globalFileHashes = await this.getEnvironmentGlobHashes(root, target);
|
|
194
138
|
const combinedHashes = [
|
|
195
139
|
// Environmental hashes
|
|
196
140
|
...Object.values(globalFileHashes),
|
|
@@ -224,6 +168,12 @@ class TargetHasher {
|
|
|
224
168
|
}), "utf-8");
|
|
225
169
|
}
|
|
226
170
|
}
|
|
171
|
+
async getEnvironmentGlobHashes(root, target) {
|
|
172
|
+
const globalFileHashes = target.environmentGlob ? this.fileHasher.hash(await (0, _globby.globAsync)(target.environmentGlob ?? [], {
|
|
173
|
+
cwd: root
|
|
174
|
+
})) : this.globalInputsHash ?? {};
|
|
175
|
+
return globalFileHashes;
|
|
176
|
+
}
|
|
227
177
|
async cleanup() {
|
|
228
178
|
this.writeTargetHashesManifest();
|
|
229
179
|
await this.fileHasher.writeManifest();
|
|
@@ -242,7 +192,6 @@ class TargetHasher {
|
|
|
242
192
|
_define_property(this, "lockInfo", void 0);
|
|
243
193
|
_define_property(this, "targetHashes", void 0);
|
|
244
194
|
_define_property(this, "dependencyMap", void 0);
|
|
245
|
-
_define_property(this, "memoizedEnvGlobResults", void 0);
|
|
246
195
|
this.options = options;
|
|
247
196
|
this.targetHashesLog = {};
|
|
248
197
|
this.packageInfos = {};
|
|
@@ -251,7 +200,6 @@ class TargetHasher {
|
|
|
251
200
|
dependencies: new Map(),
|
|
252
201
|
dependents: new Map()
|
|
253
202
|
};
|
|
254
|
-
this.memoizedEnvGlobResults = new Map();
|
|
255
203
|
const { root , logger } = options;
|
|
256
204
|
this.logger = logger;
|
|
257
205
|
this.fileHasher = new _FileHasher.FileHasher({
|
|
@@ -36,6 +36,25 @@ describe("The main Hasher class", ()=>{
|
|
|
36
36
|
task
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
it("creates different hashes given different global environment glob", async ()=>{
|
|
40
|
+
const monorepo1 = await setupFixture("monorepo-with-global-files");
|
|
41
|
+
const hasher = new _index.TargetHasher({
|
|
42
|
+
root: monorepo1.root,
|
|
43
|
+
environmentGlob: [
|
|
44
|
+
"some-global.config.js"
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
const target = createTarget(monorepo1.root, "package-a", "build");
|
|
48
|
+
const hash = await getHash(hasher, target);
|
|
49
|
+
const hasher2 = new _index.TargetHasher({
|
|
50
|
+
root: monorepo1.root,
|
|
51
|
+
environmentGlob: []
|
|
52
|
+
});
|
|
53
|
+
const target2 = createTarget(monorepo1.root, "package-a", "build");
|
|
54
|
+
const hash2 = await getHash(hasher2, target2);
|
|
55
|
+
expect(hash).not.toEqual(hash2);
|
|
56
|
+
monorepo1.cleanup();
|
|
57
|
+
});
|
|
39
58
|
it("creates different hashes given different fixtures", async ()=>{
|
|
40
59
|
const monorepo1 = await setupFixture("monorepo");
|
|
41
60
|
const hasher = new _index.TargetHasher({
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "expandInputPatterns", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return expandInputPatterns;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
function expandInputPatterns(patterns, target, dependencyMap) {
|
|
12
|
+
const expandedPatterns = {};
|
|
13
|
+
for (const pattern of patterns){
|
|
14
|
+
if (pattern.startsWith("^") || pattern.startsWith("!^")) {
|
|
15
|
+
const matchPattern = pattern.replace("^", "");
|
|
16
|
+
// get all the packages that are transitive deps and add them to the list
|
|
17
|
+
const queue = [
|
|
18
|
+
target.packageName
|
|
19
|
+
];
|
|
20
|
+
const visited = new Set();
|
|
21
|
+
while(queue.length > 0){
|
|
22
|
+
const pkg = queue.pop();
|
|
23
|
+
if (visited.has(pkg)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
visited.add(pkg);
|
|
27
|
+
if (pkg !== target.packageName) {
|
|
28
|
+
expandedPatterns[pkg] = expandedPatterns[pkg] ?? [];
|
|
29
|
+
expandedPatterns[pkg].push(matchPattern);
|
|
30
|
+
}
|
|
31
|
+
if (dependencyMap.dependencies.has(pkg)) {
|
|
32
|
+
const deps = dependencyMap.dependencies.get(pkg);
|
|
33
|
+
if (deps) {
|
|
34
|
+
for (const dep of deps){
|
|
35
|
+
queue.push(dep);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
const pkg = target.packageName;
|
|
42
|
+
expandedPatterns[pkg] = expandedPatterns[pkg] ?? [];
|
|
43
|
+
expandedPatterns[pkg].push(pattern);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return expandedPatterns;
|
|
47
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type Target } from "@lage-run/target-graph";
|
|
2
|
+
import { type DependencyMap } from "workspace-tools";
|
|
3
|
+
import { type PackageTree } from "./PackageTree.js";
|
|
4
|
+
export declare function getInputFiles(target: Target, dependencyMap: DependencyMap, packageTree: PackageTree): string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "getInputFiles", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return getInputFiles;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _expandInputPatterns = require("./expandInputPatterns.js");
|
|
12
|
+
function getInputFiles(target, dependencyMap, packageTree) {
|
|
13
|
+
const inputs = target.inputs ?? [
|
|
14
|
+
"**/*"
|
|
15
|
+
];
|
|
16
|
+
const packagePatterns = (0, _expandInputPatterns.expandInputPatterns)(inputs, target, dependencyMap);
|
|
17
|
+
const files = [];
|
|
18
|
+
for (const [pkg, patterns] of Object.entries(packagePatterns)){
|
|
19
|
+
const packageFiles = packageTree.getPackageFiles(pkg, patterns);
|
|
20
|
+
files.push(...packageFiles);
|
|
21
|
+
}
|
|
22
|
+
return files;
|
|
23
|
+
}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -2,10 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
TargetHasher: function() {
|
|
8
13
|
return _TargetHasher.TargetHasher;
|
|
14
|
+
},
|
|
15
|
+
PackageTree: function() {
|
|
16
|
+
return _PackageTree.PackageTree;
|
|
17
|
+
},
|
|
18
|
+
getInputFiles: function() {
|
|
19
|
+
return _getInputFiles.getInputFiles;
|
|
9
20
|
}
|
|
10
21
|
});
|
|
11
22
|
const _TargetHasher = require("./TargetHasher.js");
|
|
23
|
+
const _PackageTree = require("./PackageTree.js");
|
|
24
|
+
const _getInputFiles = require("./getInputFiles.js");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lage-run/hasher",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Hasher for Lage Targets",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/microsoft/lage"
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"lint": "monorepo-scripts lint"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
+
"@lage-run/globby": "^14.1.0",
|
|
18
19
|
"@lage-run/logger": "^1.3.1",
|
|
19
20
|
"@lage-run/target-graph": "^0.8.10",
|
|
20
21
|
"execa": "5.1.1",
|
|
21
|
-
"fast-glob": "3.3.2",
|
|
22
22
|
"glob-hasher": "^1.4.2",
|
|
23
23
|
"graceful-fs": "4.2.11",
|
|
24
24
|
"micromatch": "4.0.8",
|