gdrive-syncer 2.2.0 → 3.1.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/Readme.md CHANGED
@@ -4,15 +4,54 @@ A command line tool to manage sync folders with Google Drive. Features two-way s
4
4
 
5
5
  ## Prerequisites
6
6
 
7
- Install and setup [gdrive](https://github.com/prasmussen/gdrive)
7
+ Install the gdrive CLI. This tool supports both gdrive@2 and gdrive@3.
8
8
 
9
- ## Login
9
+ ### Option 1: gdrive@3 (recommended)
10
+
11
+ Install [gdrive@3](https://github.com/glotlabs/gdrive) via Homebrew:
12
+
13
+ ```bash
14
+ brew install gdrive
15
+ ```
16
+
17
+ Setup requires Google OAuth credentials.
18
+
19
+ > **Before you start:** Ask your team if someone already has OAuth credentials set up for gdrive. Sharing existing credentials avoids creating duplicate Google Cloud projects and simplifies onboarding.
20
+
21
+ #### Setting up OAuth credentials
22
+
23
+ 1. Go to [Google Cloud Console](https://console.cloud.google.com/)
24
+ 2. Create a new project or select existing
25
+ 3. Enable the Google Drive API
26
+ 4. Configure OAuth consent screen:
27
+ - **For organizations (Google Workspace):** Select **Internal** user type. This avoids the app review process and allows immediate use by your team.
28
+ - **For personal accounts:** Select **External** and add your email as a test user.
29
+ 5. Create OAuth 2.0 credentials (Desktop application)
30
+ 6. Add an account:
31
+ ```bash
32
+ gdrive account add
33
+ ```
34
+ 7. Enter your Client ID and Client Secret when prompted
35
+ 8. Complete the OAuth flow in your browser
36
+
37
+ > **Tip:** If you're in an organization, using **Internal** OAuth consent means the app is automatically trusted for all users in your domain—no verification required.
38
+
39
+ **Note:** gdrive@3 does not support `gdrive sync` commands. Use the `filesync:*` commands instead.
40
+
41
+ ### Option 2: gdrive@2 (legacy)
42
+
43
+ [gdrive@2](https://github.com/prasmussen/gdrive) is deprecated and no longer available via Homebrew. If you have it installed, login with:
10
44
 
11
- After [gdrive](https://github.com/prasmussen/gdrive) is installed, login to your Google Drive account:
12
45
  ```bash
13
46
  gdrive about
14
47
  ```
15
48
 
49
+ ### Verify Installation
50
+
51
+ ```bash
52
+ gdrive version
53
+ ```
54
+
16
55
  ## Installation
17
56
 
18
57
  ```bash
@@ -33,14 +72,15 @@ Run without arguments for interactive menu, or use direct commands.
33
72
 
34
73
  | Command | Description |
35
74
  |---------|-------------|
36
- | `filesync:diff [local\|global]` | Show differences between local and Drive |
37
- | `filesync:download [local\|global]` | Download changed files from Drive |
38
- | `filesync:upload [local\|global]` | Upload changed files to Drive |
75
+ | `filesync:diff [local\|global\|registered]` | Show differences between local and Drive |
76
+ | `filesync:download [local\|global\|registered]` | Download changed files from Drive |
77
+ | `filesync:upload [local\|global\|registered]` | Upload changed files to Drive |
39
78
  | `filesync:init` | Create or add to `.gdrive-sync.json` config |
40
79
  | `filesync:show` | Show sync configurations |
41
80
  | `filesync:remove` | Remove a sync from config |
42
81
  | `filesync:register` | Register local config to global registry |
43
82
  | `filesync:unregister` | Remove from global registry |
83
+ | `filesync:migrate` | Migrate legacy syncs to Files Sync format |
44
84
 
45
85
  ### Drive Operations
46
86
 
@@ -51,7 +91,9 @@ Run without arguments for interactive menu, or use direct commands.
51
91
  | `drive:mkdir` | Create a directory in Drive |
52
92
  | `drive:delete` | Delete a file/folder from Drive |
53
93
 
54
- ### Legacy Sync (gdrive sync upload)
94
+ ### Legacy Sync (gdrive@2 only)
95
+
96
+ **Note:** These commands require gdrive@2. They are not available with gdrive@3.
55
97
 
56
98
  | Command | Description |
57
99
  |---------|-------------|
@@ -174,15 +216,35 @@ Patterns support glob-style matching with the following features:
174
216
 
175
217
  ### Features
176
218
 
219
+ - **Nested folder support** - Recursively syncs files in subdirectories
177
220
  - **Multiple sync folders** - Configure multiple sync pairs in one config
178
221
  - **Local & Global configs** - Per-project or machine-wide configurations
179
- - **File patterns** - Filter files by pattern
222
+ - **File patterns** - Filter files by pattern (applied to filenames, not paths)
180
223
  - **Auto-discovery** - Finds local config in current or parent directories
181
- - **Git-style diffs** - Colored diff output showing changes
182
- - **Automatic backups** - Creates timestamped backups before download
224
+ - **Git-style diffs** - Colored diff output showing changes with full paths
225
+ - **Automatic backups** - Creates timestamped backups before download (preserves folder structure)
183
226
  - **Two-way sync** - Upload local changes or download from Drive
227
+ - **Optional deletion** - Prompts to delete orphan files/folders after sync
184
228
  - **Sync All** - Run operations on all syncs within selected config
185
229
  - **Registered Local Configs** - Run sync on multiple projects from anywhere
230
+ - **Auto-create folders** - Creates missing folders on Drive during upload
231
+
232
+ ### Sync Behavior
233
+
234
+ The sync compares files between local and Drive, showing:
235
+
236
+ | Status | Diff | Upload | Download |
237
+ |--------|------|--------|----------|
238
+ | **Modified** | Shows diff | Updates on Drive | Updates locally |
239
+ | **Local only** | Listed | Uploads to Drive | Prompts to delete |
240
+ | **Drive only** | Listed | Prompts to delete | Downloads locally |
241
+ | **Empty folders** | Listed | Prompts to delete | — |
242
+
243
+ **Delete prompts:**
244
+ - **Upload**: After uploading, prompts to delete files/folders on Drive that don't exist locally
245
+ - **Download**: After downloading, prompts to delete local files that don't exist on Drive (backup is created first)
246
+
247
+ This ensures you can keep Drive in sync with local (or vice versa) without accumulating orphan files.
186
248
 
187
249
  ### Registered Local Configs
188
250
 
@@ -213,7 +275,9 @@ gdrive-syncer filesync:diff
213
275
  4. Multi-select which projects to sync
214
276
  5. Operation runs on all selected projects
215
277
 
216
- ## Legacy Sync Configuration
278
+ ## Legacy Sync Configuration (gdrive@2 only)
279
+
280
+ > **Note:** Legacy sync requires gdrive@2. If you have gdrive@3 installed, use Files Sync (`filesync:*` commands) instead.
217
281
 
218
282
  Legacy sync uses the `gdrive sync upload` command under the hood. Configuration is stored globally at:
219
283
 
@@ -287,10 +351,30 @@ gdrive-syncer sync:upload
287
351
  gdrive-syncer sync:list
288
352
  ```
289
353
 
354
+ ## Migrating from Legacy Sync to Files Sync
355
+
356
+ If you have existing legacy sync configurations (`~/.gdrive_syncer/gdrive.config.json`), you can migrate them to the new Files Sync format:
357
+
358
+ ```bash
359
+ gdrive-syncer filesync:migrate
360
+ ```
361
+
362
+ The migration wizard:
363
+ 1. Shows all legacy syncs and lets you select which to migrate
364
+ 2. For each sync, asks whether to save to **Local** or **Global** config
365
+ 3. For local configs, calculates the relative path from the config location
366
+ 4. Warns if the path is outside the project directory (suggests using global instead)
367
+ 5. Lets you set a file pattern (default: `*` for all files)
368
+ 6. Shows a preview before confirming
369
+ 7. Optionally removes migrated syncs from the legacy config
370
+
371
+ This is not a one-time migration—you can run it multiple times to gradually migrate syncs as needed.
372
+
290
373
  ## Files Sync vs Legacy Sync
291
374
 
292
375
  | Feature | Files Sync | Legacy Sync |
293
376
  |---------|----------|-------------|
377
+ | **gdrive version** | gdrive@2 and gdrive@3 | gdrive@2 only |
294
378
  | Config location | Local (`.gdrive-sync.json`) or Global (`~/.gdrive_syncer/env-sync.json`) | `~/.gdrive_syncer/gdrive.config.json` (global only) |
295
379
  | Direction | Two-way (upload & download) | One-way (upload only) |
296
380
  | File patterns | Supported (`.env.*`, `*`) | All files in folder |
@@ -318,6 +402,9 @@ gdrive-syncer filesync:diff local
318
402
  # Show differences for global config only
319
403
  gdrive-syncer filesync:diff global
320
404
 
405
+ # Show differences for registered local configs
406
+ gdrive-syncer filesync:diff registered
407
+
321
408
  # Download from Drive (with backup)
322
409
  gdrive-syncer filesync:download
323
410
  gdrive-syncer filesync:download local
@@ -326,6 +413,9 @@ gdrive-syncer filesync:download local
326
413
  gdrive-syncer filesync:upload
327
414
  gdrive-syncer filesync:upload global
328
415
 
416
+ # Upload from all registered configs
417
+ gdrive-syncer filesync:upload registered
418
+
329
419
  # Initialize config (choose Local or Global)
330
420
  gdrive-syncer filesync:init
331
421
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gdrive-syncer",
3
- "version": "2.2.0",
3
+ "version": "3.1.0",
4
4
  "description": "Google Drive Syncer",
5
5
  "main": "./index.js",
6
6
  "bin": "./run.js",
package/run.js CHANGED
@@ -5,15 +5,15 @@ const color = require('picocolors');
5
5
  const { cfgAdd, cfgRm, cfgShow } = require('./src/cfgManager');
6
6
  const { runSync } = require('./src/sync');
7
7
  const { runList, runSearch, runDelete, runMkdir, runListSync } = require('./src/list');
8
- const { envInit, envRun, envShow, envRemove, envRegister, envUnregister } = require('./src/envSync');
8
+ const { envInit, envRun, envShow, envRemove, envRegister, envUnregister, envMigrate } = require('./src/envSync');
9
9
 
10
10
  const [, , ...args] = process.argv;
11
11
  const [firstArg] = args;
12
12
 
13
- // Get config type from args (local/global)
13
+ // Get config type from args (local/global/registered)
14
14
  const getConfigType = () => {
15
15
  const arg = args[1]?.toLowerCase();
16
- if (arg === 'local' || arg === 'global') return arg;
16
+ if (arg === 'local' || arg === 'global' || arg === 'registered') return arg;
17
17
  return null;
18
18
  };
19
19
 
@@ -29,6 +29,7 @@ const commands = {
29
29
  'filesync:remove': { handler: envRemove, desc: 'Remove sync config' },
30
30
  'filesync:register': { handler: envRegister, desc: 'Register local config to global' },
31
31
  'filesync:unregister': { handler: envUnregister, desc: 'Unregister local config' },
32
+ 'filesync:migrate': { handler: envMigrate, desc: 'Migrate legacy syncs to Files Sync' },
32
33
 
33
34
  // Drive Operations
34
35
  'drive:search': { handler: runSearch, desc: 'Search files in Drive' },
@@ -49,14 +50,15 @@ const showHelp = () => {
49
50
  const lines = [
50
51
  `${color.bold('Files Sync')} ${color.dim('(two-way sync with .gdrive-sync.json)')}`,
51
52
  ` filesync ${color.dim('Interactive sync menu')}`,
52
- ` filesync:diff [local|global] ${color.dim('Show differences')}`,
53
- ` filesync:download [local|global] ${color.dim('Download from Drive')}`,
54
- ` filesync:upload [local|global] ${color.dim('Upload to Drive')}`,
53
+ ` filesync:diff [local|global|registered] ${color.dim('Show differences')}`,
54
+ ` filesync:download [local|global|registered] ${color.dim('Download from Drive')}`,
55
+ ` filesync:upload [local|global|registered] ${color.dim('Upload to Drive')}`,
55
56
  ` filesync:init ${color.dim('Create/add sync config')}`,
56
57
  ` filesync:show ${color.dim('Show configurations')}`,
57
58
  ` filesync:remove ${color.dim('Remove sync config')}`,
58
59
  ` filesync:register ${color.dim('Register local config to global')}`,
59
60
  ` filesync:unregister ${color.dim('Unregister local config')}`,
61
+ ` filesync:migrate ${color.dim('Migrate legacy syncs to Files Sync')}`,
60
62
  ``,
61
63
  `${color.bold('Drive Operations')}`,
62
64
  ` drive:search ${color.dim('Search files')}`,
@@ -136,6 +138,7 @@ const showHelp = () => {
136
138
  { value: 'filesync:remove', label: 'Remove', hint: 'Remove a sync from config' },
137
139
  { value: 'filesync:register', label: 'Register', hint: 'Register local config to global' },
138
140
  { value: 'filesync:unregister', label: 'Unregister', hint: 'Unregister local config' },
141
+ { value: 'filesync:migrate', label: 'Migrate', hint: 'Migrate legacy syncs to Files Sync' },
139
142
  ],
140
143
  });
141
144
  } else if (category === 'drive') {
@@ -158,6 +161,7 @@ const showHelp = () => {
158
161
  { value: 'sync:show', label: 'Show Config', hint: 'View sync configurations' },
159
162
  { value: 'sync:add', label: 'Add Config', hint: 'Add a new sync configuration' },
160
163
  { value: 'sync:remove', label: 'Remove Config', hint: 'Remove a sync configuration' },
164
+ { value: 'filesync:migrate', label: 'Migrate to Files Sync', hint: 'Migrate to new format' },
161
165
  ],
162
166
  });
163
167
  }