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/managers/index.cjs
CHANGED
|
@@ -5,8 +5,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
6
|
|
|
7
7
|
var ignore = _interopDefault(require('ignore'));
|
|
8
|
-
var AsyncLock = _interopDefault(require('async-lock'));
|
|
9
8
|
var Hash = _interopDefault(require('sha.js/sha1.js'));
|
|
9
|
+
var AsyncLock = _interopDefault(require('async-lock'));
|
|
10
10
|
var crc32 = _interopDefault(require('crc-32'));
|
|
11
11
|
var pako = _interopDefault(require('pako'));
|
|
12
12
|
var crypto$1 = require('crypto');
|
|
@@ -1524,10 +1524,43 @@ function compareStats(entry, stats, filemode = true, trustino = true) {
|
|
|
1524
1524
|
return staleness
|
|
1525
1525
|
}
|
|
1526
1526
|
|
|
1527
|
-
//
|
|
1527
|
+
// A single process-wide lock shared by everything that serializes file
|
|
1528
|
+
// operations (the index, refs, the shallow file, blob writes). It is keyed by
|
|
1529
|
+
// path, so unrelated resources never contend. Centralizing it here also means
|
|
1530
|
+
// there is exactly one place to reset it (see `_resetLock`).
|
|
1531
|
+
//
|
|
1532
|
+
// Created lazily (not at module load) so this module has no top-level side
|
|
1533
|
+
// effect and stays tree-shakeable.
|
|
1534
|
+
let lock;
|
|
1528
1535
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1536
|
+
function getLock() {
|
|
1537
|
+
if (lock === undefined) lock = new AsyncLock({ maxPending: Infinity });
|
|
1538
|
+
return lock
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
/**
|
|
1542
|
+
* Run `callback` while holding the shared lock for `key`, then release it.
|
|
1543
|
+
*
|
|
1544
|
+
* @template T
|
|
1545
|
+
* @param {string | string[]} key - Resource key(s) to lock (usually a filepath).
|
|
1546
|
+
* @param {() => (Promise<T> | T)} callback
|
|
1547
|
+
* @returns {Promise<T>}
|
|
1548
|
+
*/
|
|
1549
|
+
function acquireLock(key, callback) {
|
|
1550
|
+
return getLock().acquire(key, callback)
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/**
|
|
1554
|
+
* Discard the shared lock so the next `acquireLock` starts a fresh one. Intended
|
|
1555
|
+
* for test harnesses that run many independent scenarios inside one long-lived
|
|
1556
|
+
* module instance: if a scenario leaves an operation stalled (e.g. a filesystem
|
|
1557
|
+
* that hangs), its still-held lock would otherwise block every later scenario
|
|
1558
|
+
* that touches the same path. Resetting abandons that stalled queue so the next
|
|
1559
|
+
* scenario starts clean. It is a no-op for normal library use.
|
|
1560
|
+
*/
|
|
1561
|
+
function _resetLock() {
|
|
1562
|
+
lock = undefined;
|
|
1563
|
+
}
|
|
1531
1564
|
|
|
1532
1565
|
const IndexCache = Symbol('IndexCache');
|
|
1533
1566
|
|
|
@@ -1598,10 +1631,9 @@ class GitIndexManager {
|
|
|
1598
1631
|
}
|
|
1599
1632
|
|
|
1600
1633
|
const filepath = `${gitdir}/index`;
|
|
1601
|
-
if (lock === null) lock = new AsyncLock({ maxPending: Infinity });
|
|
1602
1634
|
let result;
|
|
1603
1635
|
let unmergedPaths = [];
|
|
1604
|
-
await
|
|
1636
|
+
await acquireLock(filepath, async () => {
|
|
1605
1637
|
// Acquire a file lock while we're reading the index
|
|
1606
1638
|
// to make sure other processes aren't writing to it
|
|
1607
1639
|
// simultaneously, which could result in a corrupted index.
|
|
@@ -1874,13 +1906,6 @@ function assertWritableRef(ref) {
|
|
|
1874
1906
|
}
|
|
1875
1907
|
}
|
|
1876
1908
|
|
|
1877
|
-
let lock$1;
|
|
1878
|
-
|
|
1879
|
-
async function acquireLock(ref, callback) {
|
|
1880
|
-
if (lock$1 === undefined) lock$1 = new AsyncLock();
|
|
1881
|
-
return lock$1.acquire(ref, callback)
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
1909
|
/**
|
|
1885
1910
|
* A class for managing Git references, including reading, writing, deleting, and resolving refs.
|
|
1886
1911
|
*/
|
|
@@ -2485,21 +2510,76 @@ async function collect(iterable) {
|
|
|
2485
2510
|
return result
|
|
2486
2511
|
}
|
|
2487
2512
|
|
|
2513
|
+
// The `@` that ends the credentials is the last one in the authority, and the
|
|
2514
|
+
// scheme is matched case-insensitively: `HTTPS://user:pass@host/x` is a URL
|
|
2515
|
+
// like any other, and leaving the credentials in it is what `fetch` rejects.
|
|
2516
|
+
// The authority ends at the first `/`, `?` or `#`, so an `@` that lives in a
|
|
2517
|
+
// query or a fragment is left where it is.
|
|
2518
|
+
const CREDENTIALS = /^(https?:\/\/)([^/?#]+)@/i;
|
|
2519
|
+
|
|
2488
2520
|
function extractAuthFromUrl(url) {
|
|
2489
2521
|
// For whatever reason, the `fetch` API does not convert credentials embedded in the URL
|
|
2490
2522
|
// into Basic Authentication headers automatically. Instead it throws an error!
|
|
2491
2523
|
// So we must manually parse the URL, rip out the user:password portion if it is present
|
|
2492
2524
|
// and compute the Authorization header.
|
|
2493
|
-
|
|
2494
|
-
let userpass = url.match(/^https?:\/\/([^/]+)@/);
|
|
2525
|
+
const credentials = url.match(CREDENTIALS);
|
|
2495
2526
|
// No credentials, return the url unmodified and an empty auth object
|
|
2496
|
-
if (
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
//
|
|
2500
|
-
|
|
2501
|
-
//
|
|
2502
|
-
return {
|
|
2527
|
+
if (credentials == null) return { url, auth: {} }
|
|
2528
|
+
// Has credentials, return the fetch-safe URL and the parsed credentials.
|
|
2529
|
+
// The credentials are cut out of the original string rather than read back
|
|
2530
|
+
// off the parsed URL: serializing that one would also drop an explicit
|
|
2531
|
+
// `:443` and append a slash to a URL that has no path, and this return value
|
|
2532
|
+
// is what the request goes out against.
|
|
2533
|
+
return {
|
|
2534
|
+
url: url.replace(CREDENTIALS, '$1'),
|
|
2535
|
+
auth: parseUserinfo(url, credentials[2]),
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
function parseUserinfo(url, userpass) {
|
|
2540
|
+
// `URL` splits the two halves the way the platform does, so the first colon
|
|
2541
|
+
// separates them and any later one stays in the password. Only the split is
|
|
2542
|
+
// taken from it, for the reason above.
|
|
2543
|
+
const parsed = parseUrl(url);
|
|
2544
|
+
// A password is absent, not empty, when no colon was written at all. `URL`
|
|
2545
|
+
// reports `''` for both, and the difference is worth keeping.
|
|
2546
|
+
const hasPassword = userpass.indexOf(':') !== -1;
|
|
2547
|
+
|
|
2548
|
+
if (parsed !== null) {
|
|
2549
|
+
return {
|
|
2550
|
+
username: decodeUserinfo(parsed.username),
|
|
2551
|
+
password: hasPassword ? decodeUserinfo(parsed.password) : undefined,
|
|
2552
|
+
}
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
// No `URL` to parse with, or it rejected a string the expression above
|
|
2556
|
+
// accepted. Split on the first colon by hand, without the percent-decoding.
|
|
2557
|
+
const separatorIndex = userpass.indexOf(':');
|
|
2558
|
+
return {
|
|
2559
|
+
username: hasPassword ? userpass.slice(0, separatorIndex) : userpass,
|
|
2560
|
+
password: hasPassword ? userpass.slice(separatorIndex + 1) : undefined,
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
function parseUrl(url) {
|
|
2565
|
+
if (typeof URL !== 'function') return null
|
|
2566
|
+
try {
|
|
2567
|
+
return new URL(url)
|
|
2568
|
+
} catch (_) {
|
|
2569
|
+
return null
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
// `URL` hands back the userinfo still percent-encoded, so `p:ss` arrives as
|
|
2574
|
+
// `p%3Ass` and has to be decoded before it reaches the Authorization header. A
|
|
2575
|
+
// lone `%` is not something the parser encodes, and it makes the decode throw,
|
|
2576
|
+
// so the raw value stands in whenever the decode fails.
|
|
2577
|
+
function decodeUserinfo(value) {
|
|
2578
|
+
try {
|
|
2579
|
+
return decodeURIComponent(value)
|
|
2580
|
+
} catch (_) {
|
|
2581
|
+
return value
|
|
2582
|
+
}
|
|
2503
2583
|
}
|
|
2504
2584
|
|
|
2505
2585
|
class EmptyServerResponseError extends BaseError {
|
|
@@ -3191,8 +3271,6 @@ function parseRemoteUrl({ url }) {
|
|
|
3191
3271
|
}
|
|
3192
3272
|
}
|
|
3193
3273
|
|
|
3194
|
-
let lock$2 = null;
|
|
3195
|
-
|
|
3196
3274
|
class GitShallowManager {
|
|
3197
3275
|
/**
|
|
3198
3276
|
* Reads the `shallow` file in the Git repository and returns a set of object IDs (OIDs).
|
|
@@ -3203,10 +3281,9 @@ class GitShallowManager {
|
|
|
3203
3281
|
* @returns {Promise<Set<string>>} - A set of shallow object IDs.
|
|
3204
3282
|
*/
|
|
3205
3283
|
static async read({ fs, gitdir }) {
|
|
3206
|
-
if (lock$2 === null) lock$2 = new AsyncLock();
|
|
3207
3284
|
const filepath = join(gitdir, 'shallow');
|
|
3208
3285
|
const oids = new Set();
|
|
3209
|
-
await
|
|
3286
|
+
await acquireLock(filepath, async function () {
|
|
3210
3287
|
const text = await fs.read(filepath, { encoding: 'utf8' });
|
|
3211
3288
|
if (text === null) return oids // no file
|
|
3212
3289
|
if (text.trim() === '') return oids // empty file
|
|
@@ -3229,18 +3306,17 @@ class GitShallowManager {
|
|
|
3229
3306
|
* @returns {Promise<void>}
|
|
3230
3307
|
*/
|
|
3231
3308
|
static async write({ fs, gitdir, oids }) {
|
|
3232
|
-
if (lock$2 === null) lock$2 = new AsyncLock();
|
|
3233
3309
|
const filepath = join(gitdir, 'shallow');
|
|
3234
3310
|
if (oids.size > 0) {
|
|
3235
3311
|
const text = [...oids].join('\n') + '\n';
|
|
3236
|
-
await
|
|
3312
|
+
await acquireLock(filepath, async function () {
|
|
3237
3313
|
await fs.write(filepath, text, {
|
|
3238
3314
|
encoding: 'utf8',
|
|
3239
3315
|
});
|
|
3240
3316
|
});
|
|
3241
3317
|
} else {
|
|
3242
3318
|
// No shallows
|
|
3243
|
-
await
|
|
3319
|
+
await acquireLock(filepath, async function () {
|
|
3244
3320
|
await fs.rm(filepath);
|
|
3245
3321
|
});
|
|
3246
3322
|
}
|
|
@@ -5958,12 +6034,6 @@ const _TreeMap = {
|
|
|
5958
6034
|
workdir: WORKDIR,
|
|
5959
6035
|
};
|
|
5960
6036
|
|
|
5961
|
-
let lock$3;
|
|
5962
|
-
async function acquireLock$1(ref, callback) {
|
|
5963
|
-
if (lock$3 === undefined) lock$3 = new AsyncLock();
|
|
5964
|
-
return lock$3.acquire(ref, callback)
|
|
5965
|
-
}
|
|
5966
|
-
|
|
5967
6037
|
// make sure filepath, blob type and blob object (from loose objects) plus oid are in sync and valid
|
|
5968
6038
|
async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
5969
6039
|
const currentFilepath = join(dir, filepath);
|
|
@@ -5980,7 +6050,7 @@ async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
|
5980
6050
|
: undefined;
|
|
5981
6051
|
let retOid = objContent ? oid : undefined;
|
|
5982
6052
|
if (!objContent) {
|
|
5983
|
-
await acquireLock
|
|
6053
|
+
await acquireLock(currentFilepath, async () => {
|
|
5984
6054
|
const object = stats.isSymbolicLink()
|
|
5985
6055
|
? await fs.readlink(currentFilepath).then(posixifyPathBuffer)
|
|
5986
6056
|
: await fs.read(currentFilepath);
|
|
@@ -6195,7 +6265,7 @@ async function applyTreeChanges({
|
|
|
6195
6265
|
});
|
|
6196
6266
|
|
|
6197
6267
|
// apply the changes to work dir
|
|
6198
|
-
await acquireLock
|
|
6268
|
+
await acquireLock(gitdir, async () => {
|
|
6199
6269
|
for (const op of ops) {
|
|
6200
6270
|
const currentFilepath = join(dir, op.filepath);
|
|
6201
6271
|
switch (op.method) {
|
|
@@ -6426,7 +6496,7 @@ class GitStashManager {
|
|
|
6426
6496
|
);
|
|
6427
6497
|
const filepath = this.refLogsStashPath;
|
|
6428
6498
|
|
|
6429
|
-
await acquireLock
|
|
6499
|
+
await acquireLock(filepath, async () => {
|
|
6430
6500
|
const appendTo = (await this.fs.exists(filepath))
|
|
6431
6501
|
? await this.fs.read(filepath, 'utf8')
|
|
6432
6502
|
: '';
|
package/managers/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import ignore from 'ignore';
|
|
2
|
-
import AsyncLock from 'async-lock';
|
|
3
2
|
import Hash from 'sha.js/sha1.js';
|
|
3
|
+
import AsyncLock from 'async-lock';
|
|
4
4
|
import crc32 from 'crc-32';
|
|
5
5
|
import pako from 'pako';
|
|
6
6
|
|
|
@@ -1517,10 +1517,43 @@ function compareStats(entry, stats, filemode = true, trustino = true) {
|
|
|
1517
1517
|
return staleness
|
|
1518
1518
|
}
|
|
1519
1519
|
|
|
1520
|
-
//
|
|
1520
|
+
// A single process-wide lock shared by everything that serializes file
|
|
1521
|
+
// operations (the index, refs, the shallow file, blob writes). It is keyed by
|
|
1522
|
+
// path, so unrelated resources never contend. Centralizing it here also means
|
|
1523
|
+
// there is exactly one place to reset it (see `_resetLock`).
|
|
1524
|
+
//
|
|
1525
|
+
// Created lazily (not at module load) so this module has no top-level side
|
|
1526
|
+
// effect and stays tree-shakeable.
|
|
1527
|
+
let lock;
|
|
1521
1528
|
|
|
1522
|
-
|
|
1523
|
-
|
|
1529
|
+
function getLock() {
|
|
1530
|
+
if (lock === undefined) lock = new AsyncLock({ maxPending: Infinity });
|
|
1531
|
+
return lock
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
/**
|
|
1535
|
+
* Run `callback` while holding the shared lock for `key`, then release it.
|
|
1536
|
+
*
|
|
1537
|
+
* @template T
|
|
1538
|
+
* @param {string | string[]} key - Resource key(s) to lock (usually a filepath).
|
|
1539
|
+
* @param {() => (Promise<T> | T)} callback
|
|
1540
|
+
* @returns {Promise<T>}
|
|
1541
|
+
*/
|
|
1542
|
+
function acquireLock(key, callback) {
|
|
1543
|
+
return getLock().acquire(key, callback)
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
/**
|
|
1547
|
+
* Discard the shared lock so the next `acquireLock` starts a fresh one. Intended
|
|
1548
|
+
* for test harnesses that run many independent scenarios inside one long-lived
|
|
1549
|
+
* module instance: if a scenario leaves an operation stalled (e.g. a filesystem
|
|
1550
|
+
* that hangs), its still-held lock would otherwise block every later scenario
|
|
1551
|
+
* that touches the same path. Resetting abandons that stalled queue so the next
|
|
1552
|
+
* scenario starts clean. It is a no-op for normal library use.
|
|
1553
|
+
*/
|
|
1554
|
+
function _resetLock() {
|
|
1555
|
+
lock = undefined;
|
|
1556
|
+
}
|
|
1524
1557
|
|
|
1525
1558
|
const IndexCache = Symbol('IndexCache');
|
|
1526
1559
|
|
|
@@ -1591,10 +1624,9 @@ class GitIndexManager {
|
|
|
1591
1624
|
}
|
|
1592
1625
|
|
|
1593
1626
|
const filepath = `${gitdir}/index`;
|
|
1594
|
-
if (lock === null) lock = new AsyncLock({ maxPending: Infinity });
|
|
1595
1627
|
let result;
|
|
1596
1628
|
let unmergedPaths = [];
|
|
1597
|
-
await
|
|
1629
|
+
await acquireLock(filepath, async () => {
|
|
1598
1630
|
// Acquire a file lock while we're reading the index
|
|
1599
1631
|
// to make sure other processes aren't writing to it
|
|
1600
1632
|
// simultaneously, which could result in a corrupted index.
|
|
@@ -1867,13 +1899,6 @@ function assertWritableRef(ref) {
|
|
|
1867
1899
|
}
|
|
1868
1900
|
}
|
|
1869
1901
|
|
|
1870
|
-
let lock$1;
|
|
1871
|
-
|
|
1872
|
-
async function acquireLock(ref, callback) {
|
|
1873
|
-
if (lock$1 === undefined) lock$1 = new AsyncLock();
|
|
1874
|
-
return lock$1.acquire(ref, callback)
|
|
1875
|
-
}
|
|
1876
|
-
|
|
1877
1902
|
/**
|
|
1878
1903
|
* A class for managing Git references, including reading, writing, deleting, and resolving refs.
|
|
1879
1904
|
*/
|
|
@@ -2478,21 +2503,76 @@ async function collect(iterable) {
|
|
|
2478
2503
|
return result
|
|
2479
2504
|
}
|
|
2480
2505
|
|
|
2506
|
+
// The `@` that ends the credentials is the last one in the authority, and the
|
|
2507
|
+
// scheme is matched case-insensitively: `HTTPS://user:pass@host/x` is a URL
|
|
2508
|
+
// like any other, and leaving the credentials in it is what `fetch` rejects.
|
|
2509
|
+
// The authority ends at the first `/`, `?` or `#`, so an `@` that lives in a
|
|
2510
|
+
// query or a fragment is left where it is.
|
|
2511
|
+
const CREDENTIALS = /^(https?:\/\/)([^/?#]+)@/i;
|
|
2512
|
+
|
|
2481
2513
|
function extractAuthFromUrl(url) {
|
|
2482
2514
|
// For whatever reason, the `fetch` API does not convert credentials embedded in the URL
|
|
2483
2515
|
// into Basic Authentication headers automatically. Instead it throws an error!
|
|
2484
2516
|
// So we must manually parse the URL, rip out the user:password portion if it is present
|
|
2485
2517
|
// and compute the Authorization header.
|
|
2486
|
-
|
|
2487
|
-
let userpass = url.match(/^https?:\/\/([^/]+)@/);
|
|
2518
|
+
const credentials = url.match(CREDENTIALS);
|
|
2488
2519
|
// No credentials, return the url unmodified and an empty auth object
|
|
2489
|
-
if (
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
//
|
|
2493
|
-
|
|
2494
|
-
//
|
|
2495
|
-
return {
|
|
2520
|
+
if (credentials == null) return { url, auth: {} }
|
|
2521
|
+
// Has credentials, return the fetch-safe URL and the parsed credentials.
|
|
2522
|
+
// The credentials are cut out of the original string rather than read back
|
|
2523
|
+
// off the parsed URL: serializing that one would also drop an explicit
|
|
2524
|
+
// `:443` and append a slash to a URL that has no path, and this return value
|
|
2525
|
+
// is what the request goes out against.
|
|
2526
|
+
return {
|
|
2527
|
+
url: url.replace(CREDENTIALS, '$1'),
|
|
2528
|
+
auth: parseUserinfo(url, credentials[2]),
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
function parseUserinfo(url, userpass) {
|
|
2533
|
+
// `URL` splits the two halves the way the platform does, so the first colon
|
|
2534
|
+
// separates them and any later one stays in the password. Only the split is
|
|
2535
|
+
// taken from it, for the reason above.
|
|
2536
|
+
const parsed = parseUrl(url);
|
|
2537
|
+
// A password is absent, not empty, when no colon was written at all. `URL`
|
|
2538
|
+
// reports `''` for both, and the difference is worth keeping.
|
|
2539
|
+
const hasPassword = userpass.indexOf(':') !== -1;
|
|
2540
|
+
|
|
2541
|
+
if (parsed !== null) {
|
|
2542
|
+
return {
|
|
2543
|
+
username: decodeUserinfo(parsed.username),
|
|
2544
|
+
password: hasPassword ? decodeUserinfo(parsed.password) : undefined,
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
// No `URL` to parse with, or it rejected a string the expression above
|
|
2549
|
+
// accepted. Split on the first colon by hand, without the percent-decoding.
|
|
2550
|
+
const separatorIndex = userpass.indexOf(':');
|
|
2551
|
+
return {
|
|
2552
|
+
username: hasPassword ? userpass.slice(0, separatorIndex) : userpass,
|
|
2553
|
+
password: hasPassword ? userpass.slice(separatorIndex + 1) : undefined,
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
function parseUrl(url) {
|
|
2558
|
+
if (typeof URL !== 'function') return null
|
|
2559
|
+
try {
|
|
2560
|
+
return new URL(url)
|
|
2561
|
+
} catch (_) {
|
|
2562
|
+
return null
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
// `URL` hands back the userinfo still percent-encoded, so `p:ss` arrives as
|
|
2567
|
+
// `p%3Ass` and has to be decoded before it reaches the Authorization header. A
|
|
2568
|
+
// lone `%` is not something the parser encodes, and it makes the decode throw,
|
|
2569
|
+
// so the raw value stands in whenever the decode fails.
|
|
2570
|
+
function decodeUserinfo(value) {
|
|
2571
|
+
try {
|
|
2572
|
+
return decodeURIComponent(value)
|
|
2573
|
+
} catch (_) {
|
|
2574
|
+
return value
|
|
2575
|
+
}
|
|
2496
2576
|
}
|
|
2497
2577
|
|
|
2498
2578
|
class EmptyServerResponseError extends BaseError {
|
|
@@ -3184,8 +3264,6 @@ function parseRemoteUrl({ url }) {
|
|
|
3184
3264
|
}
|
|
3185
3265
|
}
|
|
3186
3266
|
|
|
3187
|
-
let lock$2 = null;
|
|
3188
|
-
|
|
3189
3267
|
class GitShallowManager {
|
|
3190
3268
|
/**
|
|
3191
3269
|
* Reads the `shallow` file in the Git repository and returns a set of object IDs (OIDs).
|
|
@@ -3196,10 +3274,9 @@ class GitShallowManager {
|
|
|
3196
3274
|
* @returns {Promise<Set<string>>} - A set of shallow object IDs.
|
|
3197
3275
|
*/
|
|
3198
3276
|
static async read({ fs, gitdir }) {
|
|
3199
|
-
if (lock$2 === null) lock$2 = new AsyncLock();
|
|
3200
3277
|
const filepath = join(gitdir, 'shallow');
|
|
3201
3278
|
const oids = new Set();
|
|
3202
|
-
await
|
|
3279
|
+
await acquireLock(filepath, async function () {
|
|
3203
3280
|
const text = await fs.read(filepath, { encoding: 'utf8' });
|
|
3204
3281
|
if (text === null) return oids // no file
|
|
3205
3282
|
if (text.trim() === '') return oids // empty file
|
|
@@ -3222,18 +3299,17 @@ class GitShallowManager {
|
|
|
3222
3299
|
* @returns {Promise<void>}
|
|
3223
3300
|
*/
|
|
3224
3301
|
static async write({ fs, gitdir, oids }) {
|
|
3225
|
-
if (lock$2 === null) lock$2 = new AsyncLock();
|
|
3226
3302
|
const filepath = join(gitdir, 'shallow');
|
|
3227
3303
|
if (oids.size > 0) {
|
|
3228
3304
|
const text = [...oids].join('\n') + '\n';
|
|
3229
|
-
await
|
|
3305
|
+
await acquireLock(filepath, async function () {
|
|
3230
3306
|
await fs.write(filepath, text, {
|
|
3231
3307
|
encoding: 'utf8',
|
|
3232
3308
|
});
|
|
3233
3309
|
});
|
|
3234
3310
|
} else {
|
|
3235
3311
|
// No shallows
|
|
3236
|
-
await
|
|
3312
|
+
await acquireLock(filepath, async function () {
|
|
3237
3313
|
await fs.rm(filepath);
|
|
3238
3314
|
});
|
|
3239
3315
|
}
|
|
@@ -5945,12 +6021,6 @@ const _TreeMap = {
|
|
|
5945
6021
|
workdir: WORKDIR,
|
|
5946
6022
|
};
|
|
5947
6023
|
|
|
5948
|
-
let lock$3;
|
|
5949
|
-
async function acquireLock$1(ref, callback) {
|
|
5950
|
-
if (lock$3 === undefined) lock$3 = new AsyncLock();
|
|
5951
|
-
return lock$3.acquire(ref, callback)
|
|
5952
|
-
}
|
|
5953
|
-
|
|
5954
6024
|
// make sure filepath, blob type and blob object (from loose objects) plus oid are in sync and valid
|
|
5955
6025
|
async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
5956
6026
|
const currentFilepath = join(dir, filepath);
|
|
@@ -5967,7 +6037,7 @@ async function checkAndWriteBlob(fs, gitdir, dir, filepath, oid = null) {
|
|
|
5967
6037
|
: undefined;
|
|
5968
6038
|
let retOid = objContent ? oid : undefined;
|
|
5969
6039
|
if (!objContent) {
|
|
5970
|
-
await acquireLock
|
|
6040
|
+
await acquireLock(currentFilepath, async () => {
|
|
5971
6041
|
const object = stats.isSymbolicLink()
|
|
5972
6042
|
? await fs.readlink(currentFilepath).then(posixifyPathBuffer)
|
|
5973
6043
|
: await fs.read(currentFilepath);
|
|
@@ -6182,7 +6252,7 @@ async function applyTreeChanges({
|
|
|
6182
6252
|
});
|
|
6183
6253
|
|
|
6184
6254
|
// apply the changes to work dir
|
|
6185
|
-
await acquireLock
|
|
6255
|
+
await acquireLock(gitdir, async () => {
|
|
6186
6256
|
for (const op of ops) {
|
|
6187
6257
|
const currentFilepath = join(dir, op.filepath);
|
|
6188
6258
|
switch (op.method) {
|
|
@@ -6413,7 +6483,7 @@ class GitStashManager {
|
|
|
6413
6483
|
);
|
|
6414
6484
|
const filepath = this.refLogsStashPath;
|
|
6415
6485
|
|
|
6416
|
-
await acquireLock
|
|
6486
|
+
await acquireLock(filepath, async () => {
|
|
6417
6487
|
const appendTo = (await this.fs.exists(filepath))
|
|
6418
6488
|
? await this.fs.read(filepath, 'utf8')
|
|
6419
6489
|
: '';
|