isomorphic-git 1.12.1 → 1.14.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
@@ -865,7 +865,7 @@ class GitIndexManager {
865
865
  const filepath = `${gitdir}/index`;
866
866
  if (lock === null) lock = new AsyncLock({ maxPending: Infinity });
867
867
  let result;
868
- await lock.acquire(filepath, async function() {
868
+ await lock.acquire(filepath, async () => {
869
869
  // Acquire a file lock while we're reading the index
870
870
  // to make sure other processes aren't writing to it
871
871
  // simultaneously, which could result in a corrupted index.
@@ -885,6 +885,7 @@ class GitIndexManager {
885
885
  index._dirty = false;
886
886
  }
887
887
  });
888
+
888
889
  return result
889
890
  }
890
891
  }
@@ -4016,6 +4017,23 @@ function WORKDIR() {
4016
4017
 
4017
4018
  // @ts-check
4018
4019
 
4020
+ class MultipleGitError extends BaseError {
4021
+ /**
4022
+ * @param {Error[]} errors
4023
+ * @param {string} message
4024
+ */
4025
+ constructor(errors) {
4026
+ super(
4027
+ `There are multiple errors that were thrown by the method. Please refer to the "errors" property to see more`
4028
+ );
4029
+ this.code = this.name = MultipleGitError.code;
4030
+ this.data = { errors };
4031
+ this.errors = errors;
4032
+ }
4033
+ }
4034
+ /** @type {'MultipleGitError'} */
4035
+ MultipleGitError.code = 'MultipleGitError';
4036
+
4019
4037
  // I'm putting this in a Manager because I reckon it could benefit
4020
4038
  // from a LOT of cacheing.
4021
4039
  class GitIgnoreManager {
@@ -4406,12 +4424,6 @@ function assertParameter(name, value) {
4406
4424
  }
4407
4425
  }
4408
4426
 
4409
- function posixifyPathBuffer(buffer) {
4410
- let idx;
4411
- while (~(idx = buffer.indexOf(92))) buffer[idx] = 47;
4412
- return buffer
4413
- }
4414
-
4415
4427
  // @ts-check
4416
4428
 
4417
4429
  /**
@@ -4421,7 +4433,7 @@ function posixifyPathBuffer(buffer) {
4421
4433
  * @param {FsClient} args.fs - a file system implementation
4422
4434
  * @param {string} args.dir - The [working tree](dir-vs-gitdir.md) directory path
4423
4435
  * @param {string} [args.gitdir=join(dir, '.git')] - [required] The [git directory](dir-vs-gitdir.md) path
4424
- * @param {string} args.filepath - The path to the file to add to the index
4436
+ * @param {string|string[]} args.filepath - The path to the file to add to the index
4425
4437
  * @param {object} [args.cache] - a [cache](cache.md) object
4426
4438
  *
4427
4439
  * @returns {Promise<void>} Resolves successfully once the git index has been updated
@@ -4443,11 +4455,11 @@ async function add({
4443
4455
  assertParameter('fs', _fs);
4444
4456
  assertParameter('dir', dir);
4445
4457
  assertParameter('gitdir', gitdir);
4446
- assertParameter('filepath', filepath);
4458
+ assertParameter('filepaths', filepath);
4447
4459
 
4448
4460
  const fs = new FileSystem(_fs);
4449
- await GitIndexManager.acquire({ fs, gitdir, cache }, async function(index) {
4450
- await addToIndex({ dir, gitdir, fs, filepath, index });
4461
+ await GitIndexManager.acquire({ fs, gitdir, cache }, async index => {
4462
+ return addToIndex({ dir, gitdir, fs, filepath, index })
4451
4463
  });
4452
4464
  } catch (err) {
4453
4465
  err.caller = 'git.add';
@@ -4457,29 +4469,56 @@ async function add({
4457
4469
 
4458
4470
  async function addToIndex({ dir, gitdir, fs, filepath, index }) {
4459
4471
  // TODO: Should ignore UNLESS it's already in the index.
4460
- const ignored = await GitIgnoreManager.isIgnored({
4461
- fs,
4462
- dir,
4463
- gitdir,
4464
- filepath,
4472
+ filepath = Array.isArray(filepath) ? filepath : [filepath];
4473
+ const promises = filepath.map(async currentFilepath => {
4474
+ const ignored = await GitIgnoreManager.isIgnored({
4475
+ fs,
4476
+ dir,
4477
+ gitdir,
4478
+ filepath: currentFilepath,
4479
+ });
4480
+ if (ignored) return
4481
+ const stats = await fs.lstat(join(dir, currentFilepath));
4482
+ if (!stats) throw new NotFoundError(currentFilepath)
4483
+
4484
+ if (stats.isDirectory()) {
4485
+ const children = await fs.readdir(join(dir, currentFilepath));
4486
+ const promises = children.map(child =>
4487
+ addToIndex({
4488
+ dir,
4489
+ gitdir,
4490
+ fs,
4491
+ filepath: [join(currentFilepath, child)],
4492
+ index,
4493
+ })
4494
+ );
4495
+ await Promise.all(promises);
4496
+ } else {
4497
+ const object = stats.isSymbolicLink()
4498
+ ? await fs.readlink(join(dir, currentFilepath))
4499
+ : await fs.read(join(dir, currentFilepath));
4500
+ if (object === null) throw new NotFoundError(currentFilepath)
4501
+ const oid = await _writeObject({ fs, gitdir, type: 'blob', object });
4502
+ index.insert({ filepath: currentFilepath, stats, oid });
4503
+ }
4465
4504
  });
4466
- if (ignored) return
4467
- const stats = await fs.lstat(join(dir, filepath));
4468
- if (!stats) throw new NotFoundError(filepath)
4469
- if (stats.isDirectory()) {
4470
- const children = await fs.readdir(join(dir, filepath));
4471
- const promises = children.map(child =>
4472
- addToIndex({ dir, gitdir, fs, filepath: join(filepath, child), index })
4473
- );
4474
- await Promise.all(promises);
4475
- } else {
4476
- const object = stats.isSymbolicLink()
4477
- ? await fs.readlink(join(dir, filepath)).then(posixifyPathBuffer)
4478
- : await fs.read(join(dir, filepath));
4479
- if (object === null) throw new NotFoundError(filepath)
4480
- const oid = await _writeObject({ fs, gitdir, type: 'blob', object });
4481
- index.insert({ filepath, stats, oid });
4505
+
4506
+ const settledPromises = await Promise.allSettled(promises);
4507
+ const rejectedPromises = settledPromises
4508
+ .filter(settle => settle.status === 'rejected')
4509
+ .map(settle => settle.reason);
4510
+ if (rejectedPromises.length > 1) {
4511
+ throw new MultipleGitError(rejectedPromises)
4512
+ }
4513
+ if (rejectedPromises.length === 1) {
4514
+ throw rejectedPromises[0]
4482
4515
  }
4516
+
4517
+ const fulfilledPromises = settledPromises
4518
+ .filter(settle => settle.status === 'fulfilled' && settle.value)
4519
+ .map(settle => settle.value);
4520
+
4521
+ return fulfilledPromises
4483
4522
  }
4484
4523
 
4485
4524
  // @ts-check
@@ -5834,7 +5873,7 @@ async function analyze({
5834
5873
 
5835
5874
  // This is a kind of silly pattern but it worked so well for me in the past
5836
5875
  // and it makes intuitively demonstrating exhaustiveness so *easy*.
5837
- // This checks for the presense and/or absense of each of the 3 entries,
5876
+ // This checks for the presense and/or absence of each of the 3 entries,
5838
5877
  // converts that to a 3-bit binary representation, and then handles
5839
5878
  // every possible combination (2^3 or 8 cases) with a lookup table.
5840
5879
  const key = [!!stage, !!commit, !!workdir].map(Number).join('');
@@ -6867,8 +6906,8 @@ function filterCapabilities(server, client) {
6867
6906
 
6868
6907
  const pkg = {
6869
6908
  name: 'isomorphic-git',
6870
- version: '1.12.1',
6871
- agent: 'git/isomorphic-git@1.12.1',
6909
+ version: '1.14.0',
6910
+ agent: 'git/isomorphic-git@1.14.0',
6872
6911
  };
6873
6912
 
6874
6913
  class FIFO {
@@ -8638,6 +8677,7 @@ async function mergeBlobs({
8638
8677
  * @param {string} args.gitdir
8639
8678
  * @param {string} [args.ours]
8640
8679
  * @param {string} args.theirs
8680
+ * @param {boolean} args.fastForward
8641
8681
  * @param {boolean} args.fastForwardOnly
8642
8682
  * @param {boolean} args.dryRun
8643
8683
  * @param {boolean} args.noUpdateBranch
@@ -8664,6 +8704,7 @@ async function _merge({
8664
8704
  gitdir,
8665
8705
  ours,
8666
8706
  theirs,
8707
+ fastForward = true,
8667
8708
  fastForwardOnly = false,
8668
8709
  dryRun = false,
8669
8710
  noUpdateBranch = false,
@@ -8714,7 +8755,7 @@ async function _merge({
8714
8755
  alreadyMerged: true,
8715
8756
  }
8716
8757
  }
8717
- if (baseOid === ourOid) {
8758
+ if (fastForward && baseOid === ourOid) {
8718
8759
  if (!dryRun && !noUpdateBranch) {
8719
8760
  await GitRefManager.writeRef({ fs, gitdir, ref: ours, value: theirOid });
8720
8761
  }
@@ -8788,6 +8829,7 @@ async function _merge({
8788
8829
  * @param {string} [args.remoteRef]
8789
8830
  * @param {string} [args.corsProxy]
8790
8831
  * @param {boolean} args.singleBranch
8832
+ * @param {boolean} args.fastForward
8791
8833
  * @param {boolean} args.fastForwardOnly
8792
8834
  * @param {Object<string, string>} [args.headers]
8793
8835
  * @param {Object} args.author
@@ -8820,6 +8862,7 @@ async function _pull({
8820
8862
  url,
8821
8863
  remote,
8822
8864
  remoteRef,
8865
+ fastForward,
8823
8866
  fastForwardOnly,
8824
8867
  corsProxy,
8825
8868
  singleBranch,
@@ -8864,6 +8907,7 @@ async function _pull({
8864
8907
  gitdir,
8865
8908
  ours: ref,
8866
8909
  theirs: fetchHead,
8910
+ fastForward,
8867
8911
  fastForwardOnly,
8868
8912
  message: `Merge ${fetchHeadDescription}`,
8869
8913
  author,
@@ -10843,6 +10887,7 @@ async function log({
10843
10887
  * @param {string} [args.gitdir=join(dir,'.git')] - [required] The [git directory](dir-vs-gitdir.md) path
10844
10888
  * @param {string} [args.ours] - The branch receiving the merge. If undefined, defaults to the current branch.
10845
10889
  * @param {string} args.theirs - The branch to be merged
10890
+ * @param {boolean} [args.fastForward = true] - If false, create a merge commit in all cases.
10846
10891
  * @param {boolean} [args.fastForwardOnly = false] - If true, then non-fast-forward merges will throw an Error instead of performing a merge.
10847
10892
  * @param {boolean} [args.dryRun = false] - If true, simulates a merge so you can test whether it would succeed.
10848
10893
  * @param {boolean} [args.noUpdateBranch = false] - If true, does not update the branch pointer after creating the commit.
@@ -10880,6 +10925,7 @@ async function merge({
10880
10925
  gitdir = join(dir, '.git'),
10881
10926
  ours,
10882
10927
  theirs,
10928
+ fastForward = true,
10883
10929
  fastForwardOnly = false,
10884
10930
  dryRun = false,
10885
10931
  noUpdateBranch = false,
@@ -10897,7 +10943,9 @@ async function merge({
10897
10943
  const fs = new FileSystem(_fs);
10898
10944
 
10899
10945
  const author = await normalizeAuthorObject({ fs, gitdir, author: _author });
10900
- if (!author && !fastForwardOnly) throw new MissingNameError('author')
10946
+ if (!author && (!fastForwardOnly || !fastForward)) {
10947
+ throw new MissingNameError('author')
10948
+ }
10901
10949
 
10902
10950
  const committer = await normalizeCommitterObject({
10903
10951
  fs,
@@ -10905,7 +10953,7 @@ async function merge({
10905
10953
  author,
10906
10954
  committer: _committer,
10907
10955
  });
10908
- if (!committer && !fastForwardOnly) {
10956
+ if (!committer && (!fastForwardOnly || !fastForward)) {
10909
10957
  throw new MissingNameError('committer')
10910
10958
  }
10911
10959
 
@@ -10915,6 +10963,7 @@ async function merge({
10915
10963
  gitdir,
10916
10964
  ours,
10917
10965
  theirs,
10966
+ fastForward,
10918
10967
  fastForwardOnly,
10919
10968
  dryRun,
10920
10969
  noUpdateBranch,
@@ -11119,6 +11168,7 @@ async function packObjects({
11119
11168
  * @param {string} [args.remoteRef] - (Added in 1.1.0) The name of the branch on the remote to fetch. By default this is the configured remote tracking branch.
11120
11169
  * @param {string} [args.corsProxy] - Optional [CORS proxy](https://www.npmjs.com/%40isomorphic-git/cors-proxy). Overrides value in repo config.
11121
11170
  * @param {boolean} [args.singleBranch = false] - Instead of the default behavior of fetching all the branches, only fetch a single branch.
11171
+ * @param {boolean} [args.fastForward = true] - If false, only create merge commits.
11122
11172
  * @param {boolean} [args.fastForwardOnly = false] - Only perform simple fast-forward merges. (Don't create merge commits.)
11123
11173
  * @param {Object<string, string>} [args.headers] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
11124
11174
  * @param {Object} [args.author] - The details about the author.
@@ -11161,6 +11211,7 @@ async function pull({
11161
11211
  url,
11162
11212
  remote,
11163
11213
  remoteRef,
11214
+ fastForward = true,
11164
11215
  fastForwardOnly = false,
11165
11216
  corsProxy,
11166
11217
  singleBranch,
@@ -11202,6 +11253,7 @@ async function pull({
11202
11253
  url,
11203
11254
  remote,
11204
11255
  remoteRef,
11256
+ fastForward,
11205
11257
  fastForwardOnly,
11206
11258
  corsProxy,
11207
11259
  singleBranch,
@@ -13325,27 +13377,37 @@ async function statusMatrix({
13325
13377
  if (!filter(filepath)) return
13326
13378
  }
13327
13379
 
13328
- // For now, just bail on directories
13329
- const headType = head && (await head.type());
13330
- if (headType === 'tree' || headType === 'special') return
13380
+ const [headType, workdirType, stageType] = await Promise.all([
13381
+ head && head.type(),
13382
+ workdir && workdir.type(),
13383
+ stage && stage.type(),
13384
+ ]);
13385
+
13386
+ const isBlob = [headType, workdirType, stageType].includes('blob');
13387
+
13388
+ // For now, bail on directories unless the file is also a blob in another tree
13389
+ if ((headType === 'tree' || headType === 'special') && !isBlob) return
13331
13390
  if (headType === 'commit') return null
13332
13391
 
13333
- const workdirType = workdir && (await workdir.type());
13334
- if (workdirType === 'tree' || workdirType === 'special') return
13392
+ if ((workdirType === 'tree' || workdirType === 'special') && !isBlob)
13393
+ return
13335
13394
 
13336
- const stageType = stage && (await stage.type());
13337
13395
  if (stageType === 'commit') return null
13338
- if (stageType === 'tree' || stageType === 'special') return
13396
+ if ((stageType === 'tree' || stageType === 'special') && !isBlob) return
13339
13397
 
13340
- // Figure out the oids, using the staged oid for the working dir oid if the stats match.
13341
- const headOid = head ? await head.oid() : undefined;
13342
- const stageOid = stage ? await stage.oid() : undefined;
13398
+ // Figure out the oids for files, using the staged oid for the working dir oid if the stats match.
13399
+ const headOid = headType === 'blob' ? await head.oid() : undefined;
13400
+ const stageOid = stageType === 'blob' ? await stage.oid() : undefined;
13343
13401
  let workdirOid;
13344
- if (!head && workdir && !stage) {
13402
+ if (
13403
+ headType !== 'blob' &&
13404
+ workdirType === 'blob' &&
13405
+ stageType !== 'blob'
13406
+ ) {
13345
13407
  // We don't actually NEED the sha. Any sha will do
13346
13408
  // TODO: update this logic to handle N trees instead of just 3.
13347
13409
  workdirOid = '42';
13348
- } else if (workdir) {
13410
+ } else if (workdirType === 'blob') {
13349
13411
  workdirOid = await workdir.oid();
13350
13412
  }
13351
13413
  const entry = [undefined, headOid, workdirOid, stageOid];
@@ -751,7 +751,7 @@ export function WORKDIR(): Walker;
751
751
  * @param {FsClient} args.fs - a file system implementation
752
752
  * @param {string} args.dir - The [working tree](dir-vs-gitdir.md) directory path
753
753
  * @param {string} [args.gitdir=join(dir, '.git')] - [required] The [git directory](dir-vs-gitdir.md) path
754
- * @param {string} args.filepath - The path to the file to add to the index
754
+ * @param {string|string[]} args.filepath - The path to the file to add to the index
755
755
  * @param {object} [args.cache] - a [cache](cache.md) object
756
756
  *
757
757
  * @returns {Promise<void>} Resolves successfully once the git index has been updated
@@ -766,7 +766,7 @@ export function add({ fs: _fs, dir, gitdir, filepath, cache, }: {
766
766
  fs: CallbackFsClient | PromiseFsClient;
767
767
  dir: string;
768
768
  gitdir?: string;
769
- filepath: string;
769
+ filepath: string | string[];
770
770
  cache?: any;
771
771
  }): Promise<void>;
772
772
  /**
@@ -2097,6 +2097,7 @@ export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follo
2097
2097
  * @param {string} [args.gitdir=join(dir,'.git')] - [required] The [git directory](dir-vs-gitdir.md) path
2098
2098
  * @param {string} [args.ours] - The branch receiving the merge. If undefined, defaults to the current branch.
2099
2099
  * @param {string} args.theirs - The branch to be merged
2100
+ * @param {boolean} [args.fastForward = true] - If false, create a merge commit in all cases.
2100
2101
  * @param {boolean} [args.fastForwardOnly = false] - If true, then non-fast-forward merges will throw an Error instead of performing a merge.
2101
2102
  * @param {boolean} [args.dryRun = false] - If true, simulates a merge so you can test whether it would succeed.
2102
2103
  * @param {boolean} [args.noUpdateBranch = false] - If true, does not update the branch pointer after creating the commit.
@@ -2127,13 +2128,14 @@ export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follo
2127
2128
  * console.log(m)
2128
2129
  *
2129
2130
  */
2130
- export function merge({ fs: _fs, onSign, dir, gitdir, ours, theirs, fastForwardOnly, dryRun, noUpdateBranch, message, author: _author, committer: _committer, signingKey, cache, }: {
2131
+ export function merge({ fs: _fs, onSign, dir, gitdir, ours, theirs, fastForward, fastForwardOnly, dryRun, noUpdateBranch, message, author: _author, committer: _committer, signingKey, cache, }: {
2131
2132
  fs: CallbackFsClient | PromiseFsClient;
2132
2133
  onSign?: SignCallback;
2133
2134
  dir?: string;
2134
2135
  gitdir?: string;
2135
2136
  ours?: string;
2136
2137
  theirs: string;
2138
+ fastForward?: boolean;
2137
2139
  fastForwardOnly?: boolean;
2138
2140
  dryRun?: boolean;
2139
2141
  noUpdateBranch?: boolean;
@@ -2210,6 +2212,7 @@ export function packObjects({ fs, dir, gitdir, oids, write, cache, }: {
2210
2212
  * @param {string} [args.remoteRef] - (Added in 1.1.0) The name of the branch on the remote to fetch. By default this is the configured remote tracking branch.
2211
2213
  * @param {string} [args.corsProxy] - Optional [CORS proxy](https://www.npmjs.com/%40isomorphic-git/cors-proxy). Overrides value in repo config.
2212
2214
  * @param {boolean} [args.singleBranch = false] - Instead of the default behavior of fetching all the branches, only fetch a single branch.
2215
+ * @param {boolean} [args.fastForward = true] - If false, only create merge commits.
2213
2216
  * @param {boolean} [args.fastForwardOnly = false] - Only perform simple fast-forward merges. (Don't create merge commits.)
2214
2217
  * @param {Object<string, string>} [args.headers] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
2215
2218
  * @param {Object} [args.author] - The details about the author.
@@ -2238,7 +2241,7 @@ export function packObjects({ fs, dir, gitdir, oids, write, cache, }: {
2238
2241
  * console.log('done')
2239
2242
  *
2240
2243
  */
2241
- export function pull({ fs: _fs, http, onProgress, onMessage, onAuth, onAuthSuccess, onAuthFailure, dir, gitdir, ref, url, remote, remoteRef, fastForwardOnly, corsProxy, singleBranch, headers, author: _author, committer: _committer, signingKey, cache, }: {
2244
+ export function pull({ fs: _fs, http, onProgress, onMessage, onAuth, onAuthSuccess, onAuthFailure, dir, gitdir, ref, url, remote, remoteRef, fastForward, fastForwardOnly, corsProxy, singleBranch, headers, author: _author, committer: _committer, signingKey, cache, }: {
2242
2245
  fs: CallbackFsClient | PromiseFsClient;
2243
2246
  http: HttpClient;
2244
2247
  onProgress?: ProgressCallback;
@@ -2254,6 +2257,7 @@ export function pull({ fs: _fs, http, onProgress, onMessage, onAuth, onAuthSucce
2254
2257
  remoteRef?: string;
2255
2258
  corsProxy?: string;
2256
2259
  singleBranch?: boolean;
2260
+ fastForward?: boolean;
2257
2261
  fastForwardOnly?: boolean;
2258
2262
  headers?: {
2259
2263
  [x: string]: string;