dorky 2.3.9 → 2.3.10
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 -2
- package/bin/index.js +50 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -381,8 +381,8 @@ ISC License - see [LICENSE](LICENSE) file for details.
|
|
|
381
381
|
## Roadmap
|
|
382
382
|
|
|
383
383
|
- [x] Update README with AWS IAM policy (bug fix release)
|
|
384
|
-
- [
|
|
385
|
-
- [
|
|
384
|
+
- [x] Handle invalid access token for Google Drive and AWS (edge cases)
|
|
385
|
+
- [x] rm + push should delete file from remote storage (minor release)
|
|
386
386
|
- [ ] Uninitialize dorky setup (Bug fix release)
|
|
387
387
|
- [ ] dorky --list remote --update should sync metadata according to remote (Minor release)
|
|
388
388
|
- [ ] Extension for VS Code to list and highlight them like git (Major release)
|
|
@@ -390,4 +390,8 @@ ISC License - see [LICENSE](LICENSE) file for details.
|
|
|
390
390
|
- [ ] Encryption of files (Minor release)
|
|
391
391
|
- [ ] Add stages for variables (Major release)
|
|
392
392
|
- [ ] Migrate dorky project to another storage (partially implemented)
|
|
393
|
+
- [ ] Add more test cases
|
|
394
|
+
- [ ] Deletion of files
|
|
395
|
+
- [ ] Edge cases for failure when credentials are invalid
|
|
396
|
+
- [ ] Add coverage reports badges
|
|
393
397
|
|
package/bin/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const path = require("path");
|
|
|
8
8
|
const mimeTypes = require("mime-types");
|
|
9
9
|
const md5 = require('md5');
|
|
10
10
|
const EOL = require("os").type() == "Darwin" ? "\r\n" : "\n";
|
|
11
|
-
const { GetObjectCommand, PutObjectCommand, ListObjectsV2Command, S3Client } = require("@aws-sdk/client-s3");
|
|
11
|
+
const { GetObjectCommand, PutObjectCommand, ListObjectsV2Command, DeleteObjectCommand, S3Client } = require("@aws-sdk/client-s3");
|
|
12
12
|
const { authenticate } = require('@google-cloud/local-auth');
|
|
13
13
|
const { google } = require('googleapis');
|
|
14
14
|
|
|
@@ -232,14 +232,15 @@ async function runS3(creds, fn) {
|
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
async function getFolderId(pathStr, drive) {
|
|
235
|
+
async function getFolderId(pathStr, drive, create = true) {
|
|
236
236
|
let parentId = 'root';
|
|
237
237
|
if (!pathStr || pathStr === '.') return parentId;
|
|
238
238
|
for (const folder of pathStr.split("/")) {
|
|
239
239
|
if (!folder) continue;
|
|
240
|
-
const res = await drive.files.list({ q: `name='${folder}' and mimeType='application/vnd.google-apps.folder' and '${parentId}' in parents`, fields: 'files(id)' });
|
|
240
|
+
const res = await drive.files.list({ q: `name='${folder}' and mimeType='application/vnd.google-apps.folder' and '${parentId}' in parents and trashed=false`, fields: 'files(id)' });
|
|
241
241
|
if (res.data.files[0]) parentId = res.data.files[0].id;
|
|
242
|
-
else parentId = (await drive.files.create({ requestBody: { name: folder, mimeType: 'application/vnd.google-apps.folder', parents: [parentId] }, fields: 'id' })).data.id;
|
|
242
|
+
else if (create) parentId = (await drive.files.create({ requestBody: { name: folder, mimeType: 'application/vnd.google-apps.folder', parents: [parentId] }, fields: 'id' })).data.id;
|
|
243
|
+
else return null;
|
|
243
244
|
}
|
|
244
245
|
return parentId;
|
|
245
246
|
}
|
|
@@ -263,36 +264,66 @@ async function push() {
|
|
|
263
264
|
checkDorkyProject();
|
|
264
265
|
if (!await checkCredentials()) return;
|
|
265
266
|
const meta = readJson(METADATA_PATH);
|
|
266
|
-
const
|
|
267
|
+
const filesToUpload = Object.keys(meta["stage-1-files"])
|
|
267
268
|
.filter(f => !meta["uploaded-files"][f] || meta["stage-1-files"][f].hash !== meta["uploaded-files"][f].hash)
|
|
268
269
|
.map(f => ({ name: f, ...meta["stage-1-files"][f] }));
|
|
269
270
|
|
|
270
|
-
|
|
271
|
+
const filesToDelete = Object.keys(meta["uploaded-files"])
|
|
272
|
+
.filter(f => !meta["stage-1-files"][f]);
|
|
273
|
+
|
|
274
|
+
if (filesToUpload.length === 0 && filesToDelete.length === 0) return console.log(chalk.yellow("ℹ Nothing to push."));
|
|
271
275
|
|
|
272
276
|
const creds = readJson(CREDENTIALS_PATH);
|
|
273
277
|
if (creds.storage === "aws") {
|
|
274
278
|
await runS3(creds, async (s3, bucket) => {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
279
|
+
if (filesToUpload.length > 0) {
|
|
280
|
+
await Promise.all(filesToUpload.map(async f => {
|
|
281
|
+
const key = path.join(path.basename(process.cwd()), f.name);
|
|
282
|
+
await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key, Body: readFileSync(f.name) }));
|
|
283
|
+
console.log(chalk.green(`✔ Uploaded: ${f.name}`));
|
|
284
|
+
}));
|
|
285
|
+
}
|
|
286
|
+
if (filesToDelete.length > 0) {
|
|
287
|
+
await Promise.all(filesToDelete.map(async f => {
|
|
288
|
+
const key = path.join(path.basename(process.cwd()), f);
|
|
289
|
+
await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
|
|
290
|
+
console.log(chalk.yellow(`✔ Deleted remote: ${f}`));
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
280
293
|
});
|
|
281
294
|
} else if (creds.storage === "google-drive") {
|
|
282
295
|
await runDrive(async (drive) => {
|
|
283
|
-
|
|
296
|
+
if (filesToUpload.length > 0) {
|
|
297
|
+
for (const f of filesToUpload) {
|
|
298
|
+
const root = path.basename(process.cwd());
|
|
299
|
+
const parentId = await getFolderId(path.dirname(path.join(root, f.name)), drive);
|
|
300
|
+
await drive.files.create({
|
|
301
|
+
requestBody: { name: path.basename(f.name), parents: [parentId] },
|
|
302
|
+
media: { mimeType: f["mime-type"], body: createReadStream(f.name) }
|
|
303
|
+
});
|
|
304
|
+
console.log(chalk.green(`✔ Uploaded: ${f.name}`));
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (filesToDelete.length > 0) {
|
|
284
308
|
const root = path.basename(process.cwd());
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
309
|
+
for (const f of filesToDelete) {
|
|
310
|
+
const parentId = await getFolderId(path.dirname(path.join(root, f)), drive, false);
|
|
311
|
+
if (parentId) {
|
|
312
|
+
const res = await drive.files.list({
|
|
313
|
+
q: `name='${path.basename(f)}' and '${parentId}' in parents and trashed=false`,
|
|
314
|
+
fields: 'files(id)'
|
|
315
|
+
});
|
|
316
|
+
if (res.data.files[0]) {
|
|
317
|
+
await drive.files.delete({ fileId: res.data.files[0].id });
|
|
318
|
+
console.log(chalk.yellow(`✔ Deleted remote: ${f}`));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
291
322
|
}
|
|
292
323
|
});
|
|
293
324
|
}
|
|
294
325
|
|
|
295
|
-
meta["uploaded-files"] = { ...meta["
|
|
326
|
+
meta["uploaded-files"] = { ...meta["stage-1-files"] };
|
|
296
327
|
writeJson(METADATA_PATH, meta);
|
|
297
328
|
}
|
|
298
329
|
|