secrez 1.1.1 → 1.1.2
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 +414 -291
- package/bin/secrez.js +50 -47
- package/coverage.report +63 -305
- package/package.json +10 -12
- package/src/Command.js +78 -57
- package/src/PreCommand.js +74 -70
- package/src/Welcome.js +144 -134
- package/src/cliConfig.js +14 -14
- package/src/commands/Alias.js +123 -100
- package/src/commands/Bash.js +10 -12
- package/src/commands/Cat.js +117 -107
- package/src/commands/Cd.js +39 -42
- package/src/commands/Chat.js +75 -63
- package/src/commands/Conf.js +123 -99
- package/src/commands/Contacts.js +189 -171
- package/src/commands/Copy.js +132 -113
- package/src/commands/Courier.js +123 -105
- package/src/commands/Ds.js +88 -76
- package/src/commands/Edit.js +122 -103
- package/src/commands/Export.js +153 -114
- package/src/commands/Find.js +115 -110
- package/src/commands/Help.js +20 -23
- package/src/commands/Import.js +296 -225
- package/src/commands/Lcat.js +36 -39
- package/src/commands/Lcd.js +38 -39
- package/src/commands/Lls.js +58 -55
- package/src/commands/Lpwd.js +20 -24
- package/src/commands/Ls.js +107 -97
- package/src/commands/Mkdir.js +35 -38
- package/src/commands/Mv.js +147 -114
- package/src/commands/Paste.js +68 -65
- package/src/commands/Pwd.js +18 -23
- package/src/commands/Quit.js +22 -24
- package/src/commands/Rm.js +78 -70
- package/src/commands/Shell.js +31 -32
- package/src/commands/Ssh.js +77 -63
- package/src/commands/Tag.js +133 -112
- package/src/commands/Totp.js +166 -136
- package/src/commands/Touch.js +169 -56
- package/src/commands/Use.js +44 -41
- package/src/commands/Ver.js +16 -18
- package/src/commands/Whoami.js +34 -37
- package/src/commands/chat/Contacts.js +41 -44
- package/src/commands/chat/Help.js +20 -23
- package/src/commands/chat/Join.js +59 -55
- package/src/commands/chat/Leave.js +16 -22
- package/src/commands/chat/Quit.js +19 -24
- package/src/commands/chat/Send.js +58 -57
- package/src/commands/chat/Show.js +60 -51
- package/src/commands/chat/Whoami.js +18 -22
- package/src/commands/index.js +20 -22
- package/src/index.js +3 -3
- package/src/prompts/ChatPrompt.js +87 -82
- package/src/prompts/ChatPromptMock.js +11 -17
- package/src/prompts/CommandPrompt.js +146 -138
- package/src/prompts/Completion.js +64 -69
- package/src/prompts/MainPrompt.js +84 -77
- package/src/prompts/MainPromptMock.js +19 -30
- package/src/prompts/MultiEditorPrompt.js +21 -22
- package/src/prompts/SigintManager.js +21 -24
- package/src/utils/AliasManager.js +16 -18
- package/src/utils/ContactManager.js +15 -17
- package/src/utils/Fido2Client.js +59 -49
- package/src/utils/HelpProto.js +130 -117
- package/src/utils/Logger.js +48 -50
- package/.eslintignore +0 -0
- package/.eslintrc +0 -33
- package/.jshintrc +0 -3
package/src/commands/Import.js
CHANGED
@@ -1,429 +1,500 @@
|
|
1
|
-
const fs = require(
|
2
|
-
const path = require(
|
3
|
-
const utils = require(
|
4
|
-
const Case = require(
|
5
|
-
const _ = require(
|
6
|
-
const chalk = require(
|
7
|
-
const {config, Entry} = require(
|
8
|
-
const {Node, FileCipher} = require(
|
9
|
-
const {fromCsvToJson, yamlStringify, isYaml} = require(
|
10
|
-
|
11
|
-
class Import extends require('../Command') {
|
1
|
+
const fs = require("fs-extra");
|
2
|
+
const path = require("path");
|
3
|
+
const utils = require("@secrez/utils");
|
4
|
+
const Case = require("case");
|
5
|
+
const _ = require("lodash");
|
6
|
+
const chalk = require("chalk");
|
7
|
+
const { config, Entry } = require("@secrez/core");
|
8
|
+
const { Node, FileCipher } = require("@secrez/fs");
|
9
|
+
const { fromCsvToJson, yamlStringify, isYaml } = require("@secrez/utils");
|
12
10
|
|
11
|
+
class Import extends require("../Command") {
|
13
12
|
setHelpAndCompletion() {
|
14
13
|
this.cliConfig.completion.import = {
|
15
14
|
_func: this.selfCompletion(this, {
|
16
|
-
external: true
|
15
|
+
external: true,
|
17
16
|
}),
|
18
|
-
_self: this
|
19
|
-
}
|
20
|
-
this.cliConfig.completion.help.import = true
|
17
|
+
_self: this,
|
18
|
+
};
|
19
|
+
this.cliConfig.completion.help.import = true;
|
21
20
|
this.optionDefinitions = [
|
22
21
|
{
|
23
|
-
name:
|
24
|
-
alias:
|
25
|
-
type: Boolean
|
22
|
+
name: "help",
|
23
|
+
alias: "h",
|
24
|
+
type: Boolean,
|
26
25
|
},
|
27
26
|
{
|
28
|
-
name:
|
29
|
-
completionType:
|
30
|
-
alias:
|
27
|
+
name: "path",
|
28
|
+
completionType: "file",
|
29
|
+
alias: "p",
|
31
30
|
defaultOption: true,
|
32
|
-
type: String
|
31
|
+
type: String,
|
33
32
|
},
|
34
33
|
{
|
35
|
-
name:
|
36
|
-
alias:
|
37
|
-
type: Boolean
|
34
|
+
name: "move",
|
35
|
+
alias: "m",
|
36
|
+
type: Boolean,
|
38
37
|
},
|
39
38
|
{
|
40
|
-
name:
|
41
|
-
alias:
|
42
|
-
type: Boolean
|
39
|
+
name: "binary-too",
|
40
|
+
alias: "b",
|
41
|
+
type: Boolean,
|
43
42
|
},
|
44
43
|
{
|
45
|
-
name:
|
46
|
-
alias:
|
47
|
-
type: Boolean
|
44
|
+
name: "simulate",
|
45
|
+
alias: "s",
|
46
|
+
type: Boolean,
|
48
47
|
},
|
49
48
|
{
|
50
|
-
name:
|
51
|
-
alias:
|
49
|
+
name: "expand",
|
50
|
+
alias: "e",
|
52
51
|
type: String,
|
53
|
-
hint:
|
52
|
+
hint: "It must be on the current dataset",
|
54
53
|
},
|
55
54
|
{
|
56
|
-
name:
|
57
|
-
alias:
|
58
|
-
type: Boolean
|
55
|
+
name: "recursive",
|
56
|
+
alias: "r",
|
57
|
+
type: Boolean,
|
59
58
|
},
|
60
59
|
{
|
61
|
-
name:
|
62
|
-
alias:
|
63
|
-
type: Boolean
|
60
|
+
name: "tags",
|
61
|
+
alias: "t",
|
62
|
+
type: Boolean,
|
64
63
|
},
|
65
64
|
{
|
66
|
-
name:
|
67
|
-
alias:
|
68
|
-
type: Boolean
|
65
|
+
name: "use-tags-for-paths",
|
66
|
+
alias: "u",
|
67
|
+
type: Boolean,
|
69
68
|
},
|
70
69
|
{
|
71
|
-
name:
|
72
|
-
alias:
|
70
|
+
name: "path-from",
|
71
|
+
alias: "P",
|
73
72
|
type: String,
|
74
|
-
multiple: true
|
73
|
+
multiple: true,
|
75
74
|
},
|
76
75
|
{
|
77
|
-
name:
|
78
|
-
type: String
|
76
|
+
name: "password",
|
77
|
+
type: String,
|
79
78
|
},
|
80
79
|
{
|
81
|
-
name:
|
82
|
-
type: String
|
83
|
-
}
|
84
|
-
]
|
80
|
+
name: "public-key",
|
81
|
+
type: String,
|
82
|
+
},
|
83
|
+
];
|
85
84
|
}
|
86
85
|
|
87
86
|
help() {
|
88
87
|
return {
|
89
88
|
description: [
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
"Import files from the OS into the current folder",
|
90
|
+
"By default binary files are not imported since they can be very large.",
|
91
|
+
"To include them, use the -b option.",
|
92
|
+
"During a move, only the imported files are moved. To avoid problems",
|
93
|
+
"you can simulate the process using -s and see which ones will be imported.",
|
95
94
|
'Import can import data from password managers and other software. If in CSV format, the first line must list the field names and one field must be "path". Similarly, if in JSON format, a "path" key is mandatory in any item. Path should be relative. If not, it will be converted.',
|
96
|
-
|
97
|
-
|
95
|
+
"Also notice that to import from a CSV file you must specify where to expand the data, if not",
|
96
|
+
"the file will be imported as a single file.",
|
98
97
|
],
|
99
98
|
examples: [
|
100
|
-
[
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
[
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
[
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
[
|
113
|
-
|
114
|
-
|
99
|
+
[
|
100
|
+
"import seed.json",
|
101
|
+
"copies seed.json from the disk into the current directory",
|
102
|
+
],
|
103
|
+
[
|
104
|
+
"import seed.json.secrez --password s8eeuhwy36534",
|
105
|
+
"imports seed.json and decrypts it using the specified password",
|
106
|
+
],
|
107
|
+
[
|
108
|
+
"import seed.json.secrez",
|
109
|
+
"imports seed.json trying to decrypt it using the key shared with the contact who encrypted the data",
|
110
|
+
],
|
111
|
+
[
|
112
|
+
"import seed.json.secrez--public-key Tush76/u+..... ",
|
113
|
+
"imports seed.json trying to decrypt it using a shared key generated using the specified public key",
|
114
|
+
],
|
115
|
+
["import -m ethKeys", "copies ethKeys and remove it from the disk"],
|
116
|
+
[
|
117
|
+
"import -p ~/passwords",
|
118
|
+
"imports all the text files in the folder passwords",
|
119
|
+
],
|
120
|
+
[
|
121
|
+
"import -b -p ~/passwords",
|
122
|
+
"imports all the files, included binaries",
|
123
|
+
],
|
124
|
+
[
|
125
|
+
"import -r ~/data -t",
|
126
|
+
"imports text files in the folder, recursively",
|
127
|
+
],
|
128
|
+
[
|
129
|
+
"import ~/data -s",
|
130
|
+
"simulates the process listing all involved files",
|
131
|
+
],
|
132
|
+
[
|
133
|
+
"import backup.csv -e /imported",
|
134
|
+
'imports a backup creating files in the "/imported"',
|
135
|
+
],
|
136
|
+
["import backup.json -e .", "imports a backup in the current folder"],
|
137
|
+
[
|
138
|
+
"import backup.csv -e / -m",
|
139
|
+
"imports a backup in the root, deleting the CSV file from the disk",
|
140
|
+
],
|
141
|
+
[
|
142
|
+
"import backup.csv -te /",
|
143
|
+
"imports a backup saving the tags field as actual tags",
|
144
|
+
],
|
145
|
+
[
|
146
|
+
"import backup.csv -ute /fromPasspack",
|
147
|
+
"uses the tags to prefix the path and keeps the tags;",
|
115
148
|
'ex: if "google" is tagged "web,email" the path becomes',
|
116
149
|
'"./web/email/google" or "./email/web/google"',
|
117
|
-
|
150
|
+
"based on the tag weight",
|
151
|
+
],
|
152
|
+
[
|
153
|
+
"import backup.csv -ue /fromPasspack",
|
154
|
+
"uses the tags to prefix the path without saving the tags",
|
118
155
|
],
|
119
|
-
[
|
120
|
-
|
121
|
-
|
156
|
+
[
|
157
|
+
"import lastpass.csv -e /imports -P grouping name",
|
158
|
+
'concatenates the fields "grouping" and "name" to obtain the path',
|
159
|
+
],
|
160
|
+
[
|
161
|
+
'import backup.csv -e /imports -P "entry name"',
|
122
162
|
'uses the field "entry name" for the path,',
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
163
|
+
"i.e., puts everything in the directory /imports,",
|
164
|
+
"without creating any subdirectory",
|
165
|
+
],
|
166
|
+
],
|
167
|
+
};
|
127
168
|
}
|
128
169
|
|
129
170
|
async import(options = {}) {
|
130
|
-
this.internalFs.tree.disableSave()
|
131
|
-
this.skipped = []
|
132
|
-
let result = await this._import(options)
|
133
|
-
this.internalFs.tree.enableSave()
|
171
|
+
this.internalFs.tree.disableSave();
|
172
|
+
this.skipped = [];
|
173
|
+
let result = await this._import(options);
|
174
|
+
this.internalFs.tree.enableSave();
|
134
175
|
if (result.length && !options.simulate) {
|
135
|
-
await this.internalFs.tree.save()
|
176
|
+
await this.internalFs.tree.save();
|
136
177
|
}
|
137
|
-
return [result.sort(), this.skipped]
|
178
|
+
return [result.sort(), this.skipped];
|
138
179
|
}
|
139
180
|
|
140
|
-
async _import(options = {}, container =
|
141
|
-
let ifs = this.internalFs
|
142
|
-
let efs = this.externalFs
|
143
|
-
let fileCipher = new FileCipher(this.secrez)
|
144
|
-
let p = efs.getNormalizedPath(options.path)
|
181
|
+
async _import(options = {}, container = "") {
|
182
|
+
let ifs = this.internalFs;
|
183
|
+
let efs = this.externalFs;
|
184
|
+
let fileCipher = new FileCipher(this.secrez);
|
185
|
+
let p = efs.getNormalizedPath(options.path);
|
145
186
|
if (await fs.pathExists(p)) {
|
146
|
-
let isDir = await efs.isDir(p)
|
147
|
-
let list = isDir
|
148
|
-
|
149
|
-
|
150
|
-
let
|
187
|
+
let isDir = await efs.isDir(p);
|
188
|
+
let list = isDir
|
189
|
+
? (await efs.getDir(p))[1].map((f) => path.join(p, f))
|
190
|
+
: [p];
|
191
|
+
let content = [];
|
192
|
+
let result = [];
|
193
|
+
let moved = [];
|
151
194
|
for (let fn of list) {
|
152
195
|
if (await efs.isDir(fn)) {
|
153
196
|
if (options.recursive) {
|
154
197
|
result = await this._import(
|
155
|
-
|
156
|
-
|
157
|
-
)
|
198
|
+
Object.assign(options, { path: fn }),
|
199
|
+
(container ? `${container}/` : "") + path.basename(fn)
|
200
|
+
);
|
158
201
|
} else {
|
159
|
-
continue
|
202
|
+
continue;
|
160
203
|
}
|
161
204
|
}
|
162
205
|
if (/\/$/.test(fn)) {
|
163
|
-
continue
|
206
|
+
continue;
|
164
207
|
}
|
165
|
-
let isEncryptedBinary = /\.secrezb(|\.\w+)$/.test(fn)
|
166
|
-
let isBinary = await utils.isBinary(fn)
|
208
|
+
let isEncryptedBinary = /\.secrezb(|\.\w+)$/.test(fn);
|
209
|
+
let isBinary = await utils.isBinary(fn);
|
167
210
|
if ((isEncryptedBinary || isBinary) && !options.binaryToo) {
|
168
|
-
this.skipped.push([
|
169
|
-
|
211
|
+
this.skipped.push([
|
212
|
+
path.basename(fn),
|
213
|
+
'binary file; use "-b" to include binaries',
|
214
|
+
]);
|
215
|
+
continue;
|
170
216
|
}
|
171
|
-
content.push([
|
217
|
+
content.push([
|
218
|
+
fn,
|
219
|
+
isBinary || isEncryptedBinary,
|
220
|
+
await fs.readFile(fn, isBinary ? undefined : "utf8"),
|
221
|
+
]);
|
172
222
|
}
|
173
|
-
let contactsPublicKeys
|
223
|
+
let contactsPublicKeys;
|
174
224
|
for (let c of content) {
|
175
|
-
let basename = Entry.sanitizeName(path.basename(c[0]),
|
176
|
-
let isEncrypted = /\.secrez(|b)(|\.\w+)$/.test(basename)
|
177
|
-
let isEncryptedBinary
|
225
|
+
let basename = Entry.sanitizeName(path.basename(c[0]), "-");
|
226
|
+
let isEncrypted = /\.secrez(|b)(|\.\w+)$/.test(basename);
|
227
|
+
let isEncryptedBinary;
|
178
228
|
if (isEncrypted) {
|
179
|
-
isEncryptedBinary = /\.secrezb(|\.\w+)$/.test(basename)
|
180
|
-
basename = basename.replace(/\.secrez(|b)(|\.\w+)$/,
|
229
|
+
isEncryptedBinary = /\.secrezb(|\.\w+)$/.test(basename);
|
230
|
+
basename = basename.replace(/\.secrez(|b)(|\.\w+)$/, "");
|
181
231
|
}
|
182
232
|
if (isEncrypted && !contactsPublicKeys && !options.publicKey) {
|
183
|
-
contactsPublicKeys = await this.getContactsPublicKeys()
|
233
|
+
contactsPublicKeys = await this.getContactsPublicKeys();
|
184
234
|
}
|
185
|
-
let name = await this.internalFs.tree.getVersionedBasename(basename)
|
235
|
+
let name = await this.internalFs.tree.getVersionedBasename(basename);
|
186
236
|
if (container) {
|
187
|
-
name = container +
|
237
|
+
name = container + "/" + name;
|
188
238
|
}
|
189
|
-
result.push(this.internalFs.tree.getNormalizedPath(name))
|
239
|
+
result.push(this.internalFs.tree.getNormalizedPath(name));
|
190
240
|
if (!options.simulate) {
|
191
241
|
if (options.move) {
|
192
|
-
moved.push(c[0])
|
242
|
+
moved.push(c[0]);
|
193
243
|
}
|
194
244
|
if (isEncrypted) {
|
195
245
|
try {
|
196
|
-
options.returnUint8Array = isEncryptedBinary
|
246
|
+
options.returnUint8Array = isEncryptedBinary;
|
197
247
|
if (!options.contactPublicKey) {
|
198
|
-
options.contactsPublicKeys = contactsPublicKeys
|
248
|
+
options.contactsPublicKeys = contactsPublicKeys;
|
199
249
|
}
|
200
|
-
c[2] = fileCipher.decryptFile(c[2], options)
|
250
|
+
c[2] = fileCipher.decryptFile(c[2], options);
|
201
251
|
} catch (e) {
|
202
|
-
this.skipped.push([path.basename(c[0]), e.message])
|
203
|
-
continue
|
252
|
+
this.skipped.push([path.basename(c[0]), e.message]);
|
253
|
+
continue;
|
204
254
|
}
|
205
255
|
}
|
206
256
|
let node = await ifs.make({
|
207
257
|
path: name,
|
208
258
|
type: c[1] ? config.types.BINARY : config.types.TEXT,
|
209
|
-
content: c[2]
|
210
|
-
})
|
211
|
-
result.pop()
|
212
|
-
result.push(node.getPath())
|
259
|
+
content: c[2],
|
260
|
+
});
|
261
|
+
result.pop();
|
262
|
+
result.push(node.getPath());
|
213
263
|
}
|
214
264
|
}
|
215
265
|
if (!options.simulate) {
|
216
266
|
if (options.move) {
|
217
267
|
for (let fn of moved) {
|
218
|
-
await fs.unlink(fn)
|
268
|
+
await fs.unlink(fn);
|
219
269
|
}
|
220
270
|
}
|
221
271
|
}
|
222
|
-
return result
|
272
|
+
return result;
|
223
273
|
} else {
|
224
|
-
return []
|
274
|
+
return [];
|
225
275
|
}
|
226
276
|
}
|
227
277
|
|
228
278
|
async getContactsPublicKeys() {
|
229
|
-
let contacts = await this.prompt.commands.contacts.contacts({
|
230
|
-
|
279
|
+
let contacts = await this.prompt.commands.contacts.contacts({
|
280
|
+
list: true,
|
281
|
+
asIs: true,
|
282
|
+
});
|
283
|
+
let publicKeys = [];
|
231
284
|
for (let contact of contacts) {
|
232
|
-
publicKeys.push(contact[1].publicKey)
|
285
|
+
publicKeys.push(contact[1].publicKey);
|
233
286
|
}
|
234
|
-
return publicKeys
|
287
|
+
return publicKeys;
|
235
288
|
}
|
236
289
|
|
237
290
|
async expand(options) {
|
238
|
-
let ifs = this.internalFs
|
239
|
-
let efs = this.externalFs
|
240
|
-
let fn = efs.getNormalizedPath(options.path)
|
291
|
+
let ifs = this.internalFs;
|
292
|
+
let efs = this.externalFs;
|
293
|
+
let fn = efs.getNormalizedPath(options.path);
|
241
294
|
if (!(await fs.pathExists(fn))) {
|
242
|
-
return this.Logger.red(
|
295
|
+
return this.Logger.red("The file does not exist");
|
243
296
|
}
|
244
|
-
let str = await fs.readFile(fn,
|
245
|
-
let ext = path.extname(fn)
|
246
|
-
let data
|
247
|
-
if (ext ===
|
248
|
-
data = JSON.parse(str)
|
249
|
-
} else if (ext ===
|
297
|
+
let str = await fs.readFile(fn, "utf-8");
|
298
|
+
let ext = path.extname(fn);
|
299
|
+
let data;
|
300
|
+
if (ext === ".json") {
|
301
|
+
data = JSON.parse(str);
|
302
|
+
} else if (ext === ".csv") {
|
250
303
|
try {
|
251
|
-
data = fromCsvToJson(str)
|
304
|
+
data = fromCsvToJson(str);
|
252
305
|
} catch (e) {
|
253
|
-
return this.Logger.red(e.message)
|
306
|
+
return this.Logger.red(e.message);
|
254
307
|
}
|
255
308
|
}
|
256
309
|
if (data.length === 0) {
|
257
|
-
return this.Logger.red(
|
310
|
+
return this.Logger.red("The data is empty");
|
258
311
|
}
|
259
312
|
if (!data[0].path) {
|
260
313
|
if (options.pathFrom) {
|
261
|
-
let pathFrom = options.pathFrom.map(e => Case.snake(_.trim(e)))
|
314
|
+
let pathFrom = options.pathFrom.map((e) => Case.snake(_.trim(e)));
|
262
315
|
for (let item of data) {
|
263
|
-
let p =
|
316
|
+
let p = "";
|
264
317
|
for (let f of pathFrom) {
|
265
|
-
p +=
|
266
|
-
|
318
|
+
p +=
|
319
|
+
(p ? "/" : "") + (typeof item[f] !== "undefined" ? item[f] : "");
|
320
|
+
delete item[f];
|
267
321
|
}
|
268
322
|
if (!p) {
|
269
|
-
throw new Error(
|
323
|
+
throw new Error("Path cannot be built from the specified fields");
|
270
324
|
}
|
271
|
-
item.path = p.replace(/\/+/g,
|
325
|
+
item.path = p.replace(/\/+/g, "/").replace(/:+/g, "_");
|
272
326
|
}
|
273
327
|
} else {
|
274
|
-
return this.Logger.red(
|
328
|
+
return this.Logger.red("The data misses a path field");
|
275
329
|
}
|
276
330
|
}
|
277
331
|
if (options.useTagsForPaths) {
|
278
|
-
let weightedTags = {}
|
332
|
+
let weightedTags = {};
|
279
333
|
for (let item of data) {
|
280
334
|
if (item.tags) {
|
281
|
-
let tags = item.tags.split(
|
335
|
+
let tags = item.tags.split(" ");
|
282
336
|
for (let t of tags) {
|
283
337
|
if (!weightedTags[t]) {
|
284
|
-
weightedTags[t] = 0
|
338
|
+
weightedTags[t] = 0;
|
285
339
|
}
|
286
|
-
weightedTags[t]
|
340
|
+
weightedTags[t]++;
|
287
341
|
}
|
288
342
|
}
|
289
343
|
}
|
290
344
|
for (let item of data) {
|
291
345
|
if (item.tags) {
|
292
|
-
let tags = item.tags.split(
|
293
|
-
item.path =
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
346
|
+
let tags = item.tags.split(" ");
|
347
|
+
item.path =
|
348
|
+
tags
|
349
|
+
.sort((a, b) => {
|
350
|
+
let A = weightedTags[a];
|
351
|
+
let B = weightedTags[b];
|
352
|
+
return A > B ? -1 : A < B ? 1 : 0;
|
353
|
+
})
|
354
|
+
.join("/") +
|
355
|
+
"/" +
|
356
|
+
item.path;
|
298
357
|
if (!options.tags) {
|
299
|
-
delete item.tags
|
358
|
+
delete item.tags;
|
300
359
|
}
|
301
360
|
}
|
302
361
|
}
|
303
362
|
}
|
304
|
-
let extra =
|
363
|
+
let extra = "";
|
305
364
|
if (options.simulate) {
|
306
|
-
extra =
|
365
|
+
extra = " (simulation)";
|
307
366
|
} else if (options.move) {
|
308
|
-
extra =
|
367
|
+
extra = " (moved)";
|
309
368
|
}
|
310
|
-
this.Logger.grey(`Imported files${extra}:`)
|
369
|
+
this.Logger.grey(`Imported files${extra}:`);
|
311
370
|
|
312
|
-
let parentFolderPath = this.internalFs.tree.getNormalizedPath(
|
313
|
-
|
371
|
+
let parentFolderPath = this.internalFs.tree.getNormalizedPath(
|
372
|
+
options.expand
|
373
|
+
);
|
374
|
+
let parentFolder;
|
314
375
|
try {
|
315
|
-
parentFolder =
|
376
|
+
parentFolder =
|
377
|
+
this.internalFs.tree.root.getChildFromPath(parentFolderPath);
|
316
378
|
} catch (e) {
|
317
|
-
await this.prompt.commands.mkdir.mkdir({
|
318
|
-
|
379
|
+
await this.prompt.commands.mkdir.mkdir({
|
380
|
+
path: parentFolderPath,
|
381
|
+
type: config.types.DIR,
|
382
|
+
});
|
383
|
+
parentFolder =
|
384
|
+
this.internalFs.tree.root.getChildFromPath(parentFolderPath);
|
319
385
|
}
|
320
386
|
if (!Node.isDir(parentFolder)) {
|
321
|
-
return this.Logger.red(
|
387
|
+
return this.Logger.red("The destination folder is not a folder.");
|
322
388
|
}
|
323
|
-
this.internalFs.tree.disableSave()
|
389
|
+
this.internalFs.tree.disableSave();
|
324
390
|
for (let item of data) {
|
325
|
-
let p = item.path
|
391
|
+
let p = item.path;
|
326
392
|
if (!p) {
|
327
|
-
continue
|
393
|
+
continue;
|
328
394
|
}
|
329
|
-
p = path.resolve(parentFolderPath, p.replace(/^\//,
|
330
|
-
let dirname = path.dirname(p)
|
331
|
-
let dir
|
395
|
+
p = path.resolve(parentFolderPath, p.replace(/^\//, ""));
|
396
|
+
let dirname = path.dirname(p);
|
397
|
+
let dir;
|
332
398
|
try {
|
333
|
-
dir = this.internalFs.tree.root.getChildFromPath(dirname)
|
399
|
+
dir = this.internalFs.tree.root.getChildFromPath(dirname);
|
334
400
|
} catch (e) {
|
335
|
-
await this.prompt.commands.mkdir.mkdir({
|
336
|
-
|
401
|
+
await this.prompt.commands.mkdir.mkdir({
|
402
|
+
path: dirname,
|
403
|
+
type: config.types.DIR,
|
404
|
+
});
|
405
|
+
dir = this.internalFs.tree.root.getChildFromPath(dirname);
|
337
406
|
}
|
338
|
-
let name = path.basename(p)
|
407
|
+
let name = path.basename(p);
|
339
408
|
if (!isYaml(name)) {
|
340
|
-
name +=
|
409
|
+
name += ".yaml";
|
341
410
|
}
|
342
|
-
name = await this.internalFs.tree.getVersionedBasename(
|
343
|
-
|
411
|
+
name = await this.internalFs.tree.getVersionedBasename(
|
412
|
+
path.join(dirname, name),
|
413
|
+
dir
|
414
|
+
);
|
415
|
+
this.Logger.reset(path.join(dirname, name));
|
344
416
|
if (!options.simulate) {
|
345
|
-
delete item.path
|
346
|
-
let tags
|
417
|
+
delete item.path;
|
418
|
+
let tags;
|
347
419
|
if (options.tags) {
|
348
|
-
tags = item.tags
|
349
|
-
delete item.tags
|
420
|
+
tags = item.tags;
|
421
|
+
delete item.tags;
|
350
422
|
}
|
351
423
|
let node = await ifs.make({
|
352
424
|
path: path.join(dirname, name),
|
353
425
|
type: config.types.TEXT,
|
354
|
-
content: yamlStringify(item)
|
355
|
-
})
|
426
|
+
content: yamlStringify(item),
|
427
|
+
});
|
356
428
|
if (tags) {
|
357
|
-
tags = tags.split(
|
358
|
-
await this.prompt.commands.tag.tag({add: tags}, [node])
|
429
|
+
tags = tags.split(" ").filter((e) => e);
|
430
|
+
await this.prompt.commands.tag.tag({ add: tags }, [node]);
|
359
431
|
}
|
360
432
|
}
|
361
433
|
}
|
362
434
|
if (!options.simulate) {
|
363
|
-
this.internalFs.tree.enableSave()
|
364
|
-
await this.internalFs.tree.save()
|
435
|
+
this.internalFs.tree.enableSave();
|
436
|
+
await this.internalFs.tree.save();
|
365
437
|
if (options.tags) {
|
366
|
-
await this.internalFs.tree.saveTags()
|
438
|
+
await this.internalFs.tree.saveTags();
|
367
439
|
}
|
368
440
|
if (options.move) {
|
369
|
-
await fs.unlink(fn)
|
441
|
+
await fs.unlink(fn);
|
370
442
|
}
|
371
443
|
}
|
372
444
|
}
|
373
445
|
|
374
446
|
async exec(options = {}) {
|
375
447
|
if (options.help) {
|
376
|
-
return this.showHelp()
|
448
|
+
return this.showHelp();
|
377
449
|
}
|
378
450
|
try {
|
379
|
-
this.validate(options)
|
451
|
+
this.validate(options);
|
380
452
|
if (options.expand) {
|
381
|
-
await this.expand(options)
|
453
|
+
await this.expand(options);
|
382
454
|
} else {
|
383
455
|
if (/\.csv$/i.test(options.path)) {
|
384
456
|
let yes = await this.useConfirm({
|
385
|
-
message:
|
386
|
-
|
387
|
-
|
457
|
+
message:
|
458
|
+
"You are importing a CSV file as a single file.\nMaybe, you wanted to import from a backup and forgot to specify the expand (-e) option.\nAre you sure you want to proceed?",
|
459
|
+
default: false,
|
460
|
+
});
|
388
461
|
if (!yes) {
|
389
|
-
await this.prompt.run()
|
390
|
-
return
|
462
|
+
await this.prompt.run();
|
463
|
+
return;
|
391
464
|
}
|
392
465
|
}
|
393
|
-
let [files, skipped] = await this.import(options)
|
466
|
+
let [files, skipped] = await this.import(options);
|
394
467
|
if (files.length) {
|
395
|
-
let extra =
|
468
|
+
let extra = "";
|
396
469
|
if (options.simulate) {
|
397
|
-
extra =
|
470
|
+
extra = " (simulation)";
|
398
471
|
} else if (options.move) {
|
399
|
-
extra =
|
472
|
+
extra = " (moved)";
|
400
473
|
}
|
401
|
-
this.Logger.grey(`Imported files${extra}:`)
|
474
|
+
this.Logger.grey(`Imported files${extra}:`);
|
402
475
|
for (let f of files) {
|
403
|
-
this.Logger.reset(f)
|
476
|
+
this.Logger.reset(f);
|
404
477
|
}
|
405
478
|
if (skipped.length) {
|
406
|
-
this.Logger.grey(
|
479
|
+
this.Logger.grey("Skipped files:");
|
407
480
|
for (let f of skipped) {
|
408
|
-
this.Logger.reset(f[0] + chalk.yellow(
|
481
|
+
this.Logger.reset(f[0] + chalk.yellow(" (" + f[1] + ")"));
|
409
482
|
}
|
410
483
|
}
|
411
484
|
} else if (skipped.length) {
|
412
|
-
this.Logger.grey(
|
485
|
+
this.Logger.grey("Skipped files:");
|
413
486
|
for (let f of skipped) {
|
414
|
-
this.Logger.reset(f[0] + chalk.yellow(
|
487
|
+
this.Logger.reset(f[0] + chalk.yellow(" (" + f[1] + ")"));
|
415
488
|
}
|
416
489
|
} else {
|
417
|
-
this.Logger.red(
|
490
|
+
this.Logger.red("No file has been imported.");
|
418
491
|
}
|
419
492
|
}
|
420
493
|
} catch (e) {
|
421
|
-
this.Logger.red(e.message)
|
494
|
+
this.Logger.red(e.message);
|
422
495
|
}
|
423
|
-
await this.prompt.run()
|
496
|
+
await this.prompt.run();
|
424
497
|
}
|
425
498
|
}
|
426
499
|
|
427
|
-
module.exports = Import
|
428
|
-
|
429
|
-
|
500
|
+
module.exports = Import;
|