@gadgetinc/ggt 0.1.16 → 0.1.17
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 +6 -6
- package/lib/commands/help.d.ts +2 -2
- package/lib/commands/help.js +2 -1
- package/lib/commands/help.js.map +1 -1
- package/lib/commands/list.d.ts +1 -0
- package/lib/commands/list.js +15 -6
- package/lib/commands/list.js.map +1 -1
- package/lib/commands/sync.d.ts +80 -5
- package/lib/commands/sync.js +98 -31
- package/lib/commands/sync.js.map +1 -1
- package/lib/utils/base-command.d.ts +16 -10
- package/lib/utils/base-command.js +27 -14
- package/lib/utils/base-command.js.map +1 -1
- package/lib/utils/client.d.ts +6 -0
- package/lib/utils/client.js +6 -0
- package/lib/utils/client.js.map +1 -1
- package/lib/utils/context.d.ts +3 -2
- package/lib/utils/context.js +3 -2
- package/lib/utils/context.js.map +1 -1
- package/lib/utils/fs-utils.d.ts +2 -2
- package/lib/utils/fs-utils.js +3 -3
- package/lib/utils/fs-utils.js.map +1 -1
- package/lib/utils/promise.d.ts +35 -0
- package/lib/utils/promise.js +114 -0
- package/lib/utils/promise.js.map +1 -0
- package/npm-shrinkwrap.json +17252 -11129
- package/oclif.manifest.json +1 -1
- package/package.json +23 -23
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ EXAMPLES
|
|
|
129
129
|
Goodbye!
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
_See code: [src/commands/sync.ts](https://github.com/gadget-inc/ggt/blob/v0.1.
|
|
132
|
+
_See code: [src/commands/sync.ts](https://github.com/gadget-inc/ggt/blob/v0.1.17/src/commands/sync.ts)_
|
|
133
133
|
|
|
134
134
|
### `ggt help [COMMAND]`
|
|
135
135
|
|
|
@@ -143,7 +143,7 @@ ARGUMENTS
|
|
|
143
143
|
COMMAND The command to show help for.
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
_See code: [src/commands/help.ts](https://github.com/gadget-inc/ggt/blob/v0.1.
|
|
146
|
+
_See code: [src/commands/help.ts](https://github.com/gadget-inc/ggt/blob/v0.1.17/src/commands/help.ts)_
|
|
147
147
|
|
|
148
148
|
### `ggt list`
|
|
149
149
|
|
|
@@ -170,7 +170,7 @@ EXAMPLES
|
|
|
170
170
|
$ ggt list --sort=slug
|
|
171
171
|
```
|
|
172
172
|
|
|
173
|
-
_See code: [src/commands/list.ts](https://github.com/gadget-inc/ggt/blob/v0.1.
|
|
173
|
+
_See code: [src/commands/list.ts](https://github.com/gadget-inc/ggt/blob/v0.1.17/src/commands/list.ts)_
|
|
174
174
|
|
|
175
175
|
### `ggt login`
|
|
176
176
|
|
|
@@ -189,7 +189,7 @@ EXAMPLES
|
|
|
189
189
|
Hello, Jane Doe (jane@example.com)
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
_See code: [src/commands/login.ts](https://github.com/gadget-inc/ggt/blob/v0.1.
|
|
192
|
+
_See code: [src/commands/login.ts](https://github.com/gadget-inc/ggt/blob/v0.1.17/src/commands/login.ts)_
|
|
193
193
|
|
|
194
194
|
### `ggt logout`
|
|
195
195
|
|
|
@@ -204,7 +204,7 @@ EXAMPLES
|
|
|
204
204
|
Goodbye
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
-
_See code: [src/commands/logout.ts](https://github.com/gadget-inc/ggt/blob/v0.1.
|
|
207
|
+
_See code: [src/commands/logout.ts](https://github.com/gadget-inc/ggt/blob/v0.1.17/src/commands/logout.ts)_
|
|
208
208
|
|
|
209
209
|
### `ggt whoami`
|
|
210
210
|
|
|
@@ -219,7 +219,7 @@ EXAMPLES
|
|
|
219
219
|
You are logged in as Jane Doe (jane@example.com)
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
_See code: [src/commands/whoami.ts](https://github.com/gadget-inc/ggt/blob/v0.1.
|
|
222
|
+
_See code: [src/commands/whoami.ts](https://github.com/gadget-inc/ggt/blob/v0.1.17/src/commands/whoami.ts)_
|
|
223
223
|
|
|
224
224
|
<!-- commandsstop -->
|
|
225
225
|
|
package/lib/commands/help.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseCommand } from "../utils/base-command";
|
|
2
2
|
/**
|
|
3
3
|
* Copied from @oclif/plugin-help. Uses our own {@link Help} template class instead of the one from @oclif/core.
|
|
4
4
|
*
|
|
5
5
|
* @see https://github.com/oclif/plugin-help/blob/67b580570257b45e92d3a04d50bf2a432c59afe3/src/commands/help.ts
|
|
6
6
|
*/
|
|
7
|
-
export default class HelpCommand extends
|
|
7
|
+
export default class HelpCommand extends BaseCommand<typeof HelpCommand> {
|
|
8
8
|
static strict: boolean;
|
|
9
9
|
static summary: string;
|
|
10
10
|
static args: {
|
package/lib/commands/help.js
CHANGED
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const help_1 = tslib_1.__importDefault(require("../utils/help"));
|
|
6
|
+
const base_command_1 = require("../utils/base-command");
|
|
6
7
|
/**
|
|
7
8
|
* Copied from @oclif/plugin-help. Uses our own {@link Help} template class instead of the one from @oclif/core.
|
|
8
9
|
*
|
|
9
10
|
* @see https://github.com/oclif/plugin-help/blob/67b580570257b45e92d3a04d50bf2a432c59afe3/src/commands/help.ts
|
|
10
11
|
*/
|
|
11
|
-
class HelpCommand extends
|
|
12
|
+
class HelpCommand extends base_command_1.BaseCommand {
|
|
12
13
|
async run() {
|
|
13
14
|
const { argv } = await this.parse();
|
|
14
15
|
const help = new help_1.default(this.config, { all: true });
|
package/lib/commands/help.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"/","sources":["commands/help.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"/","sources":["commands/help.ts"],"names":[],"mappings":";;;AAAA,sCAAmC;AACnC,iEAAiC;AACjC,wDAAoD;AAEpD;;;;GAIG;AACH,MAAqB,WAAY,SAAQ,0BAA+B;IAYtE,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,cAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAgB,CAAC,CAAC;IACxC,CAAC;;AAfe;;;;WAAS,KAAK;GAAC;AAEf;;;;WAAU,uBAAuB;GAAC;AAElC;;;;WAAO;QACrB,OAAO,EAAE,WAAI,CAAC,MAAM,CAAC;YACnB,QAAQ,EAAE,KAAK;YACf,WAAW,EAAE,+BAA+B;SAC7C,CAAC;KACH;GAAC;kBAViB,WAAW","sourcesContent":["import { Args } from \"@oclif/core\";\nimport Help from \"../utils/help\";\nimport { BaseCommand } from \"../utils/base-command\";\n\n/**\n * Copied from @oclif/plugin-help. Uses our own {@link Help} template class instead of the one from @oclif/core.\n *\n * @see https://github.com/oclif/plugin-help/blob/67b580570257b45e92d3a04d50bf2a432c59afe3/src/commands/help.ts\n */\nexport default class HelpCommand extends BaseCommand<typeof HelpCommand> {\n static override strict = false;\n\n static override summary = \"Display help for ggt.\";\n\n static override args = {\n command: Args.string({\n required: false,\n description: \"The command to show help for.\",\n }),\n };\n\n async run(): Promise<void> {\n const { argv } = await this.parse();\n const help = new Help(this.config, { all: true });\n await help.showHelp(argv as string[]);\n }\n}\n"]}
|
package/lib/commands/list.d.ts
CHANGED
package/lib/commands/list.js
CHANGED
|
@@ -7,15 +7,24 @@ const ts_dedent_1 = tslib_1.__importDefault(require("ts-dedent"));
|
|
|
7
7
|
const base_command_1 = require("../utils/base-command");
|
|
8
8
|
const context_1 = require("../utils/context");
|
|
9
9
|
class List extends base_command_1.BaseCommand {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
Object.defineProperty(this, "requireUser", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: true
|
|
17
|
+
});
|
|
18
|
+
}
|
|
10
19
|
async run() {
|
|
11
20
|
const { flags } = await this.parse(List);
|
|
12
|
-
const user = await context_1.context.getUser();
|
|
13
|
-
if (!user) {
|
|
14
|
-
this.error("You are not logged in -- no apps available", { exit: 1 });
|
|
15
|
-
}
|
|
16
21
|
const apps = await context_1.context.getAvailableApps();
|
|
17
|
-
if (apps.length
|
|
18
|
-
this.log(
|
|
22
|
+
if (!apps.length) {
|
|
23
|
+
this.log((0, ts_dedent_1.default) `
|
|
24
|
+
It doesn't look like you have any applications.
|
|
25
|
+
|
|
26
|
+
Visit https://gadget.new to create one!
|
|
27
|
+
`);
|
|
19
28
|
return;
|
|
20
29
|
}
|
|
21
30
|
core_1.ux.table(apps, {
|
package/lib/commands/list.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"/","sources":["commands/list.ts"],"names":[],"mappings":";;;AAAA,0DAA0B;AAC1B,sCAAiC;AACjC,kEAA+B;AAC/B,wDAAoD;AAEpD,8CAA2C;AAE3C,MAAqB,IAAK,SAAQ,0BAAwB;
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"/","sources":["commands/list.ts"],"names":[],"mappings":";;;AAAA,0DAA0B;AAC1B,sCAAiC;AACjC,kEAA+B;AAC/B,wDAAoD;AAEpD,8CAA2C;AAE3C,MAAqB,IAAK,SAAQ,0BAAwB;IAA1D;;QAiBW;;;;mBAAc,IAAI;WAAC;IAmC9B,CAAC;IAjCC,KAAK,CAAC,GAAG;QACP,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEzC,MAAM,IAAI,GAAG,MAAM,iBAAO,CAAC,gBAAgB,EAAE,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAChB,IAAI,CAAC,GAAG,CAAC,IAAA,mBAAM,EAAA;;;;OAId,CAAC,CAAC;YACH,OAAO;SACR;QAED,SAAE,CAAC,KAAK,CACN,IAAkD,EAClD;YACE,EAAE,EAAE;gBACF,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,IAAI;aACf;YACD,IAAI,EAAE;gBACJ,MAAM,EAAE,MAAM;aACf;YACD,aAAa,EAAE;gBACb,MAAM,EAAE,QAAQ;aACjB;SACF,EACD;YACE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC9B,GAAG,KAAK,EAAE,eAAe;SAC1B,CACF,CAAC;IACJ,CAAC;;AAlDe;;;;WAAU,0DAA0D;EAA7D,CAA8D;AAErE;;;;WAAQ,MAAM;EAAT,CAAU;AAEf;;;;WAAW;QACzB,IAAA,mBAAM,EAAC,IAAA,eAAK,EAAA;;;;KAIX,CAAC;KACH;EANuB,CAMtB;AAEc;;;;WAAQ;QACtB,GAAG,SAAE,CAAC,KAAK,CAAC,KAAK,EAAE;KACpB;EAFoB,CAEnB;kBAfiB,IAAI","sourcesContent":["import chalk from \"chalk\";\nimport { ux } from \"@oclif/core\";\nimport dedent from \"ts-dedent\";\nimport { BaseCommand } from \"../utils/base-command\";\nimport type { App } from \"../utils/context\";\nimport { context } from \"../utils/context\";\n\nexport default class List extends BaseCommand<typeof List> {\n static override summary = \"List the apps available to the currently logged in user.\";\n\n static override usage = \"list\";\n\n static override examples = [\n dedent(chalk`\n {gray $ ggt list}\n {gray $ ggt list --extended}\n {gray $ ggt list --sort=slug}\n `),\n ];\n\n static override flags = {\n ...ux.table.flags(),\n };\n\n override requireUser = true;\n\n async run(): Promise<void> {\n const { flags } = await this.parse(List);\n\n const apps = await context.getAvailableApps();\n if (!apps.length) {\n this.log(dedent`\n It doesn't look like you have any applications.\n\n Visit https://gadget.new to create one!\n `);\n return;\n }\n\n ux.table<App & Record<string, never>>(\n apps as unknown as (App & Record<string, never>)[],\n {\n id: {\n header: \"ID\",\n extended: true,\n },\n slug: {\n header: \"Slug\",\n },\n primaryDomain: {\n header: \"Domain\",\n },\n },\n {\n printLine: this.log.bind(this),\n ...flags, // parsed flags\n }\n );\n }\n}\n"]}
|
package/lib/commands/sync.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import PQueue from "p-queue";
|
|
|
4
4
|
import { BaseCommand } from "../utils/base-command";
|
|
5
5
|
import type { Query } from "../utils/client";
|
|
6
6
|
import { Client } from "../utils/client";
|
|
7
|
-
import {
|
|
7
|
+
import { FSIgnorer } from "../utils/fs-utils";
|
|
8
8
|
import type { PublishFileSyncEventsMutation, PublishFileSyncEventsMutationVariables, RemoteFilesVersionQuery, RemoteFilesVersionQueryVariables, RemoteFileSyncEventsSubscription, RemoteFileSyncEventsSubscriptionVariables } from "../__generated__/graphql";
|
|
9
9
|
export default class Sync extends BaseCommand<typeof Sync> {
|
|
10
10
|
static priority: number;
|
|
@@ -23,29 +23,104 @@ export default class Sync extends BaseCommand<typeof Sync> {
|
|
|
23
23
|
};
|
|
24
24
|
static examples: string[];
|
|
25
25
|
requireUser: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The current status of the sync process.
|
|
28
|
+
*/
|
|
26
29
|
status: SyncStatus;
|
|
30
|
+
/**
|
|
31
|
+
* The absolute path to the directory to sync files to.
|
|
32
|
+
*/
|
|
27
33
|
dir: string;
|
|
28
|
-
|
|
34
|
+
/**
|
|
35
|
+
* A list of filepaths that have changed because of a remote file-sync event. This is used to avoid sending files that
|
|
36
|
+
* we recently received from a remote file-sync event.
|
|
37
|
+
*/
|
|
38
|
+
recentRemoteChanges: Set<unknown>;
|
|
39
|
+
/**
|
|
40
|
+
* A FIFO async callback queue that ensures we process file-sync events in the order they occurred.
|
|
41
|
+
*/
|
|
29
42
|
queue: PQueue<import("p-queue/dist/priority-queue").default, import("p-queue").DefaultAddOptions>;
|
|
43
|
+
/**
|
|
44
|
+
* A GraphQL client connected to the app's /edit/api/graphql-ws endpoint
|
|
45
|
+
*/
|
|
30
46
|
client: Client;
|
|
31
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Loads the .ignore file and provides methods for checking if a file should be ignored.
|
|
49
|
+
*/
|
|
50
|
+
ignorer: FSIgnorer;
|
|
51
|
+
/**
|
|
52
|
+
* Watches the local filesystem for changes.
|
|
53
|
+
*/
|
|
32
54
|
watcher: FSWatcher;
|
|
55
|
+
/**
|
|
56
|
+
* Holds information about the state of the local filesystem. It's persisted to `.gadget/sync.json`.
|
|
57
|
+
*/
|
|
33
58
|
metadata: {
|
|
59
|
+
/**
|
|
60
|
+
* The app this filesystem is synced to.
|
|
61
|
+
*/
|
|
34
62
|
app: string;
|
|
63
|
+
/**
|
|
64
|
+
* The last filesVersion that was successfully written to the filesystem. This is used to determine if the remote
|
|
65
|
+
* filesystem is ahead of the local one.
|
|
66
|
+
*/
|
|
35
67
|
filesVersion: string;
|
|
68
|
+
/**
|
|
69
|
+
* The largest mtime that was seen on the local filesystem before `ggt sync` stopped. This is used to determine if
|
|
70
|
+
* the local filesystem has changed since the last sync.
|
|
71
|
+
*
|
|
72
|
+
* Note: This does not include the mtime of files that are ignored.
|
|
73
|
+
*/
|
|
36
74
|
mtime: number;
|
|
37
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* A debounced function that enqueue's local file changes to be sent to Gadget.
|
|
78
|
+
*/
|
|
38
79
|
publish: DebouncedFunc<() => void>;
|
|
80
|
+
/**
|
|
81
|
+
* Gracefully stops the sync.
|
|
82
|
+
*/
|
|
39
83
|
stop: (error?: unknown) => Promise<void>;
|
|
40
|
-
|
|
41
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Turns an absolute filepath into a relative one from {@linkcode dir}.
|
|
86
|
+
*/
|
|
42
87
|
relative(to: string): string;
|
|
88
|
+
/**
|
|
89
|
+
* Combines path segments into an absolute filepath that starts at {@linkcode dir}.
|
|
90
|
+
*/
|
|
43
91
|
absolute(...pathSegments: string[]): string;
|
|
92
|
+
/**
|
|
93
|
+
* Similar to {@linkcode relative} in that it turns a filepath into a relative one from {@linkcode dir}. However, it
|
|
94
|
+
* also changes any slashes to be posix/unix-like forward slashes, condenses repeat slashes into a single slash.
|
|
95
|
+
*
|
|
96
|
+
* This is used when sending file-sync events to Gadget to ensure that the paths are consistent across platforms.
|
|
97
|
+
*
|
|
98
|
+
* @see https://www.npmjs.com/package/normalize-path
|
|
99
|
+
*/
|
|
44
100
|
normalize(filepath: string, isDirectory?: boolean): string;
|
|
101
|
+
/**
|
|
102
|
+
* Pretty-prints changed and deleted filepaths to the console.
|
|
103
|
+
*
|
|
104
|
+
* @param prefix The prefix to print before each line.
|
|
105
|
+
* @param changed The filepaths that have changed.
|
|
106
|
+
* @param deleted The filepaths that have been deleted.
|
|
107
|
+
* @param options.limit The maximum number of lines to print. Defaults to 10. If debug is enabled, this is ignored.
|
|
108
|
+
*/
|
|
45
109
|
logPaths(prefix: string, changed: string[], deleted: string[], { limit }?: {
|
|
46
110
|
limit?: number | undefined;
|
|
47
111
|
}): void;
|
|
112
|
+
/**
|
|
113
|
+
* Initializes the sync process.
|
|
114
|
+
* - Ensures the directory exists.
|
|
115
|
+
* - Ensures the directory is empty or contains a `.gadget/sync.json` file.
|
|
116
|
+
* - Ensures an app is selected and that it matches the app the directory was previously synced to.
|
|
117
|
+
* - Ensures yarn v1 is installed.
|
|
118
|
+
* - Prompts the user how to resolve conflicts if the local filesystem has changed since the last sync.
|
|
119
|
+
*/
|
|
48
120
|
init(): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* Runs the sync process until it is stopped or an error occurs.
|
|
123
|
+
*/
|
|
49
124
|
run(): Promise<void>;
|
|
50
125
|
}
|
|
51
126
|
export declare enum SyncStatus {
|
package/lib/commands/sync.js
CHANGED
|
@@ -12,7 +12,6 @@ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
|
12
12
|
const inquirer_1 = require("inquirer");
|
|
13
13
|
const lodash_1 = require("lodash");
|
|
14
14
|
const lodash_2 = require("lodash");
|
|
15
|
-
const lodash_3 = require("lodash");
|
|
16
15
|
const normalize_path_1 = tslib_1.__importDefault(require("normalize-path"));
|
|
17
16
|
const p_map_1 = tslib_1.__importDefault(require("p-map"));
|
|
18
17
|
const p_queue_1 = tslib_1.__importDefault(require("p-queue"));
|
|
@@ -27,6 +26,7 @@ const errors_1 = require("../utils/errors");
|
|
|
27
26
|
const flags_1 = require("../utils/flags");
|
|
28
27
|
const fs_utils_1 = require("../utils/fs-utils");
|
|
29
28
|
const graphql_1 = require("../__generated__/graphql");
|
|
29
|
+
const promise_1 = require("../utils/promise");
|
|
30
30
|
class Sync extends base_command_1.BaseCommand {
|
|
31
31
|
constructor() {
|
|
32
32
|
super(...arguments);
|
|
@@ -36,92 +36,146 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
36
36
|
writable: true,
|
|
37
37
|
value: true
|
|
38
38
|
});
|
|
39
|
+
/**
|
|
40
|
+
* The current status of the sync process.
|
|
41
|
+
*/
|
|
39
42
|
Object.defineProperty(this, "status", {
|
|
40
43
|
enumerable: true,
|
|
41
44
|
configurable: true,
|
|
42
45
|
writable: true,
|
|
43
46
|
value: SyncStatus.STARTING
|
|
44
47
|
});
|
|
48
|
+
/**
|
|
49
|
+
* The absolute path to the directory to sync files to.
|
|
50
|
+
*/
|
|
45
51
|
Object.defineProperty(this, "dir", {
|
|
46
52
|
enumerable: true,
|
|
47
53
|
configurable: true,
|
|
48
54
|
writable: true,
|
|
49
55
|
value: void 0
|
|
50
56
|
});
|
|
51
|
-
|
|
57
|
+
/**
|
|
58
|
+
* A list of filepaths that have changed because of a remote file-sync event. This is used to avoid sending files that
|
|
59
|
+
* we recently received from a remote file-sync event.
|
|
60
|
+
*/
|
|
61
|
+
Object.defineProperty(this, "recentRemoteChanges", {
|
|
52
62
|
enumerable: true,
|
|
53
63
|
configurable: true,
|
|
54
64
|
writable: true,
|
|
55
65
|
value: new Set()
|
|
56
66
|
});
|
|
67
|
+
/**
|
|
68
|
+
* A FIFO async callback queue that ensures we process file-sync events in the order they occurred.
|
|
69
|
+
*/
|
|
57
70
|
Object.defineProperty(this, "queue", {
|
|
58
71
|
enumerable: true,
|
|
59
72
|
configurable: true,
|
|
60
73
|
writable: true,
|
|
61
74
|
value: new p_queue_1.default({ concurrency: 1 })
|
|
62
75
|
});
|
|
76
|
+
/**
|
|
77
|
+
* A GraphQL client connected to the app's /edit/api/graphql-ws endpoint
|
|
78
|
+
*/
|
|
63
79
|
Object.defineProperty(this, "client", {
|
|
64
80
|
enumerable: true,
|
|
65
81
|
configurable: true,
|
|
66
82
|
writable: true,
|
|
67
83
|
value: void 0
|
|
68
84
|
});
|
|
85
|
+
/**
|
|
86
|
+
* Loads the .ignore file and provides methods for checking if a file should be ignored.
|
|
87
|
+
*/
|
|
69
88
|
Object.defineProperty(this, "ignorer", {
|
|
70
89
|
enumerable: true,
|
|
71
90
|
configurable: true,
|
|
72
91
|
writable: true,
|
|
73
92
|
value: void 0
|
|
74
93
|
});
|
|
94
|
+
/**
|
|
95
|
+
* Watches the local filesystem for changes.
|
|
96
|
+
*/
|
|
75
97
|
Object.defineProperty(this, "watcher", {
|
|
76
98
|
enumerable: true,
|
|
77
99
|
configurable: true,
|
|
78
100
|
writable: true,
|
|
79
101
|
value: void 0
|
|
80
102
|
});
|
|
103
|
+
/**
|
|
104
|
+
* Holds information about the state of the local filesystem. It's persisted to `.gadget/sync.json`.
|
|
105
|
+
*/
|
|
81
106
|
Object.defineProperty(this, "metadata", {
|
|
82
107
|
enumerable: true,
|
|
83
108
|
configurable: true,
|
|
84
109
|
writable: true,
|
|
85
110
|
value: {
|
|
111
|
+
/**
|
|
112
|
+
* The app this filesystem is synced to.
|
|
113
|
+
*/
|
|
86
114
|
app: "",
|
|
115
|
+
/**
|
|
116
|
+
* The last filesVersion that was successfully written to the filesystem. This is used to determine if the remote
|
|
117
|
+
* filesystem is ahead of the local one.
|
|
118
|
+
*/
|
|
87
119
|
filesVersion: "0",
|
|
120
|
+
/**
|
|
121
|
+
* The largest mtime that was seen on the local filesystem before `ggt sync` stopped. This is used to determine if
|
|
122
|
+
* the local filesystem has changed since the last sync.
|
|
123
|
+
*
|
|
124
|
+
* Note: This does not include the mtime of files that are ignored.
|
|
125
|
+
*/
|
|
88
126
|
mtime: 0,
|
|
89
127
|
}
|
|
90
128
|
});
|
|
129
|
+
/**
|
|
130
|
+
* A debounced function that enqueue's local file changes to be sent to Gadget.
|
|
131
|
+
*/
|
|
91
132
|
Object.defineProperty(this, "publish", {
|
|
92
133
|
enumerable: true,
|
|
93
134
|
configurable: true,
|
|
94
135
|
writable: true,
|
|
95
136
|
value: void 0
|
|
96
137
|
});
|
|
138
|
+
/**
|
|
139
|
+
* Gracefully stops the sync.
|
|
140
|
+
*/
|
|
97
141
|
Object.defineProperty(this, "stop", {
|
|
98
142
|
enumerable: true,
|
|
99
143
|
configurable: true,
|
|
100
144
|
writable: true,
|
|
101
145
|
value: void 0
|
|
102
146
|
});
|
|
103
|
-
Object.defineProperty(this, "finished", {
|
|
104
|
-
enumerable: true,
|
|
105
|
-
configurable: true,
|
|
106
|
-
writable: true,
|
|
107
|
-
value: void 0
|
|
108
|
-
});
|
|
109
|
-
Object.defineProperty(this, "markFinished", {
|
|
110
|
-
enumerable: true,
|
|
111
|
-
configurable: true,
|
|
112
|
-
writable: true,
|
|
113
|
-
value: void 0
|
|
114
|
-
});
|
|
115
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* Turns an absolute filepath into a relative one from {@linkcode dir}.
|
|
150
|
+
*/
|
|
116
151
|
relative(to) {
|
|
117
152
|
return path_1.default.relative(this.dir, to);
|
|
118
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Combines path segments into an absolute filepath that starts at {@linkcode dir}.
|
|
156
|
+
*/
|
|
119
157
|
absolute(...pathSegments) {
|
|
120
158
|
return path_1.default.resolve(this.dir, ...pathSegments);
|
|
121
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Similar to {@linkcode relative} in that it turns a filepath into a relative one from {@linkcode dir}. However, it
|
|
162
|
+
* also changes any slashes to be posix/unix-like forward slashes, condenses repeat slashes into a single slash.
|
|
163
|
+
*
|
|
164
|
+
* This is used when sending file-sync events to Gadget to ensure that the paths are consistent across platforms.
|
|
165
|
+
*
|
|
166
|
+
* @see https://www.npmjs.com/package/normalize-path
|
|
167
|
+
*/
|
|
122
168
|
normalize(filepath, isDirectory = false) {
|
|
123
169
|
return (0, normalize_path_1.default)(path_1.default.isAbsolute(filepath) ? this.relative(filepath) : filepath) + (isDirectory ? "/" : "");
|
|
124
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Pretty-prints changed and deleted filepaths to the console.
|
|
173
|
+
*
|
|
174
|
+
* @param prefix The prefix to print before each line.
|
|
175
|
+
* @param changed The filepaths that have changed.
|
|
176
|
+
* @param deleted The filepaths that have been deleted.
|
|
177
|
+
* @param options.limit The maximum number of lines to print. Defaults to 10. If debug is enabled, this is ignored.
|
|
178
|
+
*/
|
|
125
179
|
logPaths(prefix, changed, deleted, { limit = 10 } = {}) {
|
|
126
180
|
const lines = (0, lodash_1.sortBy)([
|
|
127
181
|
...changed.map((filepath) => (0, chalk_1.default) `{green ${prefix}} ${this.normalize(filepath)} {gray (changed)}`),
|
|
@@ -139,9 +193,16 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
139
193
|
this.log((0, chalk_1.default) `{gray ${(0, pluralize_1.default)("file", lines.length, true)} in total. ${changed.length} changed, ${deleted.length} deleted.}`);
|
|
140
194
|
this.log();
|
|
141
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Initializes the sync process.
|
|
198
|
+
* - Ensures the directory exists.
|
|
199
|
+
* - Ensures the directory is empty or contains a `.gadget/sync.json` file.
|
|
200
|
+
* - Ensures an app is selected and that it matches the app the directory was previously synced to.
|
|
201
|
+
* - Ensures yarn v1 is installed.
|
|
202
|
+
* - Prompts the user how to resolve conflicts if the local filesystem has changed since the last sync.
|
|
203
|
+
*/
|
|
142
204
|
async init() {
|
|
143
205
|
await super.init();
|
|
144
|
-
(0, assert_1.default)((0, lodash_2.isString)(this.args["directory"]));
|
|
145
206
|
this.dir =
|
|
146
207
|
this.config.windows && this.args["directory"].startsWith("~/")
|
|
147
208
|
? path_1.default.join(this.config.home, this.args["directory"].slice(2))
|
|
@@ -182,7 +243,7 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
182
243
|
await context_1.context.setApp(this.metadata.app);
|
|
183
244
|
this.client = new client_1.Client();
|
|
184
245
|
// local files/folders that should never be published
|
|
185
|
-
this.ignorer = new fs_utils_1.
|
|
246
|
+
this.ignorer = new fs_utils_1.FSIgnorer(this.dir, ["node_modules", ".gadget", ".git"]);
|
|
186
247
|
this.watcher = new chokidar_1.FSWatcher({
|
|
187
248
|
ignored: (filepath) => this.ignorer.ignores(filepath),
|
|
188
249
|
// don't emit an event for every watched file on boot
|
|
@@ -207,7 +268,7 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
207
268
|
files.set(this.absolute(filepath), stats);
|
|
208
269
|
}
|
|
209
270
|
}
|
|
210
|
-
//
|
|
271
|
+
// never include the root directory
|
|
211
272
|
files.delete(this.dir);
|
|
212
273
|
return files;
|
|
213
274
|
};
|
|
@@ -232,7 +293,9 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
232
293
|
case Action.MERGE: {
|
|
233
294
|
// get all the changed files again in case more changed
|
|
234
295
|
const files = await getChangedFiles();
|
|
235
|
-
//
|
|
296
|
+
// We purposefully don't set the returned remoteFilesVersion here because we haven't received the remote changes
|
|
297
|
+
// yet. This will cause us to receive the local files that we just published + the remote files that were
|
|
298
|
+
// changed since the last sync.
|
|
236
299
|
await this.client.queryUnwrap({
|
|
237
300
|
query: exports.PUBLISH_FILE_SYNC_EVENTS_MUTATION,
|
|
238
301
|
variables: {
|
|
@@ -257,6 +320,8 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
257
320
|
break;
|
|
258
321
|
}
|
|
259
322
|
case Action.RESET: {
|
|
323
|
+
// delete all the local files that have changed since the last sync and set the files version to 0 so we receive
|
|
324
|
+
// all the remote files again, including any files that we just deleted that still exist
|
|
260
325
|
await (0, p_map_1.default)(changedFiles, ([filepath]) => fs_extra_1.default.remove(filepath));
|
|
261
326
|
this.metadata.filesVersion = "0";
|
|
262
327
|
break;
|
|
@@ -267,11 +332,12 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
267
332
|
}
|
|
268
333
|
this.debug("started");
|
|
269
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* Runs the sync process until it is stopped or an error occurs.
|
|
337
|
+
*/
|
|
270
338
|
async run() {
|
|
271
339
|
let error;
|
|
272
|
-
|
|
273
|
-
this.markFinished = resolve;
|
|
274
|
-
});
|
|
340
|
+
const stopped = new promise_1.PromiseSignal();
|
|
275
341
|
this.stop = async (e) => {
|
|
276
342
|
if (this.status != SyncStatus.RUNNING)
|
|
277
343
|
return;
|
|
@@ -289,7 +355,7 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
289
355
|
await Promise.allSettled([this.watcher.close(), this.client.dispose()]);
|
|
290
356
|
this.debug("stopped");
|
|
291
357
|
this.status = SyncStatus.STOPPED;
|
|
292
|
-
|
|
358
|
+
stopped.resolve();
|
|
293
359
|
}
|
|
294
360
|
};
|
|
295
361
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
@@ -334,10 +400,10 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
334
400
|
return;
|
|
335
401
|
}
|
|
336
402
|
const filepath = this.absolute(file.path);
|
|
337
|
-
this.
|
|
403
|
+
this.recentRemoteChanges.add(filepath);
|
|
338
404
|
if ("content" in file) {
|
|
339
405
|
if (!file.path.endsWith("/")) {
|
|
340
|
-
this.
|
|
406
|
+
this.recentRemoteChanges.add(path_1.default.dirname(filepath));
|
|
341
407
|
await fs_extra_1.default.ensureDir(path_1.default.dirname(filepath), { mode: 0o755 });
|
|
342
408
|
await fs_extra_1.default.writeFile(filepath, Buffer.from(file.content, file.encoding ?? graphql_1.FileSyncEncoding.Utf8), {
|
|
343
409
|
mode: file.mode,
|
|
@@ -370,7 +436,7 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
370
436
|
},
|
|
371
437
|
});
|
|
372
438
|
const localFilesBuffer = new Map();
|
|
373
|
-
this.publish = (0,
|
|
439
|
+
this.publish = (0, lodash_2.debounce)(() => {
|
|
374
440
|
const localFiles = new Map(localFilesBuffer.entries());
|
|
375
441
|
localFilesBuffer.clear();
|
|
376
442
|
void this.queue
|
|
@@ -391,8 +457,8 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
391
457
|
});
|
|
392
458
|
}
|
|
393
459
|
catch (error) {
|
|
394
|
-
// A file could have been changed and then deleted before we process the change event, so the readFile
|
|
395
|
-
// an ENOENT. This is normal operation, so just ignore this event.
|
|
460
|
+
// A file could have been changed and then deleted before we process the change event, so the readFile
|
|
461
|
+
// above will raise an ENOENT. This is normal operation, so just ignore this event.
|
|
396
462
|
(0, fs_utils_1.ignoreEnoent)(error);
|
|
397
463
|
}
|
|
398
464
|
}
|
|
@@ -430,12 +496,13 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
430
496
|
this.debug("skipping event caused by ignored file %s", relativePath);
|
|
431
497
|
return;
|
|
432
498
|
}
|
|
433
|
-
// we only update the mtime if the file is not ignored, because if we restart and the mtime is set to an ignored
|
|
434
|
-
// be greater than the mtime of all non ignored files and we'll think that local files have
|
|
499
|
+
// we only update the mtime if the file is not ignored, because if we restart and the mtime is set to an ignored
|
|
500
|
+
// file, then it could be greater than the mtime of all non ignored files and we'll think that local files have
|
|
501
|
+
// changed when only an ignored one has
|
|
435
502
|
if (stats && stats.mtime.getTime() > this.metadata.mtime) {
|
|
436
503
|
this.metadata.mtime = stats.mtime.getTime();
|
|
437
504
|
}
|
|
438
|
-
if (this.
|
|
505
|
+
if (this.recentRemoteChanges.delete(filepath)) {
|
|
439
506
|
this.debug("skipping event caused by recent write %s", relativePath);
|
|
440
507
|
return;
|
|
441
508
|
}
|
|
@@ -479,7 +546,7 @@ class Sync extends base_command_1.BaseCommand {
|
|
|
479
546
|
Watching for file changes... {gray Press Ctrl+C to stop}
|
|
480
547
|
`));
|
|
481
548
|
this.log();
|
|
482
|
-
await
|
|
549
|
+
await stopped;
|
|
483
550
|
if (error) {
|
|
484
551
|
this.notify({ subtitle: "Uh oh!", message: "An error occurred while syncing files" });
|
|
485
552
|
throw error;
|