@huozi-ai/git-kit 0.1.0-alpha.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/LICENSE +202 -0
- package/NOTICE +6 -0
- package/dist/commands.d.ts +17 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +62 -0
- package/dist/commands.js.map +1 -0
- package/dist/configure.d.ts +43 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +146 -0
- package/dist/configure.js.map +1 -0
- package/dist/credential.d.ts +40 -0
- package/dist/credential.d.ts.map +1 -0
- package/dist/credential.js +61 -0
- package/dist/credential.js.map +1 -0
- package/dist/git.d.ts +50 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +71 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/lfs/client.d.ts +47 -0
- package/dist/lfs/client.d.ts.map +1 -0
- package/dist/lfs/client.js +216 -0
- package/dist/lfs/client.js.map +1 -0
- package/dist/lfs/filter.d.ts +39 -0
- package/dist/lfs/filter.d.ts.map +1 -0
- package/dist/lfs/filter.js +148 -0
- package/dist/lfs/filter.js.map +1 -0
- package/dist/lfs/pktline.d.ts +33 -0
- package/dist/lfs/pktline.d.ts.map +1 -0
- package/dist/lfs/pktline.js +127 -0
- package/dist/lfs/pktline.js.map +1 -0
- package/dist/lfs/pointer.d.ts +20 -0
- package/dist/lfs/pointer.d.ts.map +1 -0
- package/dist/lfs/pointer.js +56 -0
- package/dist/lfs/pointer.js.map +1 -0
- package/dist/lfs/push.d.ts +20 -0
- package/dist/lfs/push.d.ts.map +1 -0
- package/dist/lfs/push.js +94 -0
- package/dist/lfs/push.js.map +1 -0
- package/dist/lfs/store.d.ts +28 -0
- package/dist/lfs/store.d.ts.map +1 -0
- package/dist/lfs/store.js +98 -0
- package/dist/lfs/store.js.map +1 -0
- package/dist/ops.d.ts +39 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +130 -0
- package/dist/ops.js.map +1 -0
- package/package.json +39 -0
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface GitRunOptions {
|
|
2
|
+
cwd: string;
|
|
3
|
+
input?: string | Buffer;
|
|
4
|
+
/** Extra environment, on top of the current one. */
|
|
5
|
+
env?: NodeJS.ProcessEnv;
|
|
6
|
+
/** Exit codes that are not errors. */
|
|
7
|
+
okCodes?: number[];
|
|
8
|
+
}
|
|
9
|
+
export interface GitResult {
|
|
10
|
+
code: number;
|
|
11
|
+
stdout: Buffer;
|
|
12
|
+
stderr: string;
|
|
13
|
+
}
|
|
14
|
+
export type GitKitErrorCode =
|
|
15
|
+
/** The folder is not a git repository, or has no remote. */
|
|
16
|
+
"not_a_repo"
|
|
17
|
+
/** HEAD is not on a branch. */
|
|
18
|
+
| "detached"
|
|
19
|
+
/** The remote refused the push because of the token's ref rules (for example the production branch). */
|
|
20
|
+
| "push_denied"
|
|
21
|
+
/** The remote has changes we do not have yet: sync first. */
|
|
22
|
+
| "push_rejected"
|
|
23
|
+
/** Both sides changed the same lines; `paths` lists the files. Nothing was changed locally. */
|
|
24
|
+
| "conflict"
|
|
25
|
+
/** Local changes would be overwritten. */
|
|
26
|
+
| "local_changes" | "not_found" | "invalid"
|
|
27
|
+
/** An LFS object is missing, could not be uploaded or downloaded. */
|
|
28
|
+
| "lfs" | "auth" | "git";
|
|
29
|
+
export declare class GitKitError extends Error {
|
|
30
|
+
readonly code: GitKitErrorCode;
|
|
31
|
+
readonly paths: string[];
|
|
32
|
+
constructor(code: GitKitErrorCode, message: string, options?: {
|
|
33
|
+
paths?: string[];
|
|
34
|
+
cause?: unknown;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export declare class GitCommandError extends GitKitError {
|
|
38
|
+
readonly exitCode: number;
|
|
39
|
+
readonly stderr: string;
|
|
40
|
+
constructor(args: string[], exitCode: number, stderr: string);
|
|
41
|
+
}
|
|
42
|
+
/** The environment for git: the user's, without terminal prompts. */
|
|
43
|
+
export declare function gitEnv(extra?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
44
|
+
export declare function runGit(args: string[], options: GitRunOptions): Promise<GitResult>;
|
|
45
|
+
export declare function gitText(args: string[], options: GitRunOptions): Promise<string>;
|
|
46
|
+
/** A git config value, or `undefined` when it is not set. */
|
|
47
|
+
export declare function gitConfig(cwd: string, key: string): Promise<string | undefined>;
|
|
48
|
+
/** Quotes one word for the POSIX shell git uses to run filters, hooks and helpers. */
|
|
49
|
+
export declare function shellQuote(word: string): string;
|
|
50
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe;AACzB,4DAA4D;AAC1D,YAAY;AACd,+BAA+B;GAC7B,UAAU;AACZ,wGAAwG;GACtG,aAAa;AACf,6DAA6D;GAC3D,eAAe;AACjB,+FAA+F;GAC7F,UAAU;AACZ,0CAA0C;GACxC,eAAe,GACf,WAAW,GACX,SAAS;AACX,qEAAqE;GACnE,KAAK,GACL,MAAM,GACN,KAAK,CAAC;AAEV,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;gBAEvB,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO;CAOtD;AAED,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBACZ,IAAI,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQ7D;AAED,qEAAqE;AACrE,wBAAgB,MAAM,CAAC,KAAK,GAAE,MAAM,CAAC,UAAe,GAAG,MAAM,CAAC,UAAU,CAEvE;AAED,wBAAgB,MAAM,CACpB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,SAAS,CAAC,CA2BpB;AAED,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,6DAA6D;AAC7D,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAM7B;AAED,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C"}
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
export class GitKitError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
paths;
|
|
5
|
+
constructor(code, message, options = {}) {
|
|
6
|
+
super(message, { cause: options.cause });
|
|
7
|
+
this.name = "GitKitError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.paths = options.paths ?? [];
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class GitCommandError extends GitKitError {
|
|
13
|
+
exitCode;
|
|
14
|
+
stderr;
|
|
15
|
+
constructor(args, exitCode, stderr) {
|
|
16
|
+
super("git", `git ${args.join(" ")} failed (${String(exitCode)}): ${stderr.trim()}`);
|
|
17
|
+
this.exitCode = exitCode;
|
|
18
|
+
this.stderr = stderr;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** The environment for git: the user's, without terminal prompts. */
|
|
22
|
+
export function gitEnv(extra = {}) {
|
|
23
|
+
return { ...process.env, GIT_TERMINAL_PROMPT: "0", ...extra };
|
|
24
|
+
}
|
|
25
|
+
export function runGit(args, options) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const child = spawn("git", args, {
|
|
28
|
+
cwd: options.cwd,
|
|
29
|
+
env: gitEnv(options.env),
|
|
30
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
31
|
+
});
|
|
32
|
+
const out = [];
|
|
33
|
+
const err = [];
|
|
34
|
+
child.stdout.on("data", (chunk) => out.push(chunk));
|
|
35
|
+
child.stderr.on("data", (chunk) => err.push(chunk));
|
|
36
|
+
child.on("error", reject);
|
|
37
|
+
child.on("close", (code) => {
|
|
38
|
+
const result = {
|
|
39
|
+
code: code ?? -1,
|
|
40
|
+
stdout: Buffer.concat(out),
|
|
41
|
+
stderr: Buffer.concat(err).toString("utf8"),
|
|
42
|
+
};
|
|
43
|
+
if (result.code === 0 || options.okCodes?.includes(result.code))
|
|
44
|
+
resolve(result);
|
|
45
|
+
else
|
|
46
|
+
reject(new GitCommandError(args, result.code, result.stderr));
|
|
47
|
+
});
|
|
48
|
+
child.stdin.on("error", () => {
|
|
49
|
+
// git may exit before reading its input; the exit code says why.
|
|
50
|
+
});
|
|
51
|
+
child.stdin.end(options.input);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export async function gitText(args, options) {
|
|
55
|
+
return (await runGit(args, options)).stdout.toString("utf8").trim();
|
|
56
|
+
}
|
|
57
|
+
/** A git config value, or `undefined` when it is not set. */
|
|
58
|
+
export async function gitConfig(cwd, key) {
|
|
59
|
+
const { code, stdout } = await runGit(["config", "--get", key], {
|
|
60
|
+
cwd,
|
|
61
|
+
okCodes: [1],
|
|
62
|
+
});
|
|
63
|
+
return code === 0 ? stdout.toString("utf8").trim() : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** Quotes one word for the POSIX shell git uses to run filters, hooks and helpers. */
|
|
66
|
+
export function shellQuote(word) {
|
|
67
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(word))
|
|
68
|
+
return word;
|
|
69
|
+
return `'${word.replace(/'/g, `'\\''`)}'`;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { gitConfig, GitCommandError, GitKitError, runGit, shellQuote, } from "./git.js";
|
|
2
|
+
export type { GitResult, GitRunOptions } from "./git.js";
|
|
3
|
+
export type { GitKitErrorCode } from "./git.js";
|
|
4
|
+
export { credentialHelper, formatCredential, parseCredentialInput, repoFromPath, } from "./credential.js";
|
|
5
|
+
export type { Credential, CredentialProvider, CredentialRequest, } from "./credential.js";
|
|
6
|
+
export { formatPointer, MAX_POINTER_SIZE, parsePointer, POINTER_VERSION, } from "./lfs/pointer.js";
|
|
7
|
+
export type { LfsPointer } from "./lfs/pointer.js";
|
|
8
|
+
export { LocalObjects } from "./lfs/store.js";
|
|
9
|
+
export { endpointFromRemote, LfsClient, lfsEndpoint } from "./lfs/client.js";
|
|
10
|
+
export { cleanFile, filterProcess, LfsFilter, smudgeFile, } from "./lfs/filter.js";
|
|
11
|
+
export { parsePrePushInput, pointersBetween, prePush } from "./lfs/push.js";
|
|
12
|
+
export { commandLine, configureRepo, ensureGitattributes, MEDIA_EXTENSIONS, mediaAttributes, } from "./configure.js";
|
|
13
|
+
export type { ConfigureOptions, ConfigureResult, GitKitCommand, } from "./configure.js";
|
|
14
|
+
export { processIO, runCredentialCommand, runLfsCommand } from "./commands.js";
|
|
15
|
+
export type { CommandIO } from "./commands.js";
|
|
16
|
+
export { clone, currentBranch, save, uploadMedia } from "./ops.js";
|
|
17
|
+
export type { Identity, SaveResult } from "./ops.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,eAAe,EACf,WAAW,EACX,MAAM,EACN,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,GACb,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,UAAU,EACV,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EACL,SAAS,EACT,aAAa,EACb,SAAS,EACT,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EACL,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC/E,YAAY,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { gitConfig, GitCommandError, GitKitError, runGit, shellQuote, } from "./git.js";
|
|
2
|
+
export { credentialHelper, formatCredential, parseCredentialInput, repoFromPath, } from "./credential.js";
|
|
3
|
+
export { formatPointer, MAX_POINTER_SIZE, parsePointer, POINTER_VERSION, } from "./lfs/pointer.js";
|
|
4
|
+
export { LocalObjects } from "./lfs/store.js";
|
|
5
|
+
export { endpointFromRemote, LfsClient, lfsEndpoint } from "./lfs/client.js";
|
|
6
|
+
export { cleanFile, filterProcess, LfsFilter, smudgeFile, } from "./lfs/filter.js";
|
|
7
|
+
export { parsePrePushInput, pointersBetween, prePush } from "./lfs/push.js";
|
|
8
|
+
export { commandLine, configureRepo, ensureGitattributes, MEDIA_EXTENSIONS, mediaAttributes, } from "./configure.js";
|
|
9
|
+
export { processIO, runCredentialCommand, runLfsCommand } from "./commands.js";
|
|
10
|
+
export { clone, currentBranch, save, uploadMedia } from "./ops.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,eAAe,EACf,WAAW,EACX,MAAM,EACN,UAAU,GACX,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,GACb,MAAM,iBAAiB,CAAC;AAMzB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,OAAO,EACL,SAAS,EACT,aAAa,EACb,SAAS,EACT,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EACL,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAMxB,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { LfsPointer } from "./pointer.js";
|
|
2
|
+
import type { LocalObjects } from "./store.js";
|
|
3
|
+
/** `https://host/ws_1.git` → `https://host/ws_1.git/info/lfs` (the git-lfs default for a remote). */
|
|
4
|
+
export declare function endpointFromRemote(remoteUrl: string): string;
|
|
5
|
+
/** The LFS endpoint: `lfs.url`, else derived from the remote's URL. */
|
|
6
|
+
export declare function lfsEndpoint(cwd: string, remote?: string): Promise<string>;
|
|
7
|
+
interface Action {
|
|
8
|
+
href: string;
|
|
9
|
+
header?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
interface BatchObject {
|
|
12
|
+
oid: string;
|
|
13
|
+
size: number;
|
|
14
|
+
error?: {
|
|
15
|
+
code: number;
|
|
16
|
+
message?: string;
|
|
17
|
+
};
|
|
18
|
+
actions?: {
|
|
19
|
+
download?: Action;
|
|
20
|
+
upload?: Action;
|
|
21
|
+
verify?: Action;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A Git LFS batch API client (https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md),
|
|
26
|
+
* basic transfers only. Credentials come from `git credential fill`, so the same helper that
|
|
27
|
+
* serves git (our CLI) serves LFS, and the token never appears in config or URLs.
|
|
28
|
+
*/
|
|
29
|
+
export declare class LfsClient {
|
|
30
|
+
private readonly cwd;
|
|
31
|
+
private readonly endpoint;
|
|
32
|
+
private readonly objects;
|
|
33
|
+
private credential;
|
|
34
|
+
constructor(cwd: string, endpoint: string, objects: LocalObjects);
|
|
35
|
+
private credentialInput;
|
|
36
|
+
private authorization;
|
|
37
|
+
/** Tells git whether the credential worked, so helpers can cache or forget it. */
|
|
38
|
+
private report;
|
|
39
|
+
batch(operation: "download" | "upload", objects: LfsPointer[]): Promise<BatchObject[]>;
|
|
40
|
+
/** Downloads objects into the local store, checking each sha256. */
|
|
41
|
+
download(pointers: LfsPointer[]): Promise<void>;
|
|
42
|
+
private fetchInto;
|
|
43
|
+
/** Uploads the objects the server does not have yet. Returns how many were sent. */
|
|
44
|
+
upload(pointers: LfsPointer[]): Promise<number>;
|
|
45
|
+
}
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lfs/client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,uEAAuE;AACvE,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,MAAM,SAAW,GAChB,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,UAAU,WAAW;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE;AAiBD;;;;GAIG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,UAAU,CAAqC;gBAE3C,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAMhE,OAAO,CAAC,eAAe;YAQT,aAAa;IAuB3B,kFAAkF;YACpE,MAAM;IAWd,KAAK,CACT,SAAS,EAAE,UAAU,GAAG,QAAQ,EAChC,OAAO,EAAE,UAAU,EAAE,GACpB,OAAO,CAAC,WAAW,EAAE,CAAC;IAqCzB,oEAAoE;IAC9D,QAAQ,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAmBvC,SAAS;IAuCvB,oFAAoF;IAC9E,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CA2DtD"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { openAsBlob } from "node:fs";
|
|
3
|
+
import { mkdir, open, rename, rm } from "node:fs/promises";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { gitConfig, GitKitError, runGit } from "../git.js";
|
|
7
|
+
const LFS_TYPE = "application/vnd.git-lfs+json";
|
|
8
|
+
/** Transfers at the same time. */
|
|
9
|
+
const CONCURRENCY = 4;
|
|
10
|
+
/** `https://host/ws_1.git` → `https://host/ws_1.git/info/lfs` (the git-lfs default for a remote). */
|
|
11
|
+
export function endpointFromRemote(remoteUrl) {
|
|
12
|
+
const url = remoteUrl.replace(/\/+$/, "");
|
|
13
|
+
return url.endsWith(".git") ? `${url}/info/lfs` : `${url}.git/info/lfs`;
|
|
14
|
+
}
|
|
15
|
+
/** The LFS endpoint: `lfs.url`, else derived from the remote's URL. */
|
|
16
|
+
export async function lfsEndpoint(cwd, remote = "origin") {
|
|
17
|
+
const configured = await gitConfig(cwd, "lfs.url");
|
|
18
|
+
if (configured)
|
|
19
|
+
return configured.replace(/\/+$/, "");
|
|
20
|
+
const remoteUrl = /^[a-z][a-z0-9+.-]*:\/\//i.test(remote)
|
|
21
|
+
? remote
|
|
22
|
+
: await gitConfig(cwd, `remote.${remote}.url`);
|
|
23
|
+
if (!remoteUrl)
|
|
24
|
+
throw new GitKitError("not_a_repo", `No URL for remote ${remote}; set lfs.url`);
|
|
25
|
+
return endpointFromRemote(remoteUrl);
|
|
26
|
+
}
|
|
27
|
+
async function inBatches(items, run) {
|
|
28
|
+
const queue = [...items];
|
|
29
|
+
const workers = Array.from({ length: Math.min(CONCURRENCY, queue.length) }, async () => {
|
|
30
|
+
for (let item = queue.shift(); item !== undefined; item = queue.shift())
|
|
31
|
+
await run(item);
|
|
32
|
+
});
|
|
33
|
+
await Promise.all(workers);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A Git LFS batch API client (https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md),
|
|
37
|
+
* basic transfers only. Credentials come from `git credential fill`, so the same helper that
|
|
38
|
+
* serves git (our CLI) serves LFS, and the token never appears in config or URLs.
|
|
39
|
+
*/
|
|
40
|
+
export class LfsClient {
|
|
41
|
+
cwd;
|
|
42
|
+
endpoint;
|
|
43
|
+
objects;
|
|
44
|
+
credential;
|
|
45
|
+
constructor(cwd, endpoint, objects) {
|
|
46
|
+
this.cwd = cwd;
|
|
47
|
+
this.endpoint = endpoint;
|
|
48
|
+
this.objects = objects;
|
|
49
|
+
}
|
|
50
|
+
credentialInput(extra = {}) {
|
|
51
|
+
const lines = [
|
|
52
|
+
`url=${this.endpoint}`,
|
|
53
|
+
...Object.entries(extra).map(([k, v]) => `${k}=${v}`),
|
|
54
|
+
];
|
|
55
|
+
return `${lines.join("\n")}\n\n`;
|
|
56
|
+
}
|
|
57
|
+
async authorization() {
|
|
58
|
+
if (!this.credential) {
|
|
59
|
+
const { code, stdout, stderr } = await runGit(["credential", "fill"], {
|
|
60
|
+
cwd: this.cwd,
|
|
61
|
+
input: this.credentialInput(),
|
|
62
|
+
okCodes: [128],
|
|
63
|
+
});
|
|
64
|
+
if (code !== 0)
|
|
65
|
+
throw new GitKitError("auth", `No credentials for ${this.endpoint}: ${stderr.trim()}`);
|
|
66
|
+
const values = {};
|
|
67
|
+
for (const line of stdout.toString("utf8").split("\n")) {
|
|
68
|
+
const eq = line.indexOf("=");
|
|
69
|
+
if (eq > 0)
|
|
70
|
+
values[line.slice(0, eq)] = line.slice(eq + 1);
|
|
71
|
+
}
|
|
72
|
+
this.credential = values;
|
|
73
|
+
}
|
|
74
|
+
const { username = "", password = "" } = this.credential;
|
|
75
|
+
return `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
|
|
76
|
+
}
|
|
77
|
+
/** Tells git whether the credential worked, so helpers can cache or forget it. */
|
|
78
|
+
async report(ok) {
|
|
79
|
+
if (!this.credential)
|
|
80
|
+
return;
|
|
81
|
+
const { username = "", password = "" } = this.credential;
|
|
82
|
+
await runGit(["credential", ok ? "approve" : "reject"], {
|
|
83
|
+
cwd: this.cwd,
|
|
84
|
+
input: this.credentialInput({ username, password }),
|
|
85
|
+
okCodes: [128],
|
|
86
|
+
});
|
|
87
|
+
if (!ok)
|
|
88
|
+
this.credential = undefined;
|
|
89
|
+
}
|
|
90
|
+
async batch(operation, objects) {
|
|
91
|
+
if (objects.length === 0)
|
|
92
|
+
return [];
|
|
93
|
+
const body = JSON.stringify({
|
|
94
|
+
operation,
|
|
95
|
+
transfers: ["basic"],
|
|
96
|
+
objects: objects.map(({ oid, size }) => ({ oid, size })),
|
|
97
|
+
hash_algo: "sha256",
|
|
98
|
+
});
|
|
99
|
+
for (let attempt = 0;; attempt++) {
|
|
100
|
+
const res = await fetch(`${this.endpoint}/objects/batch`, {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: {
|
|
103
|
+
Accept: LFS_TYPE,
|
|
104
|
+
"Content-Type": LFS_TYPE,
|
|
105
|
+
Authorization: await this.authorization(),
|
|
106
|
+
},
|
|
107
|
+
body,
|
|
108
|
+
});
|
|
109
|
+
if (res.status === 401 && attempt === 0) {
|
|
110
|
+
await res.arrayBuffer();
|
|
111
|
+
await this.report(false);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (!res.ok) {
|
|
115
|
+
const text = await res.text();
|
|
116
|
+
await this.report(false);
|
|
117
|
+
throw new GitKitError(res.status === 401 || res.status === 403 ? "auth" : "lfs", `LFS ${operation} refused (${String(res.status)}): ${text}`);
|
|
118
|
+
}
|
|
119
|
+
await this.report(true);
|
|
120
|
+
const data = (await res.json());
|
|
121
|
+
return data.objects ?? [];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Downloads objects into the local store, checking each sha256. */
|
|
125
|
+
async download(pointers) {
|
|
126
|
+
const wanted = [];
|
|
127
|
+
for (const p of pointers)
|
|
128
|
+
if (!(await this.objects.has(p.oid, p.size)))
|
|
129
|
+
wanted.push(p);
|
|
130
|
+
const answers = await this.batch("download", wanted);
|
|
131
|
+
await inBatches(answers, async (object) => {
|
|
132
|
+
if (object.error) {
|
|
133
|
+
throw new GitKitError("lfs", `LFS object ${object.oid} is not on the server: ${object.error.message ?? String(object.error.code)}`);
|
|
134
|
+
}
|
|
135
|
+
const link = object.actions?.download;
|
|
136
|
+
if (!link)
|
|
137
|
+
throw new GitKitError("lfs", `No download link for ${object.oid}`);
|
|
138
|
+
await this.fetchInto(link, object.oid, object.size);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async fetchInto(link, oid, size) {
|
|
142
|
+
const res = await fetch(link.href, { headers: link.header ?? {} });
|
|
143
|
+
if (!res.ok || !res.body)
|
|
144
|
+
throw new GitKitError("lfs", `Downloading ${oid} failed (${String(res.status)})`);
|
|
145
|
+
const tmp = await this.objects.tempFile();
|
|
146
|
+
const hash = createHash("sha256");
|
|
147
|
+
let seen = 0;
|
|
148
|
+
const handle = await open(tmp, "w");
|
|
149
|
+
try {
|
|
150
|
+
for await (const chunk of Readable.fromWeb(res.body)) {
|
|
151
|
+
hash.update(chunk);
|
|
152
|
+
seen += chunk.length;
|
|
153
|
+
await handle.write(chunk);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await handle.close();
|
|
158
|
+
}
|
|
159
|
+
const digest = hash.digest("hex");
|
|
160
|
+
if (digest !== oid || seen !== size) {
|
|
161
|
+
await rm(tmp, { force: true });
|
|
162
|
+
throw new GitKitError("lfs", `Downloaded ${oid} but got ${digest} (${String(seen)} bytes)`);
|
|
163
|
+
}
|
|
164
|
+
const target = this.objects.path(oid);
|
|
165
|
+
await mkdir(dirname(target), { recursive: true });
|
|
166
|
+
await rename(tmp, target);
|
|
167
|
+
}
|
|
168
|
+
/** Uploads the objects the server does not have yet. Returns how many were sent. */
|
|
169
|
+
async upload(pointers) {
|
|
170
|
+
const answers = await this.batch("upload", pointers);
|
|
171
|
+
for (const object of answers) {
|
|
172
|
+
if (object.actions?.upload &&
|
|
173
|
+
!(await this.objects.has(object.oid, object.size))) {
|
|
174
|
+
throw new GitKitError("lfs", `LFS object ${object.oid} is missing here and on the server`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
let sent = 0;
|
|
178
|
+
await inBatches(answers, async (object) => {
|
|
179
|
+
if (object.error)
|
|
180
|
+
throw new GitKitError("lfs", `Server refused ${object.oid}: ${object.error.message ?? String(object.error.code)}`);
|
|
181
|
+
const upload = object.actions?.upload;
|
|
182
|
+
if (!upload)
|
|
183
|
+
return;
|
|
184
|
+
const blob = await openAsBlob(this.objects.path(object.oid));
|
|
185
|
+
const put = await fetch(upload.href, {
|
|
186
|
+
method: "PUT",
|
|
187
|
+
headers: {
|
|
188
|
+
"Content-Type": "application/octet-stream",
|
|
189
|
+
...(upload.header ?? {}),
|
|
190
|
+
},
|
|
191
|
+
body: blob,
|
|
192
|
+
});
|
|
193
|
+
await put.arrayBuffer();
|
|
194
|
+
if (!put.ok)
|
|
195
|
+
throw new GitKitError("lfs", `Uploading ${object.oid} failed (${String(put.status)})`);
|
|
196
|
+
const verify = object.actions?.verify;
|
|
197
|
+
if (verify) {
|
|
198
|
+
const res = await fetch(verify.href, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: {
|
|
201
|
+
Accept: LFS_TYPE,
|
|
202
|
+
"Content-Type": LFS_TYPE,
|
|
203
|
+
...(verify.header ?? {}),
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify({ oid: object.oid, size: object.size }),
|
|
206
|
+
});
|
|
207
|
+
await res.arrayBuffer();
|
|
208
|
+
if (!res.ok)
|
|
209
|
+
throw new GitKitError("lfs", `The server could not verify ${object.oid} (${String(res.status)})`);
|
|
210
|
+
}
|
|
211
|
+
sent++;
|
|
212
|
+
});
|
|
213
|
+
return sent;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lfs/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Writable } from "node:stream";
|
|
2
|
+
import { LfsClient } from "./client.js";
|
|
3
|
+
import { LocalObjects } from "./store.js";
|
|
4
|
+
/** Where content goes: one call per chunk, awaited for backpressure. */
|
|
5
|
+
export type Sink = (chunk: Buffer) => Promise<void>;
|
|
6
|
+
export declare function sinkFor(out: Writable): Sink;
|
|
7
|
+
/** A filter's answer, ready to be written once we know the filter succeeded. */
|
|
8
|
+
export interface Answer {
|
|
9
|
+
write(sink: Sink): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/** State shared by the files of one filter run: the store and a lazily created LFS client. */
|
|
12
|
+
export declare class LfsFilter {
|
|
13
|
+
private readonly cwd;
|
|
14
|
+
private objectsPromise;
|
|
15
|
+
private clientPromise;
|
|
16
|
+
constructor(cwd: string);
|
|
17
|
+
objects(): Promise<LocalObjects>;
|
|
18
|
+
client(): Promise<LfsClient>;
|
|
19
|
+
/**
|
|
20
|
+
* clean: working-tree content → pointer. The bytes go into the local store; content that is
|
|
21
|
+
* already a pointer passes through unchanged (as git-lfs does).
|
|
22
|
+
*/
|
|
23
|
+
clean(input: AsyncIterable<Buffer | Uint8Array>): Promise<Answer>;
|
|
24
|
+
/**
|
|
25
|
+
* smudge: pointer → content, from the local store or downloaded through the batch API. Content
|
|
26
|
+
* that is not a pointer passes through. With `GIT_LFS_SKIP_SMUDGE=1` the pointer stays.
|
|
27
|
+
*/
|
|
28
|
+
smudge(input: AsyncIterable<Buffer | Uint8Array>): Promise<Answer>;
|
|
29
|
+
}
|
|
30
|
+
/** Single-file `clean` (`filter.lfs.clean`): stdin → stdout. */
|
|
31
|
+
export declare function cleanFile(cwd: string, input: AsyncIterable<Buffer | Uint8Array>, output: Writable): Promise<void>;
|
|
32
|
+
/** Single-file `smudge` (`filter.lfs.smudge`): stdin → stdout. */
|
|
33
|
+
export declare function smudgeFile(cwd: string, input: AsyncIterable<Buffer | Uint8Array>, output: Writable): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* git's long-running filter protocol (`filter.lfs.process`, see gitattributes(5)): one process per
|
|
36
|
+
* git command handles every file, which is much faster than one process per file.
|
|
37
|
+
*/
|
|
38
|
+
export declare function filterProcess(cwd: string, input: AsyncIterable<Buffer | Uint8Array>, output: Writable, log?: (message: string) => void): Promise<void>;
|
|
39
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/lfs/filter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAe,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAgB,MAAM,YAAY,CAAC;AAExD,wEAAwE;AACxE,MAAM,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEpD,wBAAgB,OAAO,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAW3C;AAED,gFAAgF;AAChF,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClC;AAwBD,8FAA8F;AAC9F,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAoC;IAC1D,OAAO,CAAC,aAAa,CAAiC;gBAE1C,GAAG,EAAE,MAAM;IAIvB,OAAO,IAAI,OAAO,CAAC,YAAY,CAAC;IAKhC,MAAM,IAAI,OAAO,CAAC,SAAS,CAAC;IAU5B;;;OAGG;IACG,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAavE;;;OAGG;IACG,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAUzE;AAED,gEAAgE;AAChE,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,UAAU,CAAC,EACzC,MAAM,EAAE,QAAQ,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,kEAAkE;AAClE,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,UAAU,CAAC,EACzC,MAAM,EAAE,QAAQ,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,aAAa,CAAC,MAAM,GAAG,UAAU,CAAC,EACzC,MAAM,EAAE,QAAQ,EAChB,GAAG,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAA4C,GACrE,OAAO,CAAC,IAAI,CAAC,CAwDf"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createReadStream } from "node:fs";
|
|
2
|
+
import { LfsClient, lfsEndpoint } from "./client.js";
|
|
3
|
+
import { PktReader, PktWriter } from "./pktline.js";
|
|
4
|
+
import { formatPointer, parsePointer } from "./pointer.js";
|
|
5
|
+
import { LocalObjects } from "./store.js";
|
|
6
|
+
export function sinkFor(out) {
|
|
7
|
+
return (chunk) => new Promise((resolve, reject) => {
|
|
8
|
+
if (out.write(chunk, (error) => {
|
|
9
|
+
if (error)
|
|
10
|
+
reject(error);
|
|
11
|
+
}))
|
|
12
|
+
resolve();
|
|
13
|
+
else
|
|
14
|
+
out.once("drain", resolve);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function bytes(data) {
|
|
18
|
+
return { write: (sink) => sink(data) };
|
|
19
|
+
}
|
|
20
|
+
function file(path, after) {
|
|
21
|
+
return {
|
|
22
|
+
async write(sink) {
|
|
23
|
+
try {
|
|
24
|
+
for await (const chunk of createReadStream(path))
|
|
25
|
+
await sink(chunk);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await after?.();
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function spooledAnswer(objects, spooled) {
|
|
34
|
+
if (spooled.file)
|
|
35
|
+
return file(spooled.file, () => objects.discard(spooled));
|
|
36
|
+
return bytes(spooled.small ?? Buffer.alloc(0));
|
|
37
|
+
}
|
|
38
|
+
/** State shared by the files of one filter run: the store and a lazily created LFS client. */
|
|
39
|
+
export class LfsFilter {
|
|
40
|
+
cwd;
|
|
41
|
+
objectsPromise;
|
|
42
|
+
clientPromise;
|
|
43
|
+
constructor(cwd) {
|
|
44
|
+
this.cwd = cwd;
|
|
45
|
+
}
|
|
46
|
+
objects() {
|
|
47
|
+
this.objectsPromise ??= LocalObjects.open(this.cwd);
|
|
48
|
+
return this.objectsPromise;
|
|
49
|
+
}
|
|
50
|
+
client() {
|
|
51
|
+
this.clientPromise ??= (async () => new LfsClient(this.cwd, await lfsEndpoint(this.cwd), await this.objects()))();
|
|
52
|
+
return this.clientPromise;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* clean: working-tree content → pointer. The bytes go into the local store; content that is
|
|
56
|
+
* already a pointer passes through unchanged (as git-lfs does).
|
|
57
|
+
*/
|
|
58
|
+
async clean(input) {
|
|
59
|
+
const objects = await this.objects();
|
|
60
|
+
const spooled = await objects.spool(input);
|
|
61
|
+
if (spooled.small && parsePointer(spooled.small))
|
|
62
|
+
return bytes(spooled.small);
|
|
63
|
+
if (await objects.has(spooled.oid, spooled.size))
|
|
64
|
+
await objects.discard(spooled);
|
|
65
|
+
else
|
|
66
|
+
await objects.adopt(spooled);
|
|
67
|
+
return bytes(Buffer.from(formatPointer({ oid: spooled.oid, size: spooled.size })));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* smudge: pointer → content, from the local store or downloaded through the batch API. Content
|
|
71
|
+
* that is not a pointer passes through. With `GIT_LFS_SKIP_SMUDGE=1` the pointer stays.
|
|
72
|
+
*/
|
|
73
|
+
async smudge(input) {
|
|
74
|
+
const objects = await this.objects();
|
|
75
|
+
const spooled = await objects.spool(input);
|
|
76
|
+
const pointer = spooled.small ? parsePointer(spooled.small) : null;
|
|
77
|
+
if (!pointer || process.env["GIT_LFS_SKIP_SMUDGE"] === "1")
|
|
78
|
+
return spooledAnswer(objects, spooled);
|
|
79
|
+
if (!(await objects.has(pointer.oid, pointer.size)))
|
|
80
|
+
await (await this.client()).download([pointer]);
|
|
81
|
+
return file(objects.path(pointer.oid));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Single-file `clean` (`filter.lfs.clean`): stdin → stdout. */
|
|
85
|
+
export async function cleanFile(cwd, input, output) {
|
|
86
|
+
await (await new LfsFilter(cwd).clean(input)).write(sinkFor(output));
|
|
87
|
+
}
|
|
88
|
+
/** Single-file `smudge` (`filter.lfs.smudge`): stdin → stdout. */
|
|
89
|
+
export async function smudgeFile(cwd, input, output) {
|
|
90
|
+
await (await new LfsFilter(cwd).smudge(input)).write(sinkFor(output));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* git's long-running filter protocol (`filter.lfs.process`, see gitattributes(5)): one process per
|
|
94
|
+
* git command handles every file, which is much faster than one process per file.
|
|
95
|
+
*/
|
|
96
|
+
export async function filterProcess(cwd, input, output, log = (m) => process.stderr.write(`${m}\n`)) {
|
|
97
|
+
const reader = new PktReader(input);
|
|
98
|
+
const writer = new PktWriter(output);
|
|
99
|
+
const hello = await reader.readList();
|
|
100
|
+
if (!hello?.includes("git-filter-client") || !hello.includes("version=2")) {
|
|
101
|
+
throw new Error("Expected git-filter-client version 2");
|
|
102
|
+
}
|
|
103
|
+
await writer.list(["git-filter-server", "version=2"]);
|
|
104
|
+
const offered = (await reader.readList()) ?? [];
|
|
105
|
+
await writer.list(["capability=clean", "capability=smudge"].filter((c) => offered.includes(c)));
|
|
106
|
+
const filter = new LfsFilter(cwd);
|
|
107
|
+
for (;;) {
|
|
108
|
+
const headers = await reader.readList();
|
|
109
|
+
if (headers === undefined)
|
|
110
|
+
return;
|
|
111
|
+
const fields = new Map(headers.map((h) => [
|
|
112
|
+
h.slice(0, h.indexOf("=")),
|
|
113
|
+
h.slice(h.indexOf("=") + 1),
|
|
114
|
+
]));
|
|
115
|
+
const command = fields.get("command") ?? "";
|
|
116
|
+
const pathname = fields.get("pathname") ?? "";
|
|
117
|
+
const content = reader.readContent();
|
|
118
|
+
let answer;
|
|
119
|
+
try {
|
|
120
|
+
if (command === "clean")
|
|
121
|
+
answer = await filter.clean(content);
|
|
122
|
+
else if (command === "smudge")
|
|
123
|
+
answer = await filter.smudge(content);
|
|
124
|
+
else
|
|
125
|
+
throw new Error(`Unknown filter command: ${command}`);
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
for await (const _ of content) {
|
|
129
|
+
// Skip what is left of this file before answering.
|
|
130
|
+
}
|
|
131
|
+
log(`huozi lfs ${command} ${pathname}: ${error instanceof Error ? error.message : String(error)}`);
|
|
132
|
+
await writer.list(["status=error"]);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
await writer.list(["status=success"]);
|
|
136
|
+
try {
|
|
137
|
+
await answer.write((chunk) => writer.packet(chunk));
|
|
138
|
+
await writer.flush();
|
|
139
|
+
await writer.flush(); // Status unchanged: success.
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
log(`huozi lfs ${command} ${pathname}: ${error instanceof Error ? error.message : String(error)}`);
|
|
143
|
+
await writer.flush();
|
|
144
|
+
await writer.list(["status=error"]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=filter.js.map
|