git-span 1.0.131
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/README.md +16 -0
- package/bin/git-span.exe +6 -0
- package/man/git-span.1 +172 -0
- package/package.json +37 -0
- package/scripts/postinstall.js +144 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# git span
|
|
2
|
+
|
|
3
|
+
`git span` tracks implicit semantic dependencies in a git repository — line-range or whole-file anchors that participate in a coupling no schema, type, or test enforces. Each span names its anchors, optionally carries a `why` sentence defining the subsystem they collectively form (recommended on every span), and surfaces drift via `git span stale` when those anchors diverge from their anchored state.
|
|
4
|
+
|
|
5
|
+
The primary CLI surface lives in `src/cli/mod.rs`. Run `git span --help` or `git span stale --help` for flag reference.
|
|
6
|
+
|
|
7
|
+
### Upgrading from the sqlite cache
|
|
8
|
+
|
|
9
|
+
The trail cache now lives at `<common_dir>/span/cache/v1/` as a BLAKE3-keyed content-addressed filesystem store. The previous sqlite-backed cache at `<common_dir>/span/cache/span_cache.sqlite` (or `<git_dir>/span/cache/span_cache.sqlite` on older per-worktree installations), along with its `-shm` and `-wal` companions, is unused and can be removed with a single `rm -f <common_dir>/span/cache/span_cache.sqlite*` (and the `<git_dir>` variant if present). Nothing reads those files anymore; `git span doctor --gc-trail-cache` operates only on the new store.
|
|
10
|
+
|
|
11
|
+
## Profiling
|
|
12
|
+
|
|
13
|
+
Perf investigation tooling is documented in [`./docs/profiling.md`](./docs/profiling.md):
|
|
14
|
+
|
|
15
|
+
- **Flame graph capture** — `perf record` + `inferno-flamegraph` recipe for identifying hot functions.
|
|
16
|
+
- **`--perf-trace <path>`** — opt-in per-anchor wall-clock CSV emitter for `git span stale`; CSV schema, usage constraints, and quick analysis snippets are documented there.
|
package/bin/git-span.exe
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
git-span placeholder. scripts/postinstall.js replaces this file
|
|
2
|
+
with the native binary for your platform. The name ends in .exe and the
|
|
3
|
+
first line intentionally has NO "#!" shebang so npm/yarn/pnpm cmd-shim
|
|
4
|
+
generates a direct-exec wrapper that runs on Windows; Unix ignores the
|
|
5
|
+
.exe suffix and execs by mode bit. If you are seeing this text, the
|
|
6
|
+
postinstall step did not run.
|
package/man/git-span.1
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
.ie \n(.g .ds Aq \(aq
|
|
2
|
+
.el .ds Aq '
|
|
3
|
+
.TH git-span 1 "git-span 1.0.131"
|
|
4
|
+
.ie \n(.g .ds Aq \(aq
|
|
5
|
+
.el .ds Aq '
|
|
6
|
+
.SH NAME
|
|
7
|
+
git\-span \- Track implicit semantic dependencies in a git repo.
|
|
8
|
+
.ie \n(.g .ds Aq \(aq
|
|
9
|
+
.el .ds Aq '
|
|
10
|
+
.SH SYNOPSIS
|
|
11
|
+
\fBgit\-span\fR [\fB\-\-perf\fR] [\fB\-\-span\-dir\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] [\fIsubcommands\fR]
|
|
12
|
+
.SH DESCRIPTION
|
|
13
|
+
.B git span
|
|
14
|
+
tracks implicit semantic dependencies in a Git repository: couplings between
|
|
15
|
+
line ranges (or whole files), in code or prose, that no schema, type, or test
|
|
16
|
+
enforces.
|
|
17
|
+
Each
|
|
18
|
+
.B span
|
|
19
|
+
anchors the participating anchors and carries a durable
|
|
20
|
+
.I why
|
|
21
|
+
\[em] one prose sentence that names the relationship the anchored set holds
|
|
22
|
+
and survives a rewrite of either side.
|
|
23
|
+
.PP
|
|
24
|
+
The standing question at commit time: did this change create or rely on a
|
|
25
|
+
coupling that is not visible from the lines themselves?
|
|
26
|
+
.PP
|
|
27
|
+
.B Writing the why.
|
|
28
|
+
Name the relationship the anchors hold in one prose sentence, written so it
|
|
29
|
+
survives a rewrite of either side.
|
|
30
|
+
Describe the relationship in role\-words (\(lqthe doc,\(rq \(lqthe parser,\(rq
|
|
31
|
+
\(lqthe runbook,\(rq \(lqthe migration\(rq) rather than repeating filenames.
|
|
32
|
+
For asymmetric relationships, name which side is normative:
|
|
33
|
+
\(lqthe doc is the source of truth when they disagree.\(rq
|
|
34
|
+
Do not restate the span name, embed incidental implementation details, or
|
|
35
|
+
bundle ownership and review triggers in the why.
|
|
36
|
+
.PP
|
|
37
|
+
.B Re\-anchoring on drift.
|
|
38
|
+
When
|
|
39
|
+
.B git span stale
|
|
40
|
+
reports drift, review the change at each anchor.
|
|
41
|
+
If the relationship still holds, re-anchor with
|
|
42
|
+
.B git span add
|
|
43
|
+
and commit.
|
|
44
|
+
If the relationship has changed, update the why with
|
|
45
|
+
.B git span why
|
|
46
|
+
before re-anchoring.
|
|
47
|
+
.PP
|
|
48
|
+
Each span is an ordinary tracked file under the span root (default
|
|
49
|
+
.IR .span ,
|
|
50
|
+
overridable with
|
|
51
|
+
.BR \-\-span\-dir ,
|
|
52
|
+
the
|
|
53
|
+
.I GIT_SPAN_DIR
|
|
54
|
+
environment variable, or
|
|
55
|
+
.IR "git config git-span.dir" ).
|
|
56
|
+
Spans are versioned, fetched, and pushed exactly like any other
|
|
57
|
+
tracked file \[em] stage and commit edits with
|
|
58
|
+
.B git add .span && git commit
|
|
59
|
+
\&.
|
|
60
|
+
.PP
|
|
61
|
+
Bare invocations:
|
|
62
|
+
.RS 4
|
|
63
|
+
.TP
|
|
64
|
+
.B git span
|
|
65
|
+
List every span in the repository.
|
|
66
|
+
.TP
|
|
67
|
+
.BI git\ span\ <name>
|
|
68
|
+
Show one span (anchors, why, config).
|
|
69
|
+
.RE
|
|
70
|
+
.ie \n(.g .ds Aq \(aq
|
|
71
|
+
.el .ds Aq '
|
|
72
|
+
.SH OPTIONS
|
|
73
|
+
.TP
|
|
74
|
+
\fB\-\-perf\fR
|
|
75
|
+
Emit performance timings for major git\-span operation groups to stderr.
|
|
76
|
+
|
|
77
|
+
Can also be enabled with `GIT_SPAN_PERF=1`.
|
|
78
|
+
.TP
|
|
79
|
+
\fB\-\-span\-dir\fR \fI<SPAN_DIR>\fR
|
|
80
|
+
Span root directory (default: .span). Overrides GIT_SPAN_DIR and git config git\-span.dir
|
|
81
|
+
.TP
|
|
82
|
+
\fB\-h\fR, \fB\-\-help\fR
|
|
83
|
+
Print help (see a summary with \*(Aq\-h\*(Aq)
|
|
84
|
+
.TP
|
|
85
|
+
\fB\-V\fR, \fB\-\-version\fR
|
|
86
|
+
Print version
|
|
87
|
+
.ie \n(.g .ds Aq \(aq
|
|
88
|
+
.el .ds Aq '
|
|
89
|
+
.SH SUBCOMMANDS
|
|
90
|
+
.TP
|
|
91
|
+
git\-span\-show(1)
|
|
92
|
+
Show the named span — its anchors, why, and config. Equivalent to the bare `git span <name>` positional form
|
|
93
|
+
.TP
|
|
94
|
+
git\-span\-list(1)
|
|
95
|
+
List files and anchors currently tracked by a span
|
|
96
|
+
.TP
|
|
97
|
+
git\-span\-stale(1)
|
|
98
|
+
Report anchors whose content has drifted from their anchored state
|
|
99
|
+
.TP
|
|
100
|
+
git\-span\-add(1)
|
|
101
|
+
Add anchors to a span, writing the span file under the span root. Stage and commit the change with `git add .span && git commit`
|
|
102
|
+
.TP
|
|
103
|
+
git\-span\-remove(1)
|
|
104
|
+
Remove anchors from a span, editing the span file under the span root. Stage and commit the change with `git add .span && git commit`
|
|
105
|
+
.TP
|
|
106
|
+
git\-span\-why(1)
|
|
107
|
+
Read or stage the span\*(Aqs why — a one\-sentence definition of the subsystem, flow, or concern the anchors collectively form
|
|
108
|
+
.TP
|
|
109
|
+
git\-span\-delete(1)
|
|
110
|
+
Delete a span
|
|
111
|
+
.TP
|
|
112
|
+
git\-span\-move(1)
|
|
113
|
+
Rename a span
|
|
114
|
+
.TP
|
|
115
|
+
git\-span\-doctor(1)
|
|
116
|
+
Audit the local span setup
|
|
117
|
+
.TP
|
|
118
|
+
git\-span\-tree(1)
|
|
119
|
+
Trace blast radius: render a clique\-grouped impact tree rooted at the files matched by the given paths/globs
|
|
120
|
+
.TP
|
|
121
|
+
git\-span\-merge\-driver(1)
|
|
122
|
+
Resolve `.span/` merge conflicts structurally when invoked by git as a merge driver. Receives three clean blob temp files and the marker length from git. Resolves only what is structurally derivable without trusting the worktree (which may be mid\-merge); defers same\-anchor range/hash divergence by writing minimal conflict markers and exiting non\-zero so `git span stale \-\-fix` can finish authoritatively
|
|
123
|
+
.TP
|
|
124
|
+
git\-span\-history(1)
|
|
125
|
+
Show a chronological timeline of a span file\*(Aqs git history: each commit where the span changed, rendered oldest→newest, with the content of any anchor that was added, modified, or removed, and an optional `current` entry describing how the working tree has drifted from HEAD
|
|
126
|
+
.TP
|
|
127
|
+
git\-span\-help(1)
|
|
128
|
+
Print this message or the help of the given subcommand(s)
|
|
129
|
+
.ie \n(.g .ds Aq \(aq
|
|
130
|
+
.el .ds Aq '
|
|
131
|
+
.SH VERSION
|
|
132
|
+
v1.0.131
|
|
133
|
+
.SH EXAMPLES
|
|
134
|
+
Anchor a new span alongside a code change:
|
|
135
|
+
.PP
|
|
136
|
+
.RS 4
|
|
137
|
+
.nf
|
|
138
|
+
git span add billing/charge-request-contract \e
|
|
139
|
+
docs/api/charge.md#L40-L88 api/charge.ts#L30-L76
|
|
140
|
+
git span why billing/charge-request-contract \e
|
|
141
|
+
-m "The doc states the request body shape the parser honors; \e
|
|
142
|
+
the doc is the source of truth when they disagree."
|
|
143
|
+
git add .span
|
|
144
|
+
git commit -m "Wire checkout to charge API"
|
|
145
|
+
.fi
|
|
146
|
+
.RE
|
|
147
|
+
.PP
|
|
148
|
+
Document an existing relationship anchored at HEAD:
|
|
149
|
+
.PP
|
|
150
|
+
.RS 4
|
|
151
|
+
.nf
|
|
152
|
+
git span add auth/token-contract --at HEAD \e
|
|
153
|
+
packages/auth/token.ts#L88-L104 \e
|
|
154
|
+
packages/auth/crypto.ts#L12-L40
|
|
155
|
+
git span why auth/token-contract \e
|
|
156
|
+
-m "Token verification depends on signature verification."
|
|
157
|
+
git add .span && git commit -m "Document token/crypto coupling"
|
|
158
|
+
.fi
|
|
159
|
+
.RE
|
|
160
|
+
.PP
|
|
161
|
+
Check for drift and inspect a span:
|
|
162
|
+
.PP
|
|
163
|
+
.RS 4
|
|
164
|
+
.nf
|
|
165
|
+
git span stale
|
|
166
|
+
git span billing/charge-request-contract
|
|
167
|
+
git span show billing/charge-request-contract
|
|
168
|
+
.fi
|
|
169
|
+
.RE
|
|
170
|
+
.SH SEE ALSO
|
|
171
|
+
.BR git (1),
|
|
172
|
+
.BR gitcli (7)
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "git-span",
|
|
3
|
+
"version": "1.0.131",
|
|
4
|
+
"bin": "bin/git-span.exe",
|
|
5
|
+
"man": [
|
|
6
|
+
"man/git-span.1"
|
|
7
|
+
],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node scripts/postinstall.js",
|
|
10
|
+
"build:man": "bash scripts/with-target-lock.sh shared env CARGO_BUILD_JOBS=1 CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/build\" cargo run --quiet --locked --bin gen-manpage -- man/git-span.1",
|
|
11
|
+
"build": "yarn build:man && bash scripts/with-target-lock.sh shared env CARGO_BUILD_JOBS=1 CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/build\" cargo build --release --locked",
|
|
12
|
+
"build:local": "bash scripts/build-local.sh",
|
|
13
|
+
"build:clean": "bash scripts/cleanup-stale-target.sh && bash scripts/clean-shared-build.sh && yarn build",
|
|
14
|
+
"test": "bash scripts/with-target-lock.sh shared env CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/build\" cargo nextest run --build-jobs 1 --locked",
|
|
15
|
+
"lint": "bash scripts/with-target-lock.sh shared env CARGO_BUILD_JOBS=1 RUSTFLAGS=\"-W unused -W dead-code\" CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/check\" cargo clippy --quiet --locked -- -D warnings",
|
|
16
|
+
"typecheck": "bash scripts/with-target-lock.sh shared env CARGO_BUILD_JOBS=1 RUSTFLAGS=\"-W unused -W dead-code\" CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/check\" cargo check --quiet --locked",
|
|
17
|
+
"bench:check": "bash scripts/with-target-lock.sh shared env CARGO_BUILD_JOBS=1 CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/build\" cargo bench --no-run --locked --features bench-corpus",
|
|
18
|
+
"bench": "bash scripts/with-target-lock.sh shared env CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/build\" cargo bench --locked",
|
|
19
|
+
"udeps": "bash scripts/with-target-lock.sh shared env CARGO_BUILD_JOBS=1 CARGO_TARGET_DIR=\"${GIT_SPAN_CARGO_TARGET_ROOT:-$HOME/.cache/git-span/cargo-target}/git-span/udeps\" cargo +nightly udeps"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin/git-span.exe",
|
|
23
|
+
"man/",
|
|
24
|
+
"scripts/postinstall.js"
|
|
25
|
+
],
|
|
26
|
+
"optionalDependencies": {
|
|
27
|
+
"git-span-darwin-arm64": "1.0.131",
|
|
28
|
+
"git-span-darwin-x64": "1.0.131",
|
|
29
|
+
"git-span-linux-arm64": "1.0.131",
|
|
30
|
+
"git-span-linux-x64": "1.0.131",
|
|
31
|
+
"git-span-win32-x64": "1.0.131"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/goodfoot-io/git-span.git"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const PLATFORM_MAP = {
|
|
8
|
+
linux: 'linux',
|
|
9
|
+
darwin: 'darwin',
|
|
10
|
+
win32: 'win32'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const ARCH_MAP = {
|
|
14
|
+
x64: 'x64',
|
|
15
|
+
arm64: 'arm64'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function fail(message, error) {
|
|
19
|
+
console.error(message);
|
|
20
|
+
if (error) {
|
|
21
|
+
console.error(error.message);
|
|
22
|
+
}
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function buildFromSource(destBinary, binaryName) {
|
|
27
|
+
const cargoToml = path.join(__dirname, '..', 'Cargo.toml');
|
|
28
|
+
if (!fs.existsSync(cargoToml)) {
|
|
29
|
+
fail(`git-span: Binary not found at ${destBinary} and no Cargo.toml available to build from source.`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(`git-span: Prebuilt binary missing; building from source via cargo...`);
|
|
33
|
+
|
|
34
|
+
const targetDir = path.join(__dirname, '..', 'target-cache', 'build');
|
|
35
|
+
const result = spawnSync('cargo', ['build', '--release', '--manifest-path', cargoToml], {
|
|
36
|
+
stdio: 'inherit',
|
|
37
|
+
env: { ...process.env, CARGO_BUILD_JOBS: '1', CARGO_TARGET_DIR: targetDir }
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (result.error || result.status !== 0) {
|
|
41
|
+
fail(
|
|
42
|
+
`git-span: Failed to build binary from source. Install Rust/cargo or publish the platform package.`,
|
|
43
|
+
result.error
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const builtBinary = path.join(targetDir, 'release', binaryName);
|
|
48
|
+
if (!fs.existsSync(builtBinary)) {
|
|
49
|
+
fail(`git-span: cargo build succeeded but binary not found at ${builtBinary}.`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fs.mkdirSync(path.dirname(destBinary), { recursive: true });
|
|
53
|
+
fs.copyFileSync(builtBinary, destBinary);
|
|
54
|
+
fs.chmodSync(destBinary, 0o755);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isInsideSourceTree() {
|
|
58
|
+
// Walk up from this script looking for a `.git` entry. If found, this is
|
|
59
|
+
// the git-span source repo (developer doing `yarn install`), not
|
|
60
|
+
// a consumer install under node_modules. Mutating the tracked `bin/git-span`
|
|
61
|
+
// shim in that case dirties the working tree and — if committed — ships a
|
|
62
|
+
// dangling symlink in the published tarball (see git-span-v1.0.25 regression).
|
|
63
|
+
let dir = path.resolve(__dirname, '..');
|
|
64
|
+
for (let i = 0; i < 16; i++) {
|
|
65
|
+
if (fs.existsSync(path.join(dir, '.git'))) return true;
|
|
66
|
+
const parent = path.dirname(dir);
|
|
67
|
+
if (parent === dir) return false;
|
|
68
|
+
if (path.basename(parent) === 'node_modules') return false;
|
|
69
|
+
dir = parent;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function main() {
|
|
75
|
+
if (isInsideSourceTree()) {
|
|
76
|
+
console.log('git-span: postinstall skipped (running inside source tree).');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
81
|
+
const arch = ARCH_MAP[process.arch];
|
|
82
|
+
|
|
83
|
+
if (!platform || !arch) {
|
|
84
|
+
fail(`git-span: No prebuilt binary available for ${process.platform}-${process.arch}.`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const packageName = `git-span-${platform}-${arch}`;
|
|
88
|
+
const sourceBinaryName = process.platform === 'win32' ? 'git-span.exe' : 'git-span';
|
|
89
|
+
|
|
90
|
+
let packageDir;
|
|
91
|
+
try {
|
|
92
|
+
packageDir = path.dirname(require.resolve(`${packageName}/package.json`));
|
|
93
|
+
} catch (error) {
|
|
94
|
+
fail(`git-span: Required platform package ${packageName} not found.`, error);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const sourceBinary = path.join(packageDir, 'bin', sourceBinaryName);
|
|
98
|
+
if (!fs.existsSync(sourceBinary)) {
|
|
99
|
+
buildFromSource(sourceBinary, sourceBinaryName);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Always write to bin/git-span.exe — the package.json `bin` field points
|
|
103
|
+
// here on every platform. The `.exe` extension plus a no-shebang stub makes
|
|
104
|
+
// npm's cmd-shim (generated at install time, before this postinstall) emit
|
|
105
|
+
// a direct exec on Windows; Unix executes by mode bit + ELF/Mach-O header
|
|
106
|
+
// and ignores the `.exe` suffix entirely. No resident Node process — the
|
|
107
|
+
// `git-span` command execs the native binary directly. Same pattern as
|
|
108
|
+
// Bun's and Claude Code's npm packages.
|
|
109
|
+
const binGitSpan = path.join(__dirname, '..', 'bin', 'git-span.exe');
|
|
110
|
+
|
|
111
|
+
// Hardlink first (instant, zero extra disk for the ~16MB binary; src and
|
|
112
|
+
// dest are both under node_modules so same-filesystem is the common case),
|
|
113
|
+
// then fall back to copy across devices / on link-permission errors.
|
|
114
|
+
try {
|
|
115
|
+
fs.linkSync(sourceBinary, binGitSpan);
|
|
116
|
+
} catch (linkError) {
|
|
117
|
+
if (linkError.code === 'EEXIST') {
|
|
118
|
+
try {
|
|
119
|
+
fs.unlinkSync(binGitSpan);
|
|
120
|
+
fs.linkSync(sourceBinary, binGitSpan);
|
|
121
|
+
} catch {
|
|
122
|
+
fs.copyFileSync(sourceBinary, binGitSpan);
|
|
123
|
+
}
|
|
124
|
+
} else if (linkError.code === 'EXDEV' || linkError.code === 'EPERM') {
|
|
125
|
+
fs.copyFileSync(sourceBinary, binGitSpan);
|
|
126
|
+
} else {
|
|
127
|
+
try {
|
|
128
|
+
fs.copyFileSync(sourceBinary, binGitSpan);
|
|
129
|
+
} catch (copyError) {
|
|
130
|
+
fail(
|
|
131
|
+
`git-span: Could not install binary from ${sourceBinary} to ${binGitSpan}.`,
|
|
132
|
+
new Error(`link failed: ${linkError.message}\ncopy failed: ${copyError.message}`)
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (process.platform !== 'win32') {
|
|
138
|
+
fs.chmodSync(binGitSpan, 0o755);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(`git-span: Installed git-span from ${packageName}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
main();
|