isomorphic-git 1.30.2 → 1.31.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/index.js CHANGED
@@ -6285,6 +6285,8 @@ const worthWalking = (filepath, root) => {
6285
6285
  * @param {boolean} [args.dryRun]
6286
6286
  * @param {boolean} [args.force]
6287
6287
  * @param {boolean} [args.track]
6288
+ * @param {boolean} [args.nonBlocking]
6289
+ * @param {number} [args.batchSize]
6288
6290
  *
6289
6291
  * @returns {Promise<void>} Resolves successfully when filesystem operations are complete
6290
6292
  *
@@ -6304,6 +6306,8 @@ async function _checkout({
6304
6306
  dryRun,
6305
6307
  force,
6306
6308
  track = true,
6309
+ nonBlocking = false,
6310
+ batchSize = 100,
6307
6311
  }) {
6308
6312
  // oldOid is defined only if onPostCheckout hook is attached
6309
6313
  let oldOid;
@@ -6476,72 +6480,122 @@ async function _checkout({
6476
6480
  })
6477
6481
  );
6478
6482
 
6479
- await GitIndexManager.acquire({ fs, gitdir, cache }, async function(index) {
6480
- await Promise.all(
6481
- ops
6482
- .filter(
6483
- ([method]) =>
6484
- method === 'create' ||
6485
- method === 'create-index' ||
6486
- method === 'update' ||
6487
- method === 'mkdir-index'
6488
- )
6489
- .map(async function([method, fullpath, oid, mode, chmod]) {
6490
- const filepath = `${dir}/${fullpath}`;
6491
- try {
6492
- if (method !== 'create-index' && method !== 'mkdir-index') {
6493
- const { object } = await _readObject({ fs, cache, gitdir, oid });
6494
- if (chmod) {
6495
- // Note: the mode option of fs.write only works when creating files,
6496
- // not updating them. Since the `fs` plugin doesn't expose `chmod` this
6497
- // is our only option.
6498
- await fs.rm(filepath);
6499
- }
6500
- if (mode === 0o100644) {
6501
- // regular file
6502
- await fs.write(filepath, object);
6503
- } else if (mode === 0o100755) {
6504
- // executable file
6505
- await fs.write(filepath, object, { mode: 0o777 });
6506
- } else if (mode === 0o120000) {
6507
- // symlink
6508
- await fs.writelink(filepath, object);
6509
- } else {
6510
- throw new InternalError(
6511
- `Invalid mode 0o${mode.toString(8)} detected in blob ${oid}`
6512
- )
6513
- }
6514
- }
6483
+ if (nonBlocking) {
6484
+ // Filter eligible operations first
6485
+ const eligibleOps = ops.filter(
6486
+ ([method]) =>
6487
+ method === 'create' ||
6488
+ method === 'create-index' ||
6489
+ method === 'update' ||
6490
+ method === 'mkdir-index'
6491
+ );
6515
6492
 
6516
- const stats = await fs.lstat(filepath);
6517
- // We can't trust the executable bit returned by lstat on Windows,
6518
- // so we need to preserve this value from the TREE.
6519
- // TODO: Figure out how git handles this internally.
6520
- if (mode === 0o100755) {
6521
- stats.mode = 0o755;
6522
- }
6523
- // Submodules are present in the git index but use a unique mode different from trees
6524
- if (method === 'mkdir-index') {
6525
- stats.mode = 0o160000;
6526
- }
6527
- index.insert({
6528
- filepath: fullpath,
6529
- stats,
6530
- oid,
6531
- });
6532
- if (onProgress) {
6533
- await onProgress({
6534
- phase: 'Updating workdir',
6535
- loaded: ++count,
6536
- total,
6537
- });
6538
- }
6539
- } catch (e) {
6540
- console.log(e);
6541
- }
6542
- })
6493
+ const updateWorkingDirResults = await batchAllSettled(
6494
+ 'Update Working Dir',
6495
+ eligibleOps.map(([method, fullpath, oid, mode, chmod]) => () =>
6496
+ updateWorkingDir({ fs, cache, gitdir, dir }, [
6497
+ method,
6498
+ fullpath,
6499
+ oid,
6500
+ mode,
6501
+ chmod,
6502
+ ])
6503
+ ),
6504
+ onProgress,
6505
+ batchSize
6543
6506
  );
6544
- });
6507
+
6508
+ await GitIndexManager.acquire(
6509
+ { fs, gitdir, cache, allowUnmerged: true },
6510
+ async function(index) {
6511
+ await batchAllSettled(
6512
+ 'Update Index',
6513
+ updateWorkingDirResults.map(([fullpath, oid, stats]) => () =>
6514
+ updateIndex({ index, fullpath, oid, stats })
6515
+ ),
6516
+ onProgress,
6517
+ batchSize
6518
+ );
6519
+ }
6520
+ );
6521
+ } else {
6522
+ await GitIndexManager.acquire(
6523
+ { fs, gitdir, cache, allowUnmerged: true },
6524
+ async function(index) {
6525
+ await Promise.all(
6526
+ ops
6527
+ .filter(
6528
+ ([method]) =>
6529
+ method === 'create' ||
6530
+ method === 'create-index' ||
6531
+ method === 'update' ||
6532
+ method === 'mkdir-index'
6533
+ )
6534
+ .map(async function([method, fullpath, oid, mode, chmod]) {
6535
+ const filepath = `${dir}/${fullpath}`;
6536
+ try {
6537
+ if (method !== 'create-index' && method !== 'mkdir-index') {
6538
+ const { object } = await _readObject({
6539
+ fs,
6540
+ cache,
6541
+ gitdir,
6542
+ oid,
6543
+ });
6544
+ if (chmod) {
6545
+ // Note: the mode option of fs.write only works when creating files,
6546
+ // not updating them. Since the `fs` plugin doesn't expose `chmod` this
6547
+ // is our only option.
6548
+ await fs.rm(filepath);
6549
+ }
6550
+ if (mode === 0o100644) {
6551
+ // regular file
6552
+ await fs.write(filepath, object);
6553
+ } else if (mode === 0o100755) {
6554
+ // executable file
6555
+ await fs.write(filepath, object, { mode: 0o777 });
6556
+ } else if (mode === 0o120000) {
6557
+ // symlink
6558
+ await fs.writelink(filepath, object);
6559
+ } else {
6560
+ throw new InternalError(
6561
+ `Invalid mode 0o${mode.toString(
6562
+ 8
6563
+ )} detected in blob ${oid}`
6564
+ )
6565
+ }
6566
+ }
6567
+
6568
+ const stats = await fs.lstat(filepath);
6569
+ // We can't trust the executable bit returned by lstat on Windows,
6570
+ // so we need to preserve this value from the TREE.
6571
+ // TODO: Figure out how git handles this internally.
6572
+ if (mode === 0o100755) {
6573
+ stats.mode = 0o755;
6574
+ }
6575
+ // Submodules are present in the git index but use a unique mode different from trees
6576
+ if (method === 'mkdir-index') {
6577
+ stats.mode = 0o160000;
6578
+ }
6579
+ index.insert({
6580
+ filepath: fullpath,
6581
+ stats,
6582
+ oid,
6583
+ });
6584
+ if (onProgress) {
6585
+ await onProgress({
6586
+ phase: 'Updating workdir',
6587
+ loaded: ++count,
6588
+ total,
6589
+ });
6590
+ }
6591
+ } catch (e) {
6592
+ console.log(e);
6593
+ }
6594
+ })
6595
+ );
6596
+ }
6597
+ );
6598
+ }
6545
6599
 
6546
6600
  if (onPostCheckout) {
6547
6601
  await onPostCheckout({
@@ -6859,6 +6913,78 @@ async function analyze({
6859
6913
  })
6860
6914
  }
6861
6915
 
6916
+ async function updateIndex({ index, fullpath, stats, oid }) {
6917
+ try {
6918
+ index.insert({
6919
+ filepath: fullpath,
6920
+ stats,
6921
+ oid,
6922
+ });
6923
+ } catch (e) {
6924
+ console.warn(`Error inserting ${fullpath} into index:`, e);
6925
+ }
6926
+ }
6927
+ async function updateWorkingDir(
6928
+ { fs, cache, gitdir, dir },
6929
+ [method, fullpath, oid, mode, chmod]
6930
+ ) {
6931
+ const filepath = `${dir}/${fullpath}`;
6932
+ if (method !== 'create-index' && method !== 'mkdir-index') {
6933
+ const { object } = await _readObject({ fs, cache, gitdir, oid });
6934
+ if (chmod) {
6935
+ await fs.rm(filepath);
6936
+ }
6937
+ if (mode === 0o100644) {
6938
+ // regular file
6939
+ await fs.write(filepath, object);
6940
+ } else if (mode === 0o100755) {
6941
+ // executable file
6942
+ await fs.write(filepath, object, { mode: 0o777 });
6943
+ } else if (mode === 0o120000) {
6944
+ // symlink
6945
+ await fs.writelink(filepath, object);
6946
+ } else {
6947
+ throw new InternalError(
6948
+ `Invalid mode 0o${mode.toString(8)} detected in blob ${oid}`
6949
+ )
6950
+ }
6951
+ }
6952
+ const stats = await fs.lstat(filepath);
6953
+ if (mode === 0o100755) {
6954
+ stats.mode = 0o755;
6955
+ }
6956
+ if (method === 'mkdir-index') {
6957
+ stats.mode = 0o160000;
6958
+ }
6959
+ return [fullpath, oid, stats]
6960
+ }
6961
+
6962
+ async function batchAllSettled(operationName, tasks, onProgress, batchSize) {
6963
+ const results = [];
6964
+ try {
6965
+ for (let i = 0; i < tasks.length; i += batchSize) {
6966
+ const batch = tasks.slice(i, i + batchSize).map(task => task());
6967
+ const batchResults = await Promise.allSettled(batch);
6968
+ batchResults.forEach(result => {
6969
+ if (result.status === 'fulfilled') results.push(result.value);
6970
+ });
6971
+ if (onProgress) {
6972
+ await onProgress({
6973
+ phase: 'Updating workdir',
6974
+ loaded: i + batch.length,
6975
+ total: tasks.length,
6976
+ });
6977
+ }
6978
+ }
6979
+
6980
+ return results
6981
+ } catch (error) {
6982
+ console.error(`Error during ${operationName}: ${error}`);
6983
+ }
6984
+
6985
+ return results
6986
+ }
6987
+
6862
6988
  // @ts-check
6863
6989
 
6864
6990
  /**
@@ -6881,6 +7007,8 @@ async function analyze({
6881
7007
  * @param {boolean} [args.force = false] - If true, conflicts will be ignored and files will be overwritten regardless of local changes.
6882
7008
  * @param {boolean} [args.track = true] - If false, will not set the remote branch tracking information. Defaults to true.
6883
7009
  * @param {object} [args.cache] - a [cache](cache.md) object
7010
+ * @param {boolean} [args.nonBlocking = false] - If true, will use non-blocking file system operations to allow for better performance in certain environments (For example, in Browsers)
7011
+ * @param {number} [args.batchSize = 100] - If args.nonBlocking is true, batchSize is the number of files to process at a time avoid blocking the executing thread. The default value of 100 is a good starting point.
6884
7012
  *
6885
7013
  * @returns {Promise<void>} Resolves successfully when filesystem operations are complete
6886
7014
  *
@@ -6930,6 +7058,8 @@ async function checkout({
6930
7058
  force = false,
6931
7059
  track = true,
6932
7060
  cache = {},
7061
+ nonBlocking = false,
7062
+ batchSize = 100,
6933
7063
  }) {
6934
7064
  try {
6935
7065
  assertParameter('fs', fs);
@@ -6952,6 +7082,8 @@ async function checkout({
6952
7082
  dryRun,
6953
7083
  force,
6954
7084
  track,
7085
+ nonBlocking,
7086
+ batchSize,
6955
7087
  })
6956
7088
  } catch (err) {
6957
7089
  err.caller = 'git.checkout';
@@ -7638,8 +7770,8 @@ function filterCapabilities(server, client) {
7638
7770
 
7639
7771
  const pkg = {
7640
7772
  name: 'isomorphic-git',
7641
- version: '1.30.2',
7642
- agent: 'git/isomorphic-git@1.30.2',
7773
+ version: '1.31.0',
7774
+ agent: 'git/isomorphic-git@1.31.0',
7643
7775
  };
7644
7776
 
7645
7777
  class FIFO {
@@ -8394,6 +8526,8 @@ async function _init({
8394
8526
  * @param {string[]} args.exclude
8395
8527
  * @param {boolean} args.relative
8396
8528
  * @param {Object<string, string>} args.headers
8529
+ * @param {boolean} [args.nonBlocking]
8530
+ * @param {number} [args.batchSize]
8397
8531
  *
8398
8532
  * @returns {Promise<void>} Resolves successfully when clone completes
8399
8533
  *
@@ -8422,6 +8556,8 @@ async function _clone({
8422
8556
  noCheckout,
8423
8557
  noTags,
8424
8558
  headers,
8559
+ nonBlocking,
8560
+ batchSize = 100,
8425
8561
  }) {
8426
8562
  try {
8427
8563
  await _init({ fs, gitdir });
@@ -8466,6 +8602,8 @@ async function _clone({
8466
8602
  ref,
8467
8603
  remote,
8468
8604
  noCheckout,
8605
+ nonBlocking,
8606
+ batchSize,
8469
8607
  });
8470
8608
  } catch (err) {
8471
8609
  // Remove partial local repository, see #1283
@@ -8507,6 +8645,8 @@ async function _clone({
8507
8645
  * @param {boolean} [args.relative = false] - Changes the meaning of `depth` to be measured from the current shallow depth rather than from the branch tip.
8508
8646
  * @param {Object<string, string>} [args.headers = {}] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
8509
8647
  * @param {object} [args.cache] - a [cache](cache.md) object
8648
+ * @param {boolean} [args.nonBlocking = false] - if true, checkout will happen non-blockingly (useful for long-running operations blocking the thread in browser environments)
8649
+ * @param {number} [args.batchSize = 100] - If args.nonBlocking is true, batchSize is the number of files to process at a time avoid blocking the executing thread. The default value of 100 is a good starting point.
8510
8650
  *
8511
8651
  * @returns {Promise<void>} Resolves successfully when clone completes
8512
8652
  *
@@ -8547,6 +8687,8 @@ async function clone({
8547
8687
  noTags = false,
8548
8688
  headers = {},
8549
8689
  cache = {},
8690
+ nonBlocking = false,
8691
+ batchSize = 100,
8550
8692
  }) {
8551
8693
  try {
8552
8694
  assertParameter('fs', fs);
@@ -8581,6 +8723,8 @@ async function clone({
8581
8723
  noCheckout,
8582
8724
  noTags,
8583
8725
  headers,
8726
+ nonBlocking,
8727
+ batchSize,
8584
8728
  })
8585
8729
  } catch (err) {
8586
8730
  err.caller = 'git.clone';
@@ -9386,7 +9530,12 @@ async function mergeTree({
9386
9530
  }
9387
9531
 
9388
9532
  // deleted by both
9389
- if (base && !ours && !theirs && (await base.type()) === 'blob') {
9533
+ if (
9534
+ base &&
9535
+ !ours &&
9536
+ !theirs &&
9537
+ ((await base.type()) === 'blob' || (await base.type()) === 'tree')
9538
+ ) {
9390
9539
  return undefined
9391
9540
  }
9392
9541
 
@@ -9410,9 +9559,19 @@ async function mergeTree({
9410
9559
  if (!parent) return
9411
9560
 
9412
9561
  // automatically delete directories if they have been emptied
9413
- if (parent && parent.type === 'tree' && entries.length === 0) return
9562
+ // except for the root directory
9563
+ if (
9564
+ parent &&
9565
+ parent.type === 'tree' &&
9566
+ entries.length === 0 &&
9567
+ parent.path !== '.'
9568
+ )
9569
+ return
9414
9570
 
9415
- if (entries.length > 0) {
9571
+ if (
9572
+ entries.length > 0 ||
9573
+ (parent.path === '.' && entries.length === 0)
9574
+ ) {
9416
9575
  const tree = new GitTree(entries);
9417
9576
  const object = tree.toObject();
9418
9577
  const oid = await _writeObject({
@@ -9676,7 +9835,7 @@ async function _merge({
9676
9835
  );
9677
9836
 
9678
9837
  // Defer throwing error until the index lock is relinquished and index is
9679
- // written to filsesystem
9838
+ // written to filesystem
9680
9839
  if (tree instanceof MergeConflictError) throw tree
9681
9840
 
9682
9841
  if (!message) {
@@ -15291,7 +15450,7 @@ async function tag({
15291
15450
  * oid
15292
15451
  * })
15293
15452
  */
15294
- async function updateIndex({
15453
+ async function updateIndex$1({
15295
15454
  fs: _fs,
15296
15455
  dir,
15297
15456
  gitdir = join(dir, '.git'),
@@ -16161,7 +16320,7 @@ var index = {
16161
16320
  removeNote,
16162
16321
  renameBranch,
16163
16322
  resetIndex,
16164
- updateIndex,
16323
+ updateIndex: updateIndex$1,
16165
16324
  resolveRef,
16166
16325
  status,
16167
16326
  statusMatrix,
@@ -16178,4 +16337,4 @@ var index = {
16178
16337
  };
16179
16338
 
16180
16339
  export default index;
16181
- export { Errors, STAGE, TREE, WORKDIR, abortMerge, add, addNote, addRemote, annotatedTag, branch, checkout, clone, commit, currentBranch, deleteBranch, deleteRef, deleteRemote, deleteTag, expandOid, expandRef, fastForward, fetch, findMergeBase, findRoot, getConfig, getConfigAll, getRemoteInfo, getRemoteInfo2, hashBlob, indexPack, init, isDescendent, isIgnored, listBranches, listFiles, listNotes, listRefs, listRemotes, listServerRefs, listTags, log, merge, packObjects, pull, push, readBlob, readCommit, readNote, readObject, readTag, readTree, remove, removeNote, renameBranch, resetIndex, resolveRef, setConfig, stash, status, statusMatrix, tag, updateIndex, version, walk, writeBlob, writeCommit, writeObject, writeRef, writeTag, writeTree };
16340
+ export { Errors, STAGE, TREE, WORKDIR, abortMerge, add, addNote, addRemote, annotatedTag, branch, checkout, clone, commit, currentBranch, deleteBranch, deleteRef, deleteRemote, deleteTag, expandOid, expandRef, fastForward, fetch, findMergeBase, findRoot, getConfig, getConfigAll, getRemoteInfo, getRemoteInfo2, hashBlob, indexPack, init, isDescendent, isIgnored, listBranches, listFiles, listNotes, listRefs, listRemotes, listServerRefs, listTags, log, merge, packObjects, pull, push, readBlob, readCommit, readNote, readObject, readTag, readTree, remove, removeNote, renameBranch, resetIndex, resolveRef, setConfig, stash, status, statusMatrix, tag, updateIndex$1 as updateIndex, version, walk, writeBlob, writeCommit, writeObject, writeRef, writeTag, writeTree };
@@ -681,7 +681,7 @@ declare namespace index {
681
681
  export { removeNote };
682
682
  export { renameBranch };
683
683
  export { resetIndex };
684
- export { updateIndex };
684
+ export { updateIndex$1 as updateIndex };
685
685
  export { resolveRef };
686
686
  export { status };
687
687
  export { statusMatrix };
@@ -993,6 +993,8 @@ export function branch({ fs, dir, gitdir, ref, object, checkout, force, }: {
993
993
  * @param {boolean} [args.force = false] - If true, conflicts will be ignored and files will be overwritten regardless of local changes.
994
994
  * @param {boolean} [args.track = true] - If false, will not set the remote branch tracking information. Defaults to true.
995
995
  * @param {object} [args.cache] - a [cache](cache.md) object
996
+ * @param {boolean} [args.nonBlocking = false] - If true, will use non-blocking file system operations to allow for better performance in certain environments (For example, in Browsers)
997
+ * @param {number} [args.batchSize = 100] - If args.nonBlocking is true, batchSize is the number of files to process at a time avoid blocking the executing thread. The default value of 100 is a good starting point.
996
998
  *
997
999
  * @returns {Promise<void>} Resolves successfully when filesystem operations are complete
998
1000
  *
@@ -1027,7 +1029,7 @@ export function branch({ fs, dir, gitdir, ref, object, checkout, force, }: {
1027
1029
  * })
1028
1030
  * console.log('done')
1029
1031
  */
1030
- export function checkout({ fs, onProgress, onPostCheckout, dir, gitdir, remote, ref: _ref, filepaths, noCheckout, noUpdateHead, dryRun, force, track, cache, }: {
1032
+ export function checkout({ fs, onProgress, onPostCheckout, dir, gitdir, remote, ref: _ref, filepaths, noCheckout, noUpdateHead, dryRun, force, track, cache, nonBlocking, batchSize, }: {
1031
1033
  fs: FsClient;
1032
1034
  onProgress?: ProgressCallback | undefined;
1033
1035
  onPostCheckout?: PostCheckoutCallback | undefined;
@@ -1042,6 +1044,8 @@ export function checkout({ fs, onProgress, onPostCheckout, dir, gitdir, remote,
1042
1044
  force?: boolean | undefined;
1043
1045
  track?: boolean | undefined;
1044
1046
  cache?: object;
1047
+ nonBlocking?: boolean | undefined;
1048
+ batchSize?: number | undefined;
1045
1049
  }): Promise<void>;
1046
1050
  /**
1047
1051
  * Clone a repository
@@ -1070,6 +1074,8 @@ export function checkout({ fs, onProgress, onPostCheckout, dir, gitdir, remote,
1070
1074
  * @param {boolean} [args.relative = false] - Changes the meaning of `depth` to be measured from the current shallow depth rather than from the branch tip.
1071
1075
  * @param {Object<string, string>} [args.headers = {}] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
1072
1076
  * @param {object} [args.cache] - a [cache](cache.md) object
1077
+ * @param {boolean} [args.nonBlocking = false] - if true, checkout will happen non-blockingly (useful for long-running operations blocking the thread in browser environments)
1078
+ * @param {number} [args.batchSize = 100] - If args.nonBlocking is true, batchSize is the number of files to process at a time avoid blocking the executing thread. The default value of 100 is a good starting point.
1073
1079
  *
1074
1080
  * @returns {Promise<void>} Resolves successfully when clone completes
1075
1081
  *
@@ -1086,7 +1092,7 @@ export function checkout({ fs, onProgress, onPostCheckout, dir, gitdir, remote,
1086
1092
  * console.log('done')
1087
1093
  *
1088
1094
  */
1089
- export function clone({ fs, http, onProgress, onMessage, onAuth, onAuthSuccess, onAuthFailure, onPostCheckout, dir, gitdir, url, corsProxy, ref, remote, depth, since, exclude, relative, singleBranch, noCheckout, noTags, headers, cache, }: {
1095
+ export function clone({ fs, http, onProgress, onMessage, onAuth, onAuthSuccess, onAuthFailure, onPostCheckout, dir, gitdir, url, corsProxy, ref, remote, depth, since, exclude, relative, singleBranch, noCheckout, noTags, headers, cache, nonBlocking, batchSize, }: {
1090
1096
  fs: FsClient;
1091
1097
  http: HttpClient;
1092
1098
  onProgress?: ProgressCallback | undefined;
@@ -1112,6 +1118,8 @@ export function clone({ fs, http, onProgress, onMessage, onAuth, onAuthSuccess,
1112
1118
  [x: string]: string;
1113
1119
  } | undefined;
1114
1120
  cache?: object;
1121
+ nonBlocking?: boolean | undefined;
1122
+ batchSize?: number | undefined;
1115
1123
  }): Promise<void>;
1116
1124
  /**
1117
1125
  * Create a new commit
@@ -3342,7 +3350,7 @@ export function tag({ fs: _fs, dir, gitdir, ref, object, force, }: {
3342
3350
  * oid
3343
3351
  * })
3344
3352
  */
3345
- export function updateIndex({ fs: _fs, dir, gitdir, cache, filepath, oid, mode, add, remove, force, }: {
3353
+ declare function updateIndex$1({ fs: _fs, dir, gitdir, cache, filepath, oid, mode, add, remove, force, }: {
3346
3354
  fs: FsClient;
3347
3355
  dir: string;
3348
3356
  gitdir?: string | undefined;
@@ -4650,3 +4658,4 @@ declare class BaseError extends Error {
4650
4658
  fromJSON(json: any): BaseError;
4651
4659
  get isIsomorphicGitError(): boolean;
4652
4660
  }
4661
+ export { updateIndex$1 as updateIndex };