зеркало из https://github.com/microsoft/rushstack.git
[package-deps-hash] Expose `hashFilesAsync` API (#4934)
* [package-deps-hash] Expose `hashFilesAsync` API * Update comments * rush change * Expose from index --------- Co-authored-by: David Michon <dmichon-msft@users.noreply.github.com>
This commit is contained in:
Родитель
23ed83a75b
Коммит
d7b6ad074e
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"changes": [
|
||||
{
|
||||
"packageName": "@rushstack/package-deps-hash",
|
||||
"comment": "Expose `hashFilesAsync` API. This serves a similar role as `getGitHashForFiles` but is asynchronous and allows for the file names to be provided as an async iterable.",
|
||||
"type": "minor"
|
||||
}
|
||||
],
|
||||
"packageName": "@rushstack/package-deps-hash"
|
||||
}
|
|
@ -22,6 +22,9 @@ export function getRepoRoot(currentWorkingDirectory: string, gitPath?: string):
|
|||
// @beta
|
||||
export function getRepoStateAsync(rootDirectory: string, additionalRelativePathsToHash?: string[], gitPath?: string): Promise<Map<string, string>>;
|
||||
|
||||
// @beta
|
||||
export function hashFilesAsync(rootDirectory: string, filesToHash: Iterable<string> | AsyncIterable<string>, gitPath?: string): Promise<Iterable<[string, string]>>;
|
||||
|
||||
// @beta
|
||||
export interface IFileDiffStatus {
|
||||
// (undocumented)
|
||||
|
|
|
@ -298,6 +298,61 @@ async function spawnGitAsync(
|
|||
return stdout;
|
||||
}
|
||||
|
||||
function isIterable<T>(value: Iterable<T> | AsyncIterable<T>): value is Iterable<T> {
|
||||
return Symbol.iterator in value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses `git hash-object` to hash the provided files. Unlike `getGitHashForFiles`, this API is asynchronous, and also allows for
|
||||
* the input file paths to be specified as an async iterable.
|
||||
*
|
||||
* @param rootDirectory - The root directory to which paths are specified relative. Must be the root of the Git repository.
|
||||
* @param filesToHash - The file paths to hash using `git hash-object`
|
||||
* @param gitPath - The path to the Git executable
|
||||
* @returns An iterable of [filePath, hash] pairs
|
||||
*
|
||||
* @remarks
|
||||
* The input file paths must be specified relative to the Git repository root, or else be absolute paths.
|
||||
* @beta
|
||||
*/
|
||||
export async function hashFilesAsync(
|
||||
rootDirectory: string,
|
||||
filesToHash: Iterable<string> | AsyncIterable<string>,
|
||||
gitPath?: string
|
||||
): Promise<Iterable<[string, string]>> {
|
||||
const hashPaths: string[] = [];
|
||||
|
||||
const input: Readable = Readable.from(
|
||||
isIterable(filesToHash)
|
||||
? (function* (): IterableIterator<string> {
|
||||
for (const file of filesToHash) {
|
||||
hashPaths.push(file);
|
||||
yield `${file}\n`;
|
||||
}
|
||||
})()
|
||||
: (async function* (): AsyncIterableIterator<string> {
|
||||
for await (const file of filesToHash) {
|
||||
hashPaths.push(file);
|
||||
yield `${file}\n`;
|
||||
}
|
||||
})(),
|
||||
{
|
||||
encoding: 'utf-8',
|
||||
objectMode: false,
|
||||
autoDestroy: true
|
||||
}
|
||||
);
|
||||
|
||||
const hashObjectResult: string = await spawnGitAsync(
|
||||
gitPath,
|
||||
STANDARD_GIT_OPTIONS.concat(['hash-object', '--stdin-paths']),
|
||||
rootDirectory,
|
||||
input
|
||||
);
|
||||
|
||||
return parseGitHashObject(hashObjectResult, hashPaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object hashes for all files in the Git repo, combining the current commit with working tree state.
|
||||
* Uses async operations and runs all primary Git calls in parallel.
|
||||
|
@ -346,12 +401,10 @@ export async function getRepoStateAsync(
|
|||
rootDirectory
|
||||
).then(parseGitStatus);
|
||||
|
||||
const hashPaths: string[] = [];
|
||||
async function* getFilesToHash(): AsyncIterableIterator<string> {
|
||||
if (additionalRelativePathsToHash) {
|
||||
for (const file of additionalRelativePathsToHash) {
|
||||
hashPaths.push(file);
|
||||
yield `${file}\n`;
|
||||
yield file;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,33 +412,23 @@ export async function getRepoStateAsync(
|
|||
|
||||
for (const [filePath, exists] of locallyModified) {
|
||||
if (exists) {
|
||||
hashPaths.push(filePath);
|
||||
yield `${filePath}\n`;
|
||||
yield filePath;
|
||||
} else {
|
||||
files.delete(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const hashObjectPromise: Promise<string> = spawnGitAsync(
|
||||
gitPath,
|
||||
STANDARD_GIT_OPTIONS.concat(['hash-object', '--stdin-paths']),
|
||||
const hashObjectPromise: Promise<Iterable<[string, string]>> = hashFilesAsync(
|
||||
rootDirectory,
|
||||
Readable.from(getFilesToHash(), {
|
||||
encoding: 'utf-8',
|
||||
objectMode: false,
|
||||
autoDestroy: true
|
||||
})
|
||||
getFilesToHash(),
|
||||
gitPath
|
||||
);
|
||||
|
||||
const [{ files, submodules }, hashObject] = await Promise.all([
|
||||
statePromise,
|
||||
hashObjectPromise,
|
||||
locallyModifiedPromise
|
||||
]);
|
||||
const [{ files, submodules }] = await Promise.all([statePromise, locallyModifiedPromise]);
|
||||
|
||||
// The result of "git hash-object" will be a list of file hashes delimited by newlines
|
||||
for (const [filePath, hash] of parseGitHashObject(hashObject, hashPaths)) {
|
||||
for (const [filePath, hash] of await hashObjectPromise) {
|
||||
files.set(filePath, hash);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,5 +19,6 @@ export {
|
|||
getRepoChanges,
|
||||
getRepoRoot,
|
||||
getRepoStateAsync,
|
||||
ensureGitMinimumVersion
|
||||
ensureGitMinimumVersion,
|
||||
hashFilesAsync
|
||||
} from './getRepoState';
|
||||
|
|
Загрузка…
Ссылка в новой задаче