@@ -35,21 +35,22 @@ class DependenciesHashFile {
35
35
/// Populate the hashes and persist file with entries from
36
36
/// [fileSystemEntities] .
37
37
///
38
- /// If [validBeforeLastModified] is provided, any entities that were modified
39
- /// after [validBeforeLastModified] will get a dummy hash so that they will
40
- /// show up as outdated. If any such entity exists, its uri will be returned.
41
- Future <Uri ?> hashFilesAndDirectories (
42
- List <Uri > fileSystemEntities, {
43
- DateTime ? validBeforeLastModified,
44
- }) async {
38
+ /// If [fileSystemValidBeforeLastModified] is provided, any entities that were
39
+ /// modified after [fileSystemValidBeforeLastModified] will get a dummy hash
40
+ /// so that they will show up as outdated. If any such entity exists, its uri
41
+ /// will be returned.
42
+ Future <Uri ?> hashDependencies (
43
+ List <Uri > fileSystemEntities,
44
+ DateTime fileSystemValidBeforeLastModified,
45
+ Map <String , String > environment,
46
+ ) async {
45
47
_reset ();
46
48
47
49
Uri ? modifiedAfterTimeStamp;
48
50
for (final uri in fileSystemEntities) {
49
51
int hash;
50
- if (validBeforeLastModified != null &&
51
- (await uri.fileSystemEntity.lastModified ())
52
- .isAfter (validBeforeLastModified)) {
52
+ if ((await uri.fileSystemEntity.lastModified ())
53
+ .isAfter (fileSystemValidBeforeLastModified)) {
53
54
hash = _hashLastModifiedAfterCutoff;
54
55
modifiedAfterTimeStamp = uri;
55
56
} else {
@@ -61,30 +62,55 @@ class DependenciesHashFile {
61
62
}
62
63
_hashes.files.add (FilesystemEntityHash (uri, hash));
63
64
}
65
+ for (final entry in environment.entries) {
66
+ _hashes.environment.add (EnvironmentVariableHash (
67
+ entry.key, _hashEnvironmentValue (entry.value)));
68
+ }
64
69
await _persist ();
65
70
return modifiedAfterTimeStamp;
66
71
}
67
72
68
73
Future <void > _persist () => _file.writeAsString (json.encode (_hashes.toJson ()));
69
74
70
- /// Reads the file with hashes and finds an outdated file or directory if it
71
- /// exists.
72
- Future <Uri ?> findOutdatedFileSystemEntity () async {
75
+ /// Reads the file with hashes and reports if there is an outdated file,
76
+ /// directory or environment variable.
77
+ Future <String ?> findOutdatedDependency (
78
+ Map <String , String > environment,
79
+ ) async {
73
80
await _readFile ();
74
81
75
82
for (final savedHash in _hashes.files) {
76
83
final uri = savedHash.path;
77
84
final savedHashValue = savedHash.hash;
78
- final int hashValue;
79
85
if (_isDirectoryPath (uri.path)) {
80
- hashValue = await _hashDirectory (uri);
86
+ final hashValue = await _hashDirectory (uri);
87
+ if (savedHashValue != hashValue) {
88
+ return 'Directory contents changed: ${uri .toFilePath ()}.' ;
89
+ }
81
90
} else {
82
- hashValue = await _hashFile (uri);
91
+ final hashValue = await _hashFile (uri);
92
+ if (savedHashValue != hashValue) {
93
+ return 'File contents changed: ${uri .toFilePath ()}.' ;
94
+ }
95
+ }
96
+ }
97
+
98
+ // Check if env vars changed or were removed.
99
+ for (final savedHash in _hashes.environment) {
100
+ final hashValue = _hashEnvironmentValue (environment[savedHash.key]);
101
+ if (savedHash.hash != hashValue) {
102
+ return 'Environment variable changed: ${savedHash .key }.' ;
83
103
}
84
- if (savedHashValue != hashValue) {
85
- return uri;
104
+ }
105
+
106
+ // Check if env vars were added.
107
+ final savedEnvKeys = _hashes.environment.map ((e) => e.key).toSet ();
108
+ for (final envKey in environment.keys) {
109
+ if (! savedEnvKeys.contains (envKey)) {
110
+ return 'Environment variable changed: $envKey .' ;
86
111
}
87
112
}
113
+
88
114
return null ;
89
115
}
90
116
@@ -113,6 +139,11 @@ class DependenciesHashFile {
113
139
return _md5int64 (utf8.encode (childrenNames));
114
140
}
115
141
142
+ int _hashEnvironmentValue (String ? value) {
143
+ if (value == null ) return _hashNotExists;
144
+ return _md5int64 (utf8.encode (value));
145
+ }
146
+
116
147
/// Predefined hash for files and directories that do not exist.
117
148
///
118
149
/// There are two predefined hash values. The chance that a predefined hash
@@ -135,27 +166,43 @@ class DependenciesHashFile {
135
166
class FileSystemHashes {
136
167
FileSystemHashes ({
137
168
List <FilesystemEntityHash >? files,
138
- }) : files = files ?? [];
169
+ List <EnvironmentVariableHash >? environment,
170
+ }) : files = files ?? [],
171
+ environment = environment ?? [];
139
172
140
173
factory FileSystemHashes .fromJson (Map <String , Object > json) {
141
- final rawEntries = (json[_entitiesKey] as List ).cast <Object >();
174
+ final rawFilesystemEntries =
175
+ (json[_filesystemKey] as List ? )? .cast <Object >() ?? [];
142
176
final files = < FilesystemEntityHash > [
143
- for (final rawEntry in rawEntries )
177
+ for (final rawEntry in rawFilesystemEntries )
144
178
FilesystemEntityHash ._fromJson ((rawEntry as Map ).cast ()),
145
179
];
180
+ final rawEnvironmentEntries =
181
+ (json[_environmentKey] as List ? )? .cast <Object >() ?? [];
182
+ final environment = < EnvironmentVariableHash > [
183
+ for (final rawEntry in rawEnvironmentEntries)
184
+ EnvironmentVariableHash ._fromJson ((rawEntry as Map ).cast ()),
185
+ ];
146
186
return FileSystemHashes (
147
187
files: files,
188
+ environment: environment,
148
189
);
149
190
}
150
191
151
192
final List <FilesystemEntityHash > files;
193
+ final List <EnvironmentVariableHash > environment;
152
194
153
- static const _entitiesKey = 'entities' ;
195
+ static const _filesystemKey = 'file_system' ;
196
+
197
+ static const _environmentKey = 'environment' ;
154
198
155
199
Map <String , Object > toJson () => < String , Object > {
156
- _entitiesKey : < Object > [
200
+ _filesystemKey : < Object > [
157
201
for (final FilesystemEntityHash file in files) file.toJson (),
158
202
],
203
+ _environmentKey: < Object > [
204
+ for (final EnvironmentVariableHash env in environment) env.toJson (),
205
+ ],
159
206
};
160
207
}
161
208
@@ -190,6 +237,32 @@ class FilesystemEntityHash {
190
237
};
191
238
}
192
239
240
+ class EnvironmentVariableHash {
241
+ EnvironmentVariableHash (
242
+ this .key,
243
+ this .hash,
244
+ );
245
+
246
+ factory EnvironmentVariableHash ._fromJson (Map <String , Object > json) =>
247
+ EnvironmentVariableHash (
248
+ json[_keyKey] as String ,
249
+ json[_hashKey] as int ,
250
+ );
251
+
252
+ static const _keyKey = 'key' ;
253
+ static const _hashKey = 'hash' ;
254
+
255
+ final String key;
256
+
257
+ /// A 64 bit hash.
258
+ final int hash;
259
+
260
+ Object toJson () => < String , Object > {
261
+ _keyKey: key,
262
+ _hashKey: hash,
263
+ };
264
+ }
265
+
193
266
bool _isDirectoryPath (String path) =>
194
267
path.endsWith (Platform .pathSeparator) || path.endsWith ('/' );
195
268
0 commit comments