-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathCommandMkdir.ts
More file actions
121 lines (118 loc) · 4.32 KB
/
Copy pathCommandMkdir.ts
File metadata and controls
121 lines (118 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import type PolykeyClient from 'polykey/dist/PolykeyClient';
import type { ErrorMessage } from 'polykey/dist/client/types';
import CommandPolykey from '../CommandPolykey';
import * as binUtils from '../utils';
import * as binOptions from '../utils/options';
import * as binParsers from '../utils/parsers';
import * as binProcessors from '../utils/processors';
import {
ErrorPolykeyCLIMakeDirectory,
ErrorPolykeyCLIUncaughtException,
} from '../errors';
class CommandMkdir extends CommandPolykey {
constructor(...args: ConstructorParameters<typeof CommandPolykey>) {
super(...args);
this.name('mkdir');
this.description(
'Create a Directory within a Vault. Empty directories are not a part of the vault and will not be shared when cloning a Vault.',
);
this.argument(
'<secretPath...>',
'Path to where the directory to be created, specified as <vaultName>:<directoryPath>',
);
this.addOption(binOptions.nodeId);
this.addOption(binOptions.clientHost);
this.addOption(binOptions.clientPort);
this.addOption(binOptions.parents);
this.action(async (secretPaths, options) => {
secretPaths = secretPaths.map((path: string) =>
binParsers.parseSecretPath(path),
);
const { default: PolykeyClient } = await import(
'polykey/dist/PolykeyClient'
);
const clientOptions = await binProcessors.processClientOptions(
options.nodePath,
options.nodeId,
options.clientHost,
options.clientPort,
this.fs,
this.logger.getChild(binProcessors.processClientOptions.name),
);
const meta = await binProcessors.processAuthentication(
options.passwordFile,
this.fs,
);
let pkClient: PolykeyClient;
this.exitHandlers.handlers.push(async () => {
if (pkClient != null) await pkClient.stop();
});
try {
pkClient = await PolykeyClient.createPolykeyClient({
nodeId: clientOptions.nodeId,
host: clientOptions.clientHost,
port: clientOptions.clientPort,
options: {
nodePath: options.nodePath,
},
logger: this.logger.getChild(PolykeyClient.name),
});
const hasErrored = await binUtils.retryAuthentication(async (auth) => {
// Write directory paths to input stream
const response =
await pkClient.rpcClient.methods.vaultsSecretsMkdir();
const writer = response.writable.getWriter();
let first = true;
for (const [vault, path] of secretPaths) {
await writer.write({
nameOrId: vault,
dirName: path ?? '/',
metadata: first
? { ...auth, options: { recursive: options.parents } }
: undefined,
});
first = false;
}
await writer.close();
// Print out incoming data to standard out, or incoming errors to
// standard error.
let hasErrored = false;
for await (const result of response.readable) {
if (result.type === 'error') {
// TS cannot properly evaluate a type this deeply nested, so we use
// the as keyword to help it. Inside this block, the type of data
// is ensured to be 'error'.
const error = result as ErrorMessage;
hasErrored = true;
let message: string = '';
switch (error.code) {
case 'ENOENT':
message = 'No such secret or directory';
break;
case 'EEXIST':
message = 'Secret or directory exists';
break;
default:
throw new ErrorPolykeyCLIUncaughtException(
`Unexpected error code: ${error.code}`,
);
}
process.stderr.write(
`${error.code}: cannot create directory ${error.reason}: ${message}\n`,
);
}
}
return hasErrored;
}, meta);
if (hasErrored) {
throw new ErrorPolykeyCLIMakeDirectory(
'Failed to create one or more directories',
);
}
} finally {
if (pkClient! != null) await pkClient.stop();
}
});
}
}
export default CommandMkdir;