@gadgetinc/ggt 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -128
- package/lib/__generated__/graphql.js.map +1 -1
- package/lib/commands/add.js +385 -0
- package/lib/commands/add.js.map +1 -0
- package/lib/commands/deploy.js +20 -102
- package/lib/commands/deploy.js.map +1 -1
- package/lib/commands/dev.js +43 -114
- package/lib/commands/dev.js.map +1 -1
- package/lib/commands/list.js +3 -6
- package/lib/commands/list.js.map +1 -1
- package/lib/commands/login.js +5 -5
- package/lib/commands/login.js.map +1 -1
- package/lib/commands/logout.js +2 -5
- package/lib/commands/logout.js.map +1 -1
- package/lib/commands/open.js +45 -86
- package/lib/commands/open.js.map +1 -1
- package/lib/commands/pull.js +19 -76
- package/lib/commands/pull.js.map +1 -1
- package/lib/commands/push.js +19 -76
- package/lib/commands/push.js.map +1 -1
- package/lib/commands/root.js +4 -3
- package/lib/commands/root.js.map +1 -1
- package/lib/commands/status.js +3 -8
- package/lib/commands/status.js.map +1 -1
- package/lib/commands/version.js +6 -5
- package/lib/commands/version.js.map +1 -1
- package/lib/commands/whoami.js +2 -5
- package/lib/commands/whoami.js.map +1 -1
- package/lib/ggt.js.map +1 -1
- package/lib/main.js.map +1 -1
- package/lib/services/app/api/api.js.map +1 -1
- package/lib/services/app/api/operation.js +11 -0
- package/lib/services/app/api/operation.js.map +1 -1
- package/lib/services/app/app.js +21 -2
- package/lib/services/app/app.js.map +1 -1
- package/lib/services/app/arg.js.map +1 -1
- package/lib/services/app/client.js.map +1 -1
- package/lib/services/app/edit/edit.js.map +1 -1
- package/lib/services/app/edit/operation.js +52 -0
- package/lib/services/app/edit/operation.js.map +1 -1
- package/lib/services/app/error.js.map +1 -1
- package/lib/services/command/arg.js +3 -1
- package/lib/services/command/arg.js.map +1 -1
- package/lib/services/command/command.js +1 -0
- package/lib/services/command/command.js.map +1 -1
- package/lib/services/command/context.js.map +1 -1
- package/lib/services/config/config.js.map +1 -1
- package/lib/services/config/env.js.map +1 -1
- package/lib/services/config/package-json.js.map +1 -1
- package/lib/services/filesync/changes.js.map +1 -1
- package/lib/services/filesync/conflicts.js.map +1 -1
- package/lib/services/filesync/directory.js.map +1 -1
- package/lib/services/filesync/error.js +1 -0
- package/lib/services/filesync/error.js.map +1 -1
- package/lib/services/filesync/file.js.map +1 -1
- package/lib/services/filesync/filesync.js +179 -174
- package/lib/services/filesync/filesync.js.map +1 -1
- package/lib/services/filesync/hashes.js.map +1 -1
- package/lib/services/filesync/strategy.js.map +1 -1
- package/lib/services/filesync/sync-json.js.map +1 -1
- package/lib/services/http/auth.js.map +1 -1
- package/lib/services/http/http.js.map +1 -1
- package/lib/services/output/confirm.js.map +1 -1
- package/lib/services/output/footer.js.map +1 -1
- package/lib/services/output/log/field.js.map +1 -1
- package/lib/services/output/log/format/format.js.map +1 -1
- package/lib/services/output/log/format/json.js.map +1 -1
- package/lib/services/output/log/format/pretty.js.map +1 -1
- package/lib/services/output/log/level.js.map +1 -1
- package/lib/services/output/log/logger.js.map +1 -1
- package/lib/services/output/log/structured.js.map +1 -1
- package/lib/services/output/notify.js.map +1 -1
- package/lib/services/output/output.js.map +1 -1
- package/lib/services/output/print.js.map +1 -1
- package/lib/services/output/problems.js.map +1 -1
- package/lib/services/output/prompt.js.map +1 -1
- package/lib/services/output/report.js.map +1 -1
- package/lib/services/output/select.js.map +1 -1
- package/lib/services/output/spinner.js.map +1 -1
- package/lib/services/output/sprint.js.map +1 -1
- package/lib/services/output/symbols.js.map +1 -1
- package/lib/services/output/table.js.map +1 -1
- package/lib/services/output/timestamp.js.map +1 -1
- package/lib/services/output/update.js.map +1 -1
- package/lib/services/user/session.js.map +1 -1
- package/lib/services/user/user.js.map +1 -1
- package/lib/services/util/assert.js.map +1 -1
- package/lib/services/util/boolean.js.map +1 -1
- package/lib/services/util/collection.js.map +1 -1
- package/lib/services/util/function.js.map +1 -1
- package/lib/services/util/is.js.map +1 -1
- package/lib/services/util/json.js.map +1 -1
- package/lib/services/util/number.js.map +1 -1
- package/lib/services/util/object.js.map +1 -1
- package/lib/services/util/paths.js.map +1 -1
- package/lib/services/util/promise.js.map +1 -1
- package/lib/services/util/types.js.map +1 -1
- package/npm-shrinkwrap.json +2183 -1763
- package/package.json +34 -34
|
@@ -40,12 +40,12 @@ import { MergeConflictPreference } from "./strategy.js";
|
|
|
40
40
|
* single request.
|
|
41
41
|
*/ export const MAX_PUSH_CONTENT_LENGTH = 50 * 1024 * 1024; // 50mb
|
|
42
42
|
export class FileSync {
|
|
43
|
-
async hashes(ctx) {
|
|
44
|
-
const spinner = spin({
|
|
43
|
+
async hashes(ctx, quietly) {
|
|
44
|
+
const spinner = !quietly ? spin({
|
|
45
45
|
ensureEmptyLineAbove: true
|
|
46
46
|
})`
|
|
47
47
|
Calculating file changes.
|
|
48
|
-
|
|
48
|
+
` : undefined;
|
|
49
49
|
try {
|
|
50
50
|
const [localHashes, { localFilesVersionHashes, environmentHashes, environmentFilesVersion }] = await Promise.all([
|
|
51
51
|
// get the hashes of our local files
|
|
@@ -125,10 +125,12 @@ export class FileSync {
|
|
|
125
125
|
});
|
|
126
126
|
const onlyDotGadgetFilesChanged = Array.from(environmentChangesToPull.keys()).every((filepath)=>filepath.startsWith(".gadget/"));
|
|
127
127
|
const bothChanged = localChanges.size > 0 && environmentChanges.size > 0 && !onlyDotGadgetFilesChanged;
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
if (spinner) {
|
|
129
|
+
if (inSync) {
|
|
130
|
+
spinner.succeed`Your files are up to date. ${ts()}`;
|
|
131
|
+
} else {
|
|
132
|
+
spinner.succeed`Calculated file changes. ${ts()}`;
|
|
133
|
+
}
|
|
132
134
|
}
|
|
133
135
|
return {
|
|
134
136
|
inSync,
|
|
@@ -144,7 +146,9 @@ export class FileSync {
|
|
|
144
146
|
bothChanged
|
|
145
147
|
};
|
|
146
148
|
} catch (error) {
|
|
147
|
-
spinner
|
|
149
|
+
if (spinner) {
|
|
150
|
+
spinner.fail();
|
|
151
|
+
}
|
|
148
152
|
throw error;
|
|
149
153
|
}
|
|
150
154
|
}
|
|
@@ -270,14 +274,14 @@ export class FileSync {
|
|
|
270
274
|
changed: changed.map((file)=>file.path),
|
|
271
275
|
deleted: deleted.map((file)=>file.path)
|
|
272
276
|
});
|
|
273
|
-
const changes = await this.
|
|
277
|
+
const changes = await this.writeToLocalFilesystem(ctx, {
|
|
274
278
|
filesVersion: remoteFilesVersion,
|
|
275
279
|
files: changed,
|
|
276
280
|
delete: deleted.map((file)=>file.path),
|
|
277
281
|
printEnvironmentChangesOptions: {
|
|
278
282
|
tense: "past",
|
|
279
283
|
ensureEmptyLineAbove: true,
|
|
280
|
-
title: sprintln`{
|
|
284
|
+
title: sprintln`{greenBright ${symbol.tick}} Pulled ${pluralize("file", changed.length + deleted.length)}. ${ts()}`,
|
|
281
285
|
limit: 5,
|
|
282
286
|
...printEnvironmentChangesOptions
|
|
283
287
|
}
|
|
@@ -294,13 +298,13 @@ export class FileSync {
|
|
|
294
298
|
* - All non-conflicting changes are automatically merged.
|
|
295
299
|
* - Conflicts are resolved by prompting the user to either keep their local changes or keep Gadget's changes.
|
|
296
300
|
* - This function will not return until the filesystem is in sync.
|
|
297
|
-
*/ async merge(ctx, { hashes, maxAttempts = 10, printLocalChangesOptions, printEnvironmentChangesOptions } = {}) {
|
|
301
|
+
*/ async merge(ctx, { hashes, maxAttempts = 10, printLocalChangesOptions, printEnvironmentChangesOptions, quietly } = {}) {
|
|
298
302
|
let attempt = 0;
|
|
299
303
|
do {
|
|
300
304
|
if (attempt === 0) {
|
|
301
|
-
hashes ??= await this.hashes(ctx);
|
|
305
|
+
hashes ??= await this.hashes(ctx, quietly);
|
|
302
306
|
} else {
|
|
303
|
-
hashes = await this.hashes(ctx);
|
|
307
|
+
hashes = await this.hashes(ctx, quietly);
|
|
304
308
|
}
|
|
305
309
|
if (hashes.inSync) {
|
|
306
310
|
this._syncOperations.clear();
|
|
@@ -384,6 +388,166 @@ export class FileSync {
|
|
|
384
388
|
printEnvironmentChangesOptions
|
|
385
389
|
});
|
|
386
390
|
}
|
|
391
|
+
async writeToLocalFilesystem(ctx, options) {
|
|
392
|
+
const filesVersion = BigInt(options.filesVersion);
|
|
393
|
+
assert(filesVersion >= this.syncJson.filesVersion, "filesVersion must be greater than or equal to current filesVersion");
|
|
394
|
+
ctx.log.debug("writing to local filesystem", {
|
|
395
|
+
filesVersion,
|
|
396
|
+
files: options.files.map((file)=>file.path),
|
|
397
|
+
delete: options.delete
|
|
398
|
+
});
|
|
399
|
+
const changes = new Changes();
|
|
400
|
+
const directoriesWithDeletedFiles = new Set();
|
|
401
|
+
await pMap(options.delete, async (pathToDelete)=>{
|
|
402
|
+
// add all the directories that contain this file to
|
|
403
|
+
// directoriesWithDeletedFiles so we can clean them up later
|
|
404
|
+
let dir = path.dirname(pathToDelete);
|
|
405
|
+
while(dir !== "."){
|
|
406
|
+
directoriesWithDeletedFiles.add(this.syncJson.directory.normalize(dir, true));
|
|
407
|
+
dir = path.dirname(dir);
|
|
408
|
+
}
|
|
409
|
+
const currentPath = this.syncJson.directory.absolute(pathToDelete);
|
|
410
|
+
const backupPath = this.syncJson.directory.absolute(".gadget/backup", this.syncJson.directory.relative(pathToDelete));
|
|
411
|
+
// rather than `rm -rf`ing files, we move them to
|
|
412
|
+
// `.gadget/backup/` so that users can recover them if something
|
|
413
|
+
// goes wrong. We've seen a lot of EBUSY/EINVAL errors when moving
|
|
414
|
+
// files so we retry a few times.
|
|
415
|
+
await pRetry(async ()=>{
|
|
416
|
+
try {
|
|
417
|
+
// remove the current backup file in case it exists and is a
|
|
418
|
+
// different type (file vs directory)
|
|
419
|
+
await fs.remove(backupPath);
|
|
420
|
+
await fs.move(currentPath, backupPath);
|
|
421
|
+
changes.set(pathToDelete, {
|
|
422
|
+
type: "delete"
|
|
423
|
+
});
|
|
424
|
+
} catch (error) {
|
|
425
|
+
if (isENOENTError(error)) {
|
|
426
|
+
// replicate the behavior of `rm -rf` and ignore ENOENT
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
if (isENOTDIRError(error) || isEEXISTError(error)) {
|
|
430
|
+
// the backup path already exists and ends in a file
|
|
431
|
+
// rather than a directory, so we have to remove the file
|
|
432
|
+
// before we can move the current path to the backup path
|
|
433
|
+
let dir = path.dirname(backupPath);
|
|
434
|
+
while(dir !== this.syncJson.directory.absolute(".gadget/backup")){
|
|
435
|
+
const stats = await fs.stat(dir);
|
|
436
|
+
// eslint-disable-next-line max-depth
|
|
437
|
+
if (!stats.isDirectory()) {
|
|
438
|
+
// this file is in the way, so remove it
|
|
439
|
+
ctx.log.debug("removing file in the way of backup path", {
|
|
440
|
+
currentPath,
|
|
441
|
+
backupPath,
|
|
442
|
+
file: dir
|
|
443
|
+
});
|
|
444
|
+
await fs.remove(dir);
|
|
445
|
+
}
|
|
446
|
+
dir = path.dirname(dir);
|
|
447
|
+
}
|
|
448
|
+
// still throw the error so we retry
|
|
449
|
+
}
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
}, {
|
|
453
|
+
// windows tends to run into these issues way more often than
|
|
454
|
+
// mac/linux, so we retry more times
|
|
455
|
+
retries: config.windows ? 4 : 2,
|
|
456
|
+
minTimeout: ms("100ms"),
|
|
457
|
+
onFailedAttempt: (error)=>{
|
|
458
|
+
ctx.log.warn("failed to move file to backup", {
|
|
459
|
+
error,
|
|
460
|
+
currentPath,
|
|
461
|
+
backupPath
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
for (const directoryWithDeletedFile of Array.from(directoriesWithDeletedFiles.values()).sort().reverse()){
|
|
467
|
+
if (options.files.some((file)=>file.path === directoryWithDeletedFile)) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
try {
|
|
471
|
+
// delete any empty directories that contained a deleted file.
|
|
472
|
+
// if the empty directory should continue to exist, we would
|
|
473
|
+
// have received an event to create it above
|
|
474
|
+
await fs.rmdir(this.syncJson.directory.absolute(directoryWithDeletedFile));
|
|
475
|
+
changes.set(directoryWithDeletedFile, {
|
|
476
|
+
type: "delete"
|
|
477
|
+
});
|
|
478
|
+
} catch (error) {
|
|
479
|
+
if (isENOENTError(error) || isENOTEMPTYError(error)) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
throw error;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
await pMap(options.files, async (file)=>{
|
|
486
|
+
const absolutePath = this.syncJson.directory.absolute(file.path);
|
|
487
|
+
if (await fs.pathExists(absolutePath)) {
|
|
488
|
+
if (!file.path.endsWith("/")) {
|
|
489
|
+
// only track file updates, not directory updates
|
|
490
|
+
changes.set(file.path, {
|
|
491
|
+
type: "update"
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
changes.set(file.path, {
|
|
496
|
+
type: "create"
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
if (file.path.endsWith("/")) {
|
|
500
|
+
await fs.ensureDir(absolutePath);
|
|
501
|
+
} else {
|
|
502
|
+
await fs.outputFile(absolutePath, Buffer.from(file.content, file.encoding));
|
|
503
|
+
}
|
|
504
|
+
if (supportsPermissions) {
|
|
505
|
+
// the os's default umask makes setting the mode during creation
|
|
506
|
+
// not work, so an additional fs.chmod call is necessary to
|
|
507
|
+
// ensure the file has the correct mode
|
|
508
|
+
await fs.chmod(absolutePath, file.mode & 0o777);
|
|
509
|
+
}
|
|
510
|
+
if (absolutePath === this.syncJson.directory.absolute(".ignore")) {
|
|
511
|
+
await this.syncJson.directory.loadIgnoreFile();
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
await this.syncJson.save(String(filesVersion));
|
|
515
|
+
options.spinner?.clear();
|
|
516
|
+
printChanges(ctx, {
|
|
517
|
+
changes,
|
|
518
|
+
tense: "past",
|
|
519
|
+
title: sprint`{greenBright ${symbol.arrowDown}} Pulled ${pluralize("file", changes.size)}. ${ts()}`,
|
|
520
|
+
...options.printEnvironmentChangesOptions,
|
|
521
|
+
includeDotGadget: !!ctx.args["--verbose"]
|
|
522
|
+
});
|
|
523
|
+
if (changes.has("yarn.lock")) {
|
|
524
|
+
const spinner = spin({
|
|
525
|
+
ensureEmptyLineAbove: true
|
|
526
|
+
})('Running "yarn install --check-files"');
|
|
527
|
+
try {
|
|
528
|
+
await execa("yarn", [
|
|
529
|
+
"install",
|
|
530
|
+
"--check-files"
|
|
531
|
+
], {
|
|
532
|
+
cwd: this.syncJson.directory.path
|
|
533
|
+
});
|
|
534
|
+
spinner.succeed`Ran "yarn install --check-files" ${ts()}`;
|
|
535
|
+
} catch (error) {
|
|
536
|
+
spinner.fail();
|
|
537
|
+
ctx.log.error("yarn install failed", {
|
|
538
|
+
error
|
|
539
|
+
});
|
|
540
|
+
const message = serializeError(error).message;
|
|
541
|
+
if (message) {
|
|
542
|
+
println({
|
|
543
|
+
ensureEmptyLineAbove: true,
|
|
544
|
+
indent: 2
|
|
545
|
+
})(message);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
return changes;
|
|
550
|
+
}
|
|
387
551
|
async _merge(ctx, { hashes: { localChanges, environmentChanges, environmentFilesVersion }, printLocalChangesOptions, printEnvironmentChangesOptions }) {
|
|
388
552
|
const conflicts = getConflicts({
|
|
389
553
|
localChanges,
|
|
@@ -455,7 +619,7 @@ export class FileSync {
|
|
|
455
619
|
})(sprintChanges(ctx, {
|
|
456
620
|
changes,
|
|
457
621
|
tense: "present",
|
|
458
|
-
title: sprint`Pulling ${pluralize("file", changes.size)}
|
|
622
|
+
title: sprint`Pulling ${pluralize("file", changes.size)}.`,
|
|
459
623
|
...printEnvironmentChangesOptions
|
|
460
624
|
}));
|
|
461
625
|
try {
|
|
@@ -474,7 +638,7 @@ export class FileSync {
|
|
|
474
638
|
});
|
|
475
639
|
files = fileSyncFiles.files;
|
|
476
640
|
}
|
|
477
|
-
await this.
|
|
641
|
+
await this.writeToLocalFilesystem(ctx, {
|
|
478
642
|
filesVersion,
|
|
479
643
|
files,
|
|
480
644
|
delete: changes.deleted(),
|
|
@@ -611,165 +775,6 @@ export class FileSync {
|
|
|
611
775
|
throw error;
|
|
612
776
|
}
|
|
613
777
|
}
|
|
614
|
-
async _writeToLocalFilesystem(ctx, options) {
|
|
615
|
-
const filesVersion = BigInt(options.filesVersion);
|
|
616
|
-
assert(filesVersion >= this.syncJson.filesVersion, "filesVersion must be greater than or equal to current filesVersion");
|
|
617
|
-
ctx.log.debug("writing to local filesystem", {
|
|
618
|
-
filesVersion,
|
|
619
|
-
files: options.files.map((file)=>file.path),
|
|
620
|
-
delete: options.delete
|
|
621
|
-
});
|
|
622
|
-
const changes = new Changes();
|
|
623
|
-
const directoriesWithDeletedFiles = new Set();
|
|
624
|
-
await pMap(options.delete, async (pathToDelete)=>{
|
|
625
|
-
// add all the directories that contain this file to
|
|
626
|
-
// directoriesWithDeletedFiles so we can clean them up later
|
|
627
|
-
let dir = path.dirname(pathToDelete);
|
|
628
|
-
while(dir !== "."){
|
|
629
|
-
directoriesWithDeletedFiles.add(this.syncJson.directory.normalize(dir, true));
|
|
630
|
-
dir = path.dirname(dir);
|
|
631
|
-
}
|
|
632
|
-
const currentPath = this.syncJson.directory.absolute(pathToDelete);
|
|
633
|
-
const backupPath = this.syncJson.directory.absolute(".gadget/backup", this.syncJson.directory.relative(pathToDelete));
|
|
634
|
-
// rather than `rm -rf`ing files, we move them to
|
|
635
|
-
// `.gadget/backup/` so that users can recover them if something
|
|
636
|
-
// goes wrong. We've seen a lot of EBUSY/EINVAL errors when moving
|
|
637
|
-
// files so we retry a few times.
|
|
638
|
-
await pRetry(async ()=>{
|
|
639
|
-
try {
|
|
640
|
-
// remove the current backup file in case it exists and is a
|
|
641
|
-
// different type (file vs directory)
|
|
642
|
-
await fs.remove(backupPath);
|
|
643
|
-
await fs.move(currentPath, backupPath);
|
|
644
|
-
changes.set(pathToDelete, {
|
|
645
|
-
type: "delete"
|
|
646
|
-
});
|
|
647
|
-
} catch (error) {
|
|
648
|
-
if (isENOENTError(error)) {
|
|
649
|
-
// replicate the behavior of `rm -rf` and ignore ENOENT
|
|
650
|
-
return;
|
|
651
|
-
}
|
|
652
|
-
if (isENOTDIRError(error) || isEEXISTError(error)) {
|
|
653
|
-
// the backup path already exists and ends in a file
|
|
654
|
-
// rather than a directory, so we have to remove the file
|
|
655
|
-
// before we can move the current path to the backup path
|
|
656
|
-
let dir = path.dirname(backupPath);
|
|
657
|
-
while(dir !== this.syncJson.directory.absolute(".gadget/backup")){
|
|
658
|
-
const stats = await fs.stat(dir);
|
|
659
|
-
// eslint-disable-next-line max-depth
|
|
660
|
-
if (!stats.isDirectory()) {
|
|
661
|
-
// this file is in the way, so remove it
|
|
662
|
-
ctx.log.debug("removing file in the way of backup path", {
|
|
663
|
-
currentPath,
|
|
664
|
-
backupPath,
|
|
665
|
-
file: dir
|
|
666
|
-
});
|
|
667
|
-
await fs.remove(dir);
|
|
668
|
-
}
|
|
669
|
-
dir = path.dirname(dir);
|
|
670
|
-
}
|
|
671
|
-
// still throw the error so we retry
|
|
672
|
-
}
|
|
673
|
-
throw error;
|
|
674
|
-
}
|
|
675
|
-
}, {
|
|
676
|
-
// windows tends to run into these issues way more often than
|
|
677
|
-
// mac/linux, so we retry more times
|
|
678
|
-
retries: config.windows ? 4 : 2,
|
|
679
|
-
minTimeout: ms("100ms"),
|
|
680
|
-
onFailedAttempt: (error)=>{
|
|
681
|
-
ctx.log.warn("failed to move file to backup", {
|
|
682
|
-
error,
|
|
683
|
-
currentPath,
|
|
684
|
-
backupPath
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
});
|
|
688
|
-
});
|
|
689
|
-
for (const directoryWithDeletedFile of Array.from(directoriesWithDeletedFiles.values()).sort().reverse()){
|
|
690
|
-
if (options.files.some((file)=>file.path === directoryWithDeletedFile)) {
|
|
691
|
-
continue;
|
|
692
|
-
}
|
|
693
|
-
try {
|
|
694
|
-
// delete any empty directories that contained a deleted file.
|
|
695
|
-
// if the empty directory should continue to exist, we would
|
|
696
|
-
// have received an event to create it above
|
|
697
|
-
await fs.rmdir(this.syncJson.directory.absolute(directoryWithDeletedFile));
|
|
698
|
-
changes.set(directoryWithDeletedFile, {
|
|
699
|
-
type: "delete"
|
|
700
|
-
});
|
|
701
|
-
} catch (error) {
|
|
702
|
-
if (isENOENTError(error) || isENOTEMPTYError(error)) {
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
throw error;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
await pMap(options.files, async (file)=>{
|
|
709
|
-
const absolutePath = this.syncJson.directory.absolute(file.path);
|
|
710
|
-
if (await fs.pathExists(absolutePath)) {
|
|
711
|
-
if (!file.path.endsWith("/")) {
|
|
712
|
-
// only track file updates, not directory updates
|
|
713
|
-
changes.set(file.path, {
|
|
714
|
-
type: "update"
|
|
715
|
-
});
|
|
716
|
-
}
|
|
717
|
-
} else {
|
|
718
|
-
changes.set(file.path, {
|
|
719
|
-
type: "create"
|
|
720
|
-
});
|
|
721
|
-
}
|
|
722
|
-
if (file.path.endsWith("/")) {
|
|
723
|
-
await fs.ensureDir(absolutePath);
|
|
724
|
-
} else {
|
|
725
|
-
await fs.outputFile(absolutePath, Buffer.from(file.content, file.encoding));
|
|
726
|
-
}
|
|
727
|
-
if (supportsPermissions) {
|
|
728
|
-
// the os's default umask makes setting the mode during creation
|
|
729
|
-
// not work, so an additional fs.chmod call is necessary to
|
|
730
|
-
// ensure the file has the correct mode
|
|
731
|
-
await fs.chmod(absolutePath, file.mode & 0o777);
|
|
732
|
-
}
|
|
733
|
-
if (absolutePath === this.syncJson.directory.absolute(".ignore")) {
|
|
734
|
-
await this.syncJson.directory.loadIgnoreFile();
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
await this.syncJson.save(String(filesVersion));
|
|
738
|
-
options.spinner?.clear();
|
|
739
|
-
printChanges(ctx, {
|
|
740
|
-
changes,
|
|
741
|
-
tense: "past",
|
|
742
|
-
title: sprint`{green ${symbol.tick}} Pulled ${pluralize("file", changes.size)}. ${symbol.arrowLeft} ${ts()}`,
|
|
743
|
-
...options.printEnvironmentChangesOptions
|
|
744
|
-
});
|
|
745
|
-
if (changes.has("yarn.lock")) {
|
|
746
|
-
const spinner = spin({
|
|
747
|
-
ensureEmptyLineAbove: true
|
|
748
|
-
})('Running "yarn install --check-files"');
|
|
749
|
-
try {
|
|
750
|
-
await execa("yarn", [
|
|
751
|
-
"install",
|
|
752
|
-
"--check-files"
|
|
753
|
-
], {
|
|
754
|
-
cwd: this.syncJson.directory.path
|
|
755
|
-
});
|
|
756
|
-
spinner.succeed`Ran "yarn install --check-files" ${ts()}`;
|
|
757
|
-
} catch (error) {
|
|
758
|
-
spinner.fail();
|
|
759
|
-
ctx.log.error("yarn install failed", {
|
|
760
|
-
error
|
|
761
|
-
});
|
|
762
|
-
const message = serializeError(error).message;
|
|
763
|
-
if (message) {
|
|
764
|
-
println({
|
|
765
|
-
ensureEmptyLineAbove: true,
|
|
766
|
-
indent: 2
|
|
767
|
-
})(message);
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
return changes;
|
|
772
|
-
}
|
|
773
778
|
constructor(syncJson){
|
|
774
779
|
_define_property(this, "syncJson", void 0);
|
|
775
780
|
/**
|