isomorphic-git 1.41.0 → 1.41.2
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/index.cjs +113 -43
- package/index.js +113 -43
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +108 -38
- package/managers/index.js +108 -38
- package/managers/index.umd.min.js +1 -1
- package/managers/index.umd.min.js.map +1 -1
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -4,8 +4,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
6
|
|
|
7
|
-
var AsyncLock = _interopDefault(require('async-lock'));
|
|
8
7
|
var Hash = _interopDefault(require('sha.js/sha1.js'));
|
|
8
|
+
var AsyncLock = _interopDefault(require('async-lock'));
|
|
9
9
|
var crc32 = _interopDefault(require('crc-32'));
|
|
10
10
|
var pako = _interopDefault(require('pako'));
|
|
11
11
|
var crypto$1 = require('crypto');
|
|
@@ -964,10 +964,43 @@ function compareStats(entry, stats, filemode = true, trustino = true) {
|
|
|
964
964
|
return staleness
|
|
965
965
|
}
|
|
966
966
|
|
|
967
|
-
//
|
|
967
|
+
// A single process-wide lock shared by everything that serializes file
|
|
968
|
+
// operations (the index, refs, the shallow file, blob writes). It is keyed by
|
|
969
|
+
// path, so unrelated resources never contend. Centralizing it here also means
|
|
970
|
+
// there is exactly one place to reset it (see `_resetLock`).
|
|
971
|
+
//
|
|
972
|
+
// Created lazily (not at module load) so this module has no top-level side
|
|
973
|
+
// effect and stays tree-shakeable.
|
|
974
|
+
let lock;
|
|
968
975
|
|
|
969
|
-
|
|
970
|
-
|
|
976
|
+
function getLock() {
|
|
977
|
+
if (lock === undefined) lock = new AsyncLock({ maxPending: Infinity });
|
|
978
|
+
return lock
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Run `callback` while holding the shared lock for `key`, then release it.
|
|
983
|
+
*
|
|
984
|
+
* @template T
|
|
985
|
+
* @param {string | string[]} key - Resource key(s) to lock (usually a filepath).
|
|
986
|
+
* @param {() => (Promise<T> | T)} callback
|
|
987
|
+
* @returns {Promise<T>}
|
|
988
|
+
*/
|
|
989
|
+
function acquireLock(key, callback) {
|
|
990
|
+
return getLock().acquire(key, callback)
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Discard the shared lock so the next `acquireLock` starts a fresh one. Intended
|
|
995
|
+
* for test harnesses that run many independent scenarios inside one long-lived
|
|
996
|
+
* module instance: if a scenario leaves an operation stalled (e.g. a filesystem
|
|
997
|
+
* that hangs), its still-held lock would otherwise block every later scenario
|
|
998
|
+
* that touches the same path. Resetting abandons that stalled queue so the next
|
|
999
|
+
* scenario starts clean. It is a no-op for normal library use.
|
|
1000
|
+
*/
|
|
1001
|
+
function _resetLock() {
|
|
1002
|
+
lock = undefined;
|
|
1003
|
+
}
|
|
971
1004
|
|
|
972
1005
|
const IndexCache = Symbol('IndexCache');
|
|
973
1006
|
|
|
@@ -1038,10 +1071,9 @@ class GitIndexManager {
|
|
|
1038
1071
|
}
|
|
1039
1072
|
|
|
1040
1073
|
const filepath = `${gitdir}/index`;
|
|
1041
|
-
if (lock === null) lock = new AsyncLock({ maxPending: Infinity });
|
|
1042
1074
|
let result;
|
|
1043
1075
|
let unmergedPaths = [];
|
|
1044
|
-
await
|
|
1076
|
+
await acquireLock(filepath, async () => {
|
|
1045
1077
|
// Acquire a file lock while we're reading the index
|
|
1046
1078
|
// to make sure other processes aren't writing to it
|
|
1047
1079
|
// simultaneously, which could result in a corrupted index.
|
|
@@ -2031,13 +2063,6 @@ function assertWritableRef(ref) {
|
|
|
2031
2063
|
}
|
|
2032
2064
|
}
|
|
2033
2065
|
|
|
2034
|
-
let lock$1;
|
|
2035
|
-
|
|
2036
|
-
async function acquireLock(ref, callback) {
|
|
2037
|
-
if (lock$1 === undefined) lock$1 = new AsyncLock();
|
|
2038
|
-
return lock$1.acquire(ref, callback)
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
2066
|
/**
|
|
2042
2067
|
* A class for managing Git references, including reading, writing, deleting, and resolving refs.
|
|
2043
2068
|
*/
|
|
@@ -8348,12 +8373,6 @@ const _TreeMap = {
|
|
|
8348
8373
|
workdir: WORKDIR,
|
|
8349
8374
|
};
|
|
8350
8375
|
|
|
8351
|
-
let lock$2;
|
|
8352
|
-
async function acquireLock$1(ref, callback) {
|
|
8353
|
-
if (lock$2 === undefined) lock$2 = new AsyncLock();
|
|
8354
|
-
return lock$2.acquire(ref, callback)
|
|
8355
|
-
}
|
|
8356
|
-
|
|
8357
8376
|
// make sure filepath, blob type and blob object (from loose objects) plus oid are in sync and valid
|
|
8358
8377
|
async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
8359
8378
|
const currentFilepath = join(dir, filepath);
|
|
@@ -8370,7 +8389,7 @@ async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
|
8370
8389
|
: undefined;
|
|
8371
8390
|
let retOid = objContent ? oid : undefined;
|
|
8372
8391
|
if (!objContent) {
|
|
8373
|
-
await acquireLock
|
|
8392
|
+
await acquireLock(currentFilepath, async () => {
|
|
8374
8393
|
const object = stats.isSymbolicLink()
|
|
8375
8394
|
? await fs.readlink(currentFilepath).then(posixifyPathBuffer)
|
|
8376
8395
|
: await fs.read(currentFilepath);
|
|
@@ -8585,7 +8604,7 @@ async function applyTreeChanges({
|
|
|
8585
8604
|
});
|
|
8586
8605
|
|
|
8587
8606
|
// apply the changes to work dir
|
|
8588
|
-
await acquireLock
|
|
8607
|
+
await acquireLock(gitdir, async () => {
|
|
8589
8608
|
for (const op of ops) {
|
|
8590
8609
|
const currentFilepath = join(dir, op.filepath);
|
|
8591
8610
|
switch (op.method) {
|
|
@@ -8974,21 +8993,76 @@ async function collect(iterable) {
|
|
|
8974
8993
|
return result
|
|
8975
8994
|
}
|
|
8976
8995
|
|
|
8996
|
+
// The `@` that ends the credentials is the last one in the authority, and the
|
|
8997
|
+
// scheme is matched case-insensitively: `HTTPS://user:pass@host/x` is a URL
|
|
8998
|
+
// like any other, and leaving the credentials in it is what `fetch` rejects.
|
|
8999
|
+
// The authority ends at the first `/`, `?` or `#`, so an `@` that lives in a
|
|
9000
|
+
// query or a fragment is left where it is.
|
|
9001
|
+
const CREDENTIALS = /^(https?:\/\/)([^/?#]+)@/i;
|
|
9002
|
+
|
|
8977
9003
|
function extractAuthFromUrl(url) {
|
|
8978
9004
|
// For whatever reason, the `fetch` API does not convert credentials embedded in the URL
|
|
8979
9005
|
// into Basic Authentication headers automatically. Instead it throws an error!
|
|
8980
9006
|
// So we must manually parse the URL, rip out the user:password portion if it is present
|
|
8981
9007
|
// and compute the Authorization header.
|
|
8982
|
-
|
|
8983
|
-
let userpass = url.match(/^https?:\/\/([^/]+)@/);
|
|
9008
|
+
const credentials = url.match(CREDENTIALS);
|
|
8984
9009
|
// No credentials, return the url unmodified and an empty auth object
|
|
8985
|
-
if (
|
|
8986
|
-
|
|
8987
|
-
|
|
8988
|
-
//
|
|
8989
|
-
|
|
8990
|
-
//
|
|
8991
|
-
return {
|
|
9010
|
+
if (credentials == null) return { url, auth: {} }
|
|
9011
|
+
// Has credentials, return the fetch-safe URL and the parsed credentials.
|
|
9012
|
+
// The credentials are cut out of the original string rather than read back
|
|
9013
|
+
// off the parsed URL: serializing that one would also drop an explicit
|
|
9014
|
+
// `:443` and append a slash to a URL that has no path, and this return value
|
|
9015
|
+
// is what the request goes out against.
|
|
9016
|
+
return {
|
|
9017
|
+
url: url.replace(CREDENTIALS, '$1'),
|
|
9018
|
+
auth: parseUserinfo(url, credentials[2]),
|
|
9019
|
+
}
|
|
9020
|
+
}
|
|
9021
|
+
|
|
9022
|
+
function parseUserinfo(url, userpass) {
|
|
9023
|
+
// `URL` splits the two halves the way the platform does, so the first colon
|
|
9024
|
+
// separates them and any later one stays in the password. Only the split is
|
|
9025
|
+
// taken from it, for the reason above.
|
|
9026
|
+
const parsed = parseUrl(url);
|
|
9027
|
+
// A password is absent, not empty, when no colon was written at all. `URL`
|
|
9028
|
+
// reports `''` for both, and the difference is worth keeping.
|
|
9029
|
+
const hasPassword = userpass.indexOf(':') !== -1;
|
|
9030
|
+
|
|
9031
|
+
if (parsed !== null) {
|
|
9032
|
+
return {
|
|
9033
|
+
username: decodeUserinfo(parsed.username),
|
|
9034
|
+
password: hasPassword ? decodeUserinfo(parsed.password) : undefined,
|
|
9035
|
+
}
|
|
9036
|
+
}
|
|
9037
|
+
|
|
9038
|
+
// No `URL` to parse with, or it rejected a string the expression above
|
|
9039
|
+
// accepted. Split on the first colon by hand, without the percent-decoding.
|
|
9040
|
+
const separatorIndex = userpass.indexOf(':');
|
|
9041
|
+
return {
|
|
9042
|
+
username: hasPassword ? userpass.slice(0, separatorIndex) : userpass,
|
|
9043
|
+
password: hasPassword ? userpass.slice(separatorIndex + 1) : undefined,
|
|
9044
|
+
}
|
|
9045
|
+
}
|
|
9046
|
+
|
|
9047
|
+
function parseUrl(url) {
|
|
9048
|
+
if (typeof URL !== 'function') return null
|
|
9049
|
+
try {
|
|
9050
|
+
return new URL(url)
|
|
9051
|
+
} catch (_) {
|
|
9052
|
+
return null
|
|
9053
|
+
}
|
|
9054
|
+
}
|
|
9055
|
+
|
|
9056
|
+
// `URL` hands back the userinfo still percent-encoded, so `p:ss` arrives as
|
|
9057
|
+
// `p%3Ass` and has to be decoded before it reaches the Authorization header. A
|
|
9058
|
+
// lone `%` is not something the parser encodes, and it makes the decode throw,
|
|
9059
|
+
// so the raw value stands in whenever the decode fails.
|
|
9060
|
+
function decodeUserinfo(value) {
|
|
9061
|
+
try {
|
|
9062
|
+
return decodeURIComponent(value)
|
|
9063
|
+
} catch (_) {
|
|
9064
|
+
return value
|
|
9065
|
+
}
|
|
8992
9066
|
}
|
|
8993
9067
|
|
|
8994
9068
|
function padHex(b, n) {
|
|
@@ -9484,8 +9558,6 @@ function parseRemoteUrl({ url }) {
|
|
|
9484
9558
|
}
|
|
9485
9559
|
}
|
|
9486
9560
|
|
|
9487
|
-
let lock$3 = null;
|
|
9488
|
-
|
|
9489
9561
|
class GitShallowManager {
|
|
9490
9562
|
/**
|
|
9491
9563
|
* Reads the `shallow` file in the Git repository and returns a set of object IDs (OIDs).
|
|
@@ -9496,10 +9568,9 @@ class GitShallowManager {
|
|
|
9496
9568
|
* @returns {Promise<Set<string>>} - A set of shallow object IDs.
|
|
9497
9569
|
*/
|
|
9498
9570
|
static async read({ fs, gitdir }) {
|
|
9499
|
-
if (lock$3 === null) lock$3 = new AsyncLock();
|
|
9500
9571
|
const filepath = join(gitdir, 'shallow');
|
|
9501
9572
|
const oids = new Set();
|
|
9502
|
-
await
|
|
9573
|
+
await acquireLock(filepath, async function () {
|
|
9503
9574
|
const text = await fs.read(filepath, { encoding: 'utf8' });
|
|
9504
9575
|
if (text === null) return oids // no file
|
|
9505
9576
|
if (text.trim() === '') return oids // empty file
|
|
@@ -9522,18 +9593,17 @@ class GitShallowManager {
|
|
|
9522
9593
|
* @returns {Promise<void>}
|
|
9523
9594
|
*/
|
|
9524
9595
|
static async write({ fs, gitdir, oids }) {
|
|
9525
|
-
if (lock$3 === null) lock$3 = new AsyncLock();
|
|
9526
9596
|
const filepath = join(gitdir, 'shallow');
|
|
9527
9597
|
if (oids.size > 0) {
|
|
9528
9598
|
const text = [...oids].join('\n') + '\n';
|
|
9529
|
-
await
|
|
9599
|
+
await acquireLock(filepath, async function () {
|
|
9530
9600
|
await fs.write(filepath, text, {
|
|
9531
9601
|
encoding: 'utf8',
|
|
9532
9602
|
});
|
|
9533
9603
|
});
|
|
9534
9604
|
} else {
|
|
9535
9605
|
// No shallows
|
|
9536
|
-
await
|
|
9606
|
+
await acquireLock(filepath, async function () {
|
|
9537
9607
|
await fs.rm(filepath);
|
|
9538
9608
|
});
|
|
9539
9609
|
}
|
|
@@ -9630,8 +9700,8 @@ function filterCapabilities(server, client) {
|
|
|
9630
9700
|
|
|
9631
9701
|
const pkg = {
|
|
9632
9702
|
name: 'isomorphic-git',
|
|
9633
|
-
version: '1.41.
|
|
9634
|
-
agent: 'git/isomorphic-git@1.41.
|
|
9703
|
+
version: '1.41.2',
|
|
9704
|
+
agent: 'git/isomorphic-git@1.41.2',
|
|
9635
9705
|
};
|
|
9636
9706
|
|
|
9637
9707
|
class FIFO {
|
|
@@ -15988,7 +16058,7 @@ class GitStashManager {
|
|
|
15988
16058
|
);
|
|
15989
16059
|
const filepath = this.refLogsStashPath;
|
|
15990
16060
|
|
|
15991
|
-
await acquireLock
|
|
16061
|
+
await acquireLock(filepath, async () => {
|
|
15992
16062
|
const appendTo = (await this.fs.exists(filepath))
|
|
15993
16063
|
? await this.fs.read(filepath, 'utf8')
|
|
15994
16064
|
: '';
|
|
@@ -16182,7 +16252,7 @@ async function _stashDrop({ fs, dir, gitdir, refIdx = 0 }) {
|
|
|
16182
16252
|
}
|
|
16183
16253
|
// remove stash ref first
|
|
16184
16254
|
const stashRefPath = stashMgr.refStashPath;
|
|
16185
|
-
await acquireLock
|
|
16255
|
+
await acquireLock(stashRefPath, async () => {
|
|
16186
16256
|
if (await fs.exists(stashRefPath)) {
|
|
16187
16257
|
await fs.rm(stashRefPath);
|
|
16188
16258
|
}
|
|
@@ -16198,7 +16268,7 @@ async function _stashDrop({ fs, dir, gitdir, refIdx = 0 }) {
|
|
|
16198
16268
|
reflogEntries.splice(refIdx, 1);
|
|
16199
16269
|
|
|
16200
16270
|
const stashReflogPath = stashMgr.refLogsStashPath;
|
|
16201
|
-
await acquireLock
|
|
16271
|
+
await acquireLock(stashReflogPath, async () => {
|
|
16202
16272
|
if (reflogEntries.length) {
|
|
16203
16273
|
await fs.write(
|
|
16204
16274
|
stashReflogPath,
|
|
@@ -16224,7 +16294,7 @@ async function _stashClear({ fs, dir, gitdir }) {
|
|
|
16224
16294
|
const stashMgr = new GitStashManager({ fs, dir, gitdir });
|
|
16225
16295
|
const stashRefPath = [stashMgr.refStashPath, stashMgr.refLogsStashPath];
|
|
16226
16296
|
|
|
16227
|
-
await acquireLock
|
|
16297
|
+
await acquireLock(stashRefPath, async () => {
|
|
16228
16298
|
await Promise.all(
|
|
16229
16299
|
stashRefPath.map(async path => {
|
|
16230
16300
|
if (await fs.exists(path)) {
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import AsyncLock from 'async-lock';
|
|
2
1
|
import Hash from 'sha.js/sha1.js';
|
|
2
|
+
import AsyncLock from 'async-lock';
|
|
3
3
|
import crc32 from 'crc-32';
|
|
4
4
|
import pako from 'pako';
|
|
5
5
|
import pify from 'pify';
|
|
@@ -957,10 +957,43 @@ function compareStats(entry, stats, filemode = true, trustino = true) {
|
|
|
957
957
|
return staleness
|
|
958
958
|
}
|
|
959
959
|
|
|
960
|
-
//
|
|
960
|
+
// A single process-wide lock shared by everything that serializes file
|
|
961
|
+
// operations (the index, refs, the shallow file, blob writes). It is keyed by
|
|
962
|
+
// path, so unrelated resources never contend. Centralizing it here also means
|
|
963
|
+
// there is exactly one place to reset it (see `_resetLock`).
|
|
964
|
+
//
|
|
965
|
+
// Created lazily (not at module load) so this module has no top-level side
|
|
966
|
+
// effect and stays tree-shakeable.
|
|
967
|
+
let lock;
|
|
961
968
|
|
|
962
|
-
|
|
963
|
-
|
|
969
|
+
function getLock() {
|
|
970
|
+
if (lock === undefined) lock = new AsyncLock({ maxPending: Infinity });
|
|
971
|
+
return lock
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* Run `callback` while holding the shared lock for `key`, then release it.
|
|
976
|
+
*
|
|
977
|
+
* @template T
|
|
978
|
+
* @param {string | string[]} key - Resource key(s) to lock (usually a filepath).
|
|
979
|
+
* @param {() => (Promise<T> | T)} callback
|
|
980
|
+
* @returns {Promise<T>}
|
|
981
|
+
*/
|
|
982
|
+
function acquireLock(key, callback) {
|
|
983
|
+
return getLock().acquire(key, callback)
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Discard the shared lock so the next `acquireLock` starts a fresh one. Intended
|
|
988
|
+
* for test harnesses that run many independent scenarios inside one long-lived
|
|
989
|
+
* module instance: if a scenario leaves an operation stalled (e.g. a filesystem
|
|
990
|
+
* that hangs), its still-held lock would otherwise block every later scenario
|
|
991
|
+
* that touches the same path. Resetting abandons that stalled queue so the next
|
|
992
|
+
* scenario starts clean. It is a no-op for normal library use.
|
|
993
|
+
*/
|
|
994
|
+
function _resetLock() {
|
|
995
|
+
lock = undefined;
|
|
996
|
+
}
|
|
964
997
|
|
|
965
998
|
const IndexCache = Symbol('IndexCache');
|
|
966
999
|
|
|
@@ -1031,10 +1064,9 @@ class GitIndexManager {
|
|
|
1031
1064
|
}
|
|
1032
1065
|
|
|
1033
1066
|
const filepath = `${gitdir}/index`;
|
|
1034
|
-
if (lock === null) lock = new AsyncLock({ maxPending: Infinity });
|
|
1035
1067
|
let result;
|
|
1036
1068
|
let unmergedPaths = [];
|
|
1037
|
-
await
|
|
1069
|
+
await acquireLock(filepath, async () => {
|
|
1038
1070
|
// Acquire a file lock while we're reading the index
|
|
1039
1071
|
// to make sure other processes aren't writing to it
|
|
1040
1072
|
// simultaneously, which could result in a corrupted index.
|
|
@@ -2024,13 +2056,6 @@ function assertWritableRef(ref) {
|
|
|
2024
2056
|
}
|
|
2025
2057
|
}
|
|
2026
2058
|
|
|
2027
|
-
let lock$1;
|
|
2028
|
-
|
|
2029
|
-
async function acquireLock(ref, callback) {
|
|
2030
|
-
if (lock$1 === undefined) lock$1 = new AsyncLock();
|
|
2031
|
-
return lock$1.acquire(ref, callback)
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
2059
|
/**
|
|
2035
2060
|
* A class for managing Git references, including reading, writing, deleting, and resolving refs.
|
|
2036
2061
|
*/
|
|
@@ -8335,12 +8360,6 @@ const _TreeMap = {
|
|
|
8335
8360
|
workdir: WORKDIR,
|
|
8336
8361
|
};
|
|
8337
8362
|
|
|
8338
|
-
let lock$2;
|
|
8339
|
-
async function acquireLock$1(ref, callback) {
|
|
8340
|
-
if (lock$2 === undefined) lock$2 = new AsyncLock();
|
|
8341
|
-
return lock$2.acquire(ref, callback)
|
|
8342
|
-
}
|
|
8343
|
-
|
|
8344
8363
|
// make sure filepath, blob type and blob object (from loose objects) plus oid are in sync and valid
|
|
8345
8364
|
async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
8346
8365
|
const currentFilepath = join(dir, filepath);
|
|
@@ -8357,7 +8376,7 @@ async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
|
8357
8376
|
: undefined;
|
|
8358
8377
|
let retOid = objContent ? oid : undefined;
|
|
8359
8378
|
if (!objContent) {
|
|
8360
|
-
await acquireLock
|
|
8379
|
+
await acquireLock(currentFilepath, async () => {
|
|
8361
8380
|
const object = stats.isSymbolicLink()
|
|
8362
8381
|
? await fs.readlink(currentFilepath).then(posixifyPathBuffer)
|
|
8363
8382
|
: await fs.read(currentFilepath);
|
|
@@ -8572,7 +8591,7 @@ async function applyTreeChanges({
|
|
|
8572
8591
|
});
|
|
8573
8592
|
|
|
8574
8593
|
// apply the changes to work dir
|
|
8575
|
-
await acquireLock
|
|
8594
|
+
await acquireLock(gitdir, async () => {
|
|
8576
8595
|
for (const op of ops) {
|
|
8577
8596
|
const currentFilepath = join(dir, op.filepath);
|
|
8578
8597
|
switch (op.method) {
|
|
@@ -8961,21 +8980,76 @@ async function collect(iterable) {
|
|
|
8961
8980
|
return result
|
|
8962
8981
|
}
|
|
8963
8982
|
|
|
8983
|
+
// The `@` that ends the credentials is the last one in the authority, and the
|
|
8984
|
+
// scheme is matched case-insensitively: `HTTPS://user:pass@host/x` is a URL
|
|
8985
|
+
// like any other, and leaving the credentials in it is what `fetch` rejects.
|
|
8986
|
+
// The authority ends at the first `/`, `?` or `#`, so an `@` that lives in a
|
|
8987
|
+
// query or a fragment is left where it is.
|
|
8988
|
+
const CREDENTIALS = /^(https?:\/\/)([^/?#]+)@/i;
|
|
8989
|
+
|
|
8964
8990
|
function extractAuthFromUrl(url) {
|
|
8965
8991
|
// For whatever reason, the `fetch` API does not convert credentials embedded in the URL
|
|
8966
8992
|
// into Basic Authentication headers automatically. Instead it throws an error!
|
|
8967
8993
|
// So we must manually parse the URL, rip out the user:password portion if it is present
|
|
8968
8994
|
// and compute the Authorization header.
|
|
8969
|
-
|
|
8970
|
-
let userpass = url.match(/^https?:\/\/([^/]+)@/);
|
|
8995
|
+
const credentials = url.match(CREDENTIALS);
|
|
8971
8996
|
// No credentials, return the url unmodified and an empty auth object
|
|
8972
|
-
if (
|
|
8973
|
-
|
|
8974
|
-
|
|
8975
|
-
//
|
|
8976
|
-
|
|
8977
|
-
//
|
|
8978
|
-
return {
|
|
8997
|
+
if (credentials == null) return { url, auth: {} }
|
|
8998
|
+
// Has credentials, return the fetch-safe URL and the parsed credentials.
|
|
8999
|
+
// The credentials are cut out of the original string rather than read back
|
|
9000
|
+
// off the parsed URL: serializing that one would also drop an explicit
|
|
9001
|
+
// `:443` and append a slash to a URL that has no path, and this return value
|
|
9002
|
+
// is what the request goes out against.
|
|
9003
|
+
return {
|
|
9004
|
+
url: url.replace(CREDENTIALS, '$1'),
|
|
9005
|
+
auth: parseUserinfo(url, credentials[2]),
|
|
9006
|
+
}
|
|
9007
|
+
}
|
|
9008
|
+
|
|
9009
|
+
function parseUserinfo(url, userpass) {
|
|
9010
|
+
// `URL` splits the two halves the way the platform does, so the first colon
|
|
9011
|
+
// separates them and any later one stays in the password. Only the split is
|
|
9012
|
+
// taken from it, for the reason above.
|
|
9013
|
+
const parsed = parseUrl(url);
|
|
9014
|
+
// A password is absent, not empty, when no colon was written at all. `URL`
|
|
9015
|
+
// reports `''` for both, and the difference is worth keeping.
|
|
9016
|
+
const hasPassword = userpass.indexOf(':') !== -1;
|
|
9017
|
+
|
|
9018
|
+
if (parsed !== null) {
|
|
9019
|
+
return {
|
|
9020
|
+
username: decodeUserinfo(parsed.username),
|
|
9021
|
+
password: hasPassword ? decodeUserinfo(parsed.password) : undefined,
|
|
9022
|
+
}
|
|
9023
|
+
}
|
|
9024
|
+
|
|
9025
|
+
// No `URL` to parse with, or it rejected a string the expression above
|
|
9026
|
+
// accepted. Split on the first colon by hand, without the percent-decoding.
|
|
9027
|
+
const separatorIndex = userpass.indexOf(':');
|
|
9028
|
+
return {
|
|
9029
|
+
username: hasPassword ? userpass.slice(0, separatorIndex) : userpass,
|
|
9030
|
+
password: hasPassword ? userpass.slice(separatorIndex + 1) : undefined,
|
|
9031
|
+
}
|
|
9032
|
+
}
|
|
9033
|
+
|
|
9034
|
+
function parseUrl(url) {
|
|
9035
|
+
if (typeof URL !== 'function') return null
|
|
9036
|
+
try {
|
|
9037
|
+
return new URL(url)
|
|
9038
|
+
} catch (_) {
|
|
9039
|
+
return null
|
|
9040
|
+
}
|
|
9041
|
+
}
|
|
9042
|
+
|
|
9043
|
+
// `URL` hands back the userinfo still percent-encoded, so `p:ss` arrives as
|
|
9044
|
+
// `p%3Ass` and has to be decoded before it reaches the Authorization header. A
|
|
9045
|
+
// lone `%` is not something the parser encodes, and it makes the decode throw,
|
|
9046
|
+
// so the raw value stands in whenever the decode fails.
|
|
9047
|
+
function decodeUserinfo(value) {
|
|
9048
|
+
try {
|
|
9049
|
+
return decodeURIComponent(value)
|
|
9050
|
+
} catch (_) {
|
|
9051
|
+
return value
|
|
9052
|
+
}
|
|
8979
9053
|
}
|
|
8980
9054
|
|
|
8981
9055
|
function padHex(b, n) {
|
|
@@ -9471,8 +9545,6 @@ function parseRemoteUrl({ url }) {
|
|
|
9471
9545
|
}
|
|
9472
9546
|
}
|
|
9473
9547
|
|
|
9474
|
-
let lock$3 = null;
|
|
9475
|
-
|
|
9476
9548
|
class GitShallowManager {
|
|
9477
9549
|
/**
|
|
9478
9550
|
* Reads the `shallow` file in the Git repository and returns a set of object IDs (OIDs).
|
|
@@ -9483,10 +9555,9 @@ class GitShallowManager {
|
|
|
9483
9555
|
* @returns {Promise<Set<string>>} - A set of shallow object IDs.
|
|
9484
9556
|
*/
|
|
9485
9557
|
static async read({ fs, gitdir }) {
|
|
9486
|
-
if (lock$3 === null) lock$3 = new AsyncLock();
|
|
9487
9558
|
const filepath = join(gitdir, 'shallow');
|
|
9488
9559
|
const oids = new Set();
|
|
9489
|
-
await
|
|
9560
|
+
await acquireLock(filepath, async function () {
|
|
9490
9561
|
const text = await fs.read(filepath, { encoding: 'utf8' });
|
|
9491
9562
|
if (text === null) return oids // no file
|
|
9492
9563
|
if (text.trim() === '') return oids // empty file
|
|
@@ -9509,18 +9580,17 @@ class GitShallowManager {
|
|
|
9509
9580
|
* @returns {Promise<void>}
|
|
9510
9581
|
*/
|
|
9511
9582
|
static async write({ fs, gitdir, oids }) {
|
|
9512
|
-
if (lock$3 === null) lock$3 = new AsyncLock();
|
|
9513
9583
|
const filepath = join(gitdir, 'shallow');
|
|
9514
9584
|
if (oids.size > 0) {
|
|
9515
9585
|
const text = [...oids].join('\n') + '\n';
|
|
9516
|
-
await
|
|
9586
|
+
await acquireLock(filepath, async function () {
|
|
9517
9587
|
await fs.write(filepath, text, {
|
|
9518
9588
|
encoding: 'utf8',
|
|
9519
9589
|
});
|
|
9520
9590
|
});
|
|
9521
9591
|
} else {
|
|
9522
9592
|
// No shallows
|
|
9523
|
-
await
|
|
9593
|
+
await acquireLock(filepath, async function () {
|
|
9524
9594
|
await fs.rm(filepath);
|
|
9525
9595
|
});
|
|
9526
9596
|
}
|
|
@@ -9617,8 +9687,8 @@ function filterCapabilities(server, client) {
|
|
|
9617
9687
|
|
|
9618
9688
|
const pkg = {
|
|
9619
9689
|
name: 'isomorphic-git',
|
|
9620
|
-
version: '1.41.
|
|
9621
|
-
agent: 'git/isomorphic-git@1.41.
|
|
9690
|
+
version: '1.41.2',
|
|
9691
|
+
agent: 'git/isomorphic-git@1.41.2',
|
|
9622
9692
|
};
|
|
9623
9693
|
|
|
9624
9694
|
class FIFO {
|
|
@@ -15975,7 +16045,7 @@ class GitStashManager {
|
|
|
15975
16045
|
);
|
|
15976
16046
|
const filepath = this.refLogsStashPath;
|
|
15977
16047
|
|
|
15978
|
-
await acquireLock
|
|
16048
|
+
await acquireLock(filepath, async () => {
|
|
15979
16049
|
const appendTo = (await this.fs.exists(filepath))
|
|
15980
16050
|
? await this.fs.read(filepath, 'utf8')
|
|
15981
16051
|
: '';
|
|
@@ -16169,7 +16239,7 @@ async function _stashDrop({ fs, dir, gitdir, refIdx = 0 }) {
|
|
|
16169
16239
|
}
|
|
16170
16240
|
// remove stash ref first
|
|
16171
16241
|
const stashRefPath = stashMgr.refStashPath;
|
|
16172
|
-
await acquireLock
|
|
16242
|
+
await acquireLock(stashRefPath, async () => {
|
|
16173
16243
|
if (await fs.exists(stashRefPath)) {
|
|
16174
16244
|
await fs.rm(stashRefPath);
|
|
16175
16245
|
}
|
|
@@ -16185,7 +16255,7 @@ async function _stashDrop({ fs, dir, gitdir, refIdx = 0 }) {
|
|
|
16185
16255
|
reflogEntries.splice(refIdx, 1);
|
|
16186
16256
|
|
|
16187
16257
|
const stashReflogPath = stashMgr.refLogsStashPath;
|
|
16188
|
-
await acquireLock
|
|
16258
|
+
await acquireLock(stashReflogPath, async () => {
|
|
16189
16259
|
if (reflogEntries.length) {
|
|
16190
16260
|
await fs.write(
|
|
16191
16261
|
stashReflogPath,
|
|
@@ -16211,7 +16281,7 @@ async function _stashClear({ fs, dir, gitdir }) {
|
|
|
16211
16281
|
const stashMgr = new GitStashManager({ fs, dir, gitdir });
|
|
16212
16282
|
const stashRefPath = [stashMgr.refStashPath, stashMgr.refLogsStashPath];
|
|
16213
16283
|
|
|
16214
|
-
await acquireLock
|
|
16284
|
+
await acquireLock(stashRefPath, async () => {
|
|
16215
16285
|
await Promise.all(
|
|
16216
16286
|
stashRefPath.map(async path => {
|
|
16217
16287
|
if (await fs.exists(path)) {
|