uzdu 1.0.17 → 1.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
@@ -29,19 +29,19 @@ bunx uzdu -h
29
29
 
30
30
  ### uploading
31
31
 
32
- - [Amazon S3](https://docs.aws.amazon.com/s3/) `npx uzdu upload aws -h`
33
- - [Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs) `npx uzdu upload az -h`
34
- - [Nexus](https://support.sonatype.com/hc/en-us/articles/115006744008-Repository-How-can-I-programmatically-upload-files-into-Nexus-3#DirectUploadusingHTTPPUTtotheRepositoryPath) `npx uzdu upload http -h`
35
- - SSH/SCP `npx uzdu upload ssh -h`
32
+ - [Amazon S3](https://docs.aws.amazon.com/s3/) `npx uzdu upload aws --dotenv /projects/environments/test.env -- build/index.html -- uzdu:ru-central1-d:http://storage.yandexcloud.net`
33
+ - [Azure Blob Storage](https://azure.microsoft.com/en-us/products/storage/blobs) `AZURE_STORAGE_CONNECTION_STRING=...; npx uzdu upload azure build/ $web`
34
+ - [Nexus](https://support.sonatype.com/hc/en-us/articles/115006744008-Repository-How-can-I-programmatically-upload-files-into-Nexus-3#DirectUploadusingHTTPPUTtotheRepositoryPath) `npx upload http --header "Authorization: Basic TOKEN=" -- website.zip https://nexus/repository/private-raw/dist/test-uzdu/website.zip",`
35
+ - SSH/SFTP `npx uzdu upload ssh /projects/website/build/ sftp://root:password@example.localtest.me/var/www/html/`
36
36
 
37
37
  ### downloading
38
38
 
39
- - http `npx uzdu download http -h`
39
+ - http `npx uzdu download http --dotenv --header \"Authorization: Basic TOKEN=\" https://nexus/repository/private-raw/dist/test-uzdu/website.zip website.zip`
40
40
 
41
41
  ### working with zip-archives
42
42
 
43
- - zip `npx uzdu zip -h`
44
- - unzip `npx uzdu unzip -h`
43
+ - zip `npx uzdu zip build/ ./build.zip`
44
+ - unzip `npx uzdu unzip /tmp/repo.zip ./src`
45
45
 
46
46
 
47
47
  ## For developers
@@ -3,8 +3,9 @@ import {
3
3
  getEnvironment,
4
4
  initEnvironment,
5
5
  listFiles,
6
- resolvePath
7
- } from "./chunk-OIXJ4D3Z.js";
6
+ resolvePath,
7
+ runSequentially
8
+ } from "./chunk-WWXWWCCX.js";
8
9
 
9
10
  // src/azure.ts
10
11
  var azure_exports = {};
@@ -95,7 +96,12 @@ async function upload2(dir, s3config, metadataFile = ".metadata.json") {
95
96
  }
96
97
  await Promise.all(Object.entries(files).map(async ([file, absFile]) => {
97
98
  const filePath = absFile;
98
- const fileContent = fs2.readFileSync(filePath);
99
+ const fileContent = await new Promise((resolve, reject) => {
100
+ fs2.readFile(filePath, (err, data) => {
101
+ if (err) reject(err);
102
+ else resolve(data);
103
+ });
104
+ });
99
105
  const params = {
100
106
  Bucket: s3config.bucket,
101
107
  Key: file,
@@ -126,6 +132,7 @@ async function upload2(dir, s3config, metadataFile = ".metadata.json") {
126
132
  // src/ssh.ts
127
133
  var ssh_exports = {};
128
134
  __export(ssh_exports, {
135
+ execute: () => execute,
129
136
  getConnectConfig: () => getConnectConfig,
130
137
  getCredentials: () => getCredentials,
131
138
  getDirMap: () => getDirMap,
@@ -137,26 +144,29 @@ import { Client } from "ssh2";
137
144
  import fs3 from "fs";
138
145
  import path3 from "path";
139
146
  import deepmerge from "deepmerge";
140
- async function upload3(source, sftpUrl, sshCredentials) {
147
+ async function upload3(source, sftpUrl, options) {
141
148
  await new Promise((resolve, reject) => {
142
149
  fs3.stat(source, async (err, stats) => {
150
+ if (err) {
151
+ reject(err);
152
+ return;
153
+ }
143
154
  if (stats.isSymbolicLink()) {
144
155
  reject(new Error(`${source} is symlink`));
145
156
  } else {
146
157
  let sshConnection;
147
158
  try {
148
159
  const _connectConfig = getConnectConfig(sftpUrl);
149
- const _sshCredentials = sshCredentials || getCredentials();
160
+ const _sshCredentials = _connectConfig.password ? void 0 : getCredentials(options);
150
161
  const connectConfig = { ..._connectConfig, ..._sshCredentials };
151
162
  sshConnection = await connect(connectConfig);
152
163
  const files = await listFiles(source);
153
- const destination = getRemoteDestination(sftpUrl);
164
+ const destination = normilizeSftpPath(_connectConfig.path) || "";
154
165
  const _source = source.replace(/\/+$/, "");
155
166
  await mkdirs(sshConnection, destination, files);
156
167
  await uploadFiles(files, _source, destination, sshConnection);
157
168
  resolve();
158
169
  } catch (e) {
159
- console.error("SFTP error", e);
160
170
  reject(e);
161
171
  } finally {
162
172
  sshConnection?.destroy();
@@ -165,22 +175,69 @@ async function upload3(source, sftpUrl, sshCredentials) {
165
175
  });
166
176
  });
167
177
  }
178
+ async function execute(sshAddress, commands, options) {
179
+ await new Promise(async (resolve, reject) => {
180
+ let sshConnection;
181
+ try {
182
+ const _connectConfig = getConnectConfig(sshAddress);
183
+ const _sshCredentials = _connectConfig.password ? void 0 : getCredentials(options);
184
+ const connectConfig = { ..._connectConfig, ..._sshCredentials };
185
+ sshConnection = await connect(connectConfig);
186
+ const shellOptions = {
187
+ ...options,
188
+ cwd: normilizeSftpPath(_connectConfig.path)
189
+ };
190
+ await shellExec(sshConnection, commands, shellOptions);
191
+ resolve();
192
+ } catch (e) {
193
+ reject(e);
194
+ } finally {
195
+ sshConnection?.destroy();
196
+ }
197
+ });
198
+ }
168
199
  async function mkdirs(sshConnection, destination, sources) {
169
200
  const fileMap = getDirMap(sources);
170
201
  const makeDirs = getMakeDirs(fileMap, destination);
171
202
  const commands = makeDirs ? makeDirs.map((dir) => `mkdir -p "${dir}"`) : [`mkdir -p "${destination}"`];
172
- const commandLine = commands.length > 1 ? commands.join(";") : commands[0];
173
- await new Promise((res, rej) => {
174
- sshConnection.exec(commandLine, {}, (err, channel) => {
175
- if (err) {
176
- console.error("mkdir error", err);
177
- rej(new Error(`failed: mkdir -p ... : ${err}`));
178
- } else {
179
- channel.on("exit", (code, signal) => {
180
- if (code != 0) rej(new Error(`Exit code: ${code} for "mkdir -p ..."`));
181
- else res();
182
- });
183
- }
203
+ await shellExec(sshConnection, commands);
204
+ }
205
+ async function shellExec(sshConnection, commands, options) {
206
+ if (!commands) {
207
+ return Promise.reject("shellExec did not get any command");
208
+ }
209
+ if (options?.cwd) {
210
+ const command = `set -e; cd ${options.cwd}; set +e; ${commands.join(";")}`;
211
+ await shellCommand(sshConnection, command, options);
212
+ } else {
213
+ const shellCommands = commands.map((command) => () => shellCommand(sshConnection, command, options));
214
+ await runSequentially(shellCommands);
215
+ }
216
+ }
217
+ async function shellCommand(sshClient, command, options) {
218
+ return new Promise((res, rej) => {
219
+ const decoder = new TextDecoder();
220
+ sshClient.exec(command, (err, stream) => {
221
+ if (err) rej(err);
222
+ stream.on("close", (code, signal) => {
223
+ if (code != 0) {
224
+ options?.callback?.({ error: `closing SSH by signal=${signal} and exit code=${code}`, code, signal });
225
+ rej(new Error(`Close code ${code}`));
226
+ } else {
227
+ res(code);
228
+ }
229
+ }).on("exit", (code, signal) => {
230
+ if (code != 0) {
231
+ options?.callback?.({ error: `Exit command signal=${signal} and exit code=${code}`, code, signal });
232
+ rej(new Error(`Exit code ${code}`));
233
+ } else {
234
+ res(code);
235
+ }
236
+ }).on("data", (message) => {
237
+ options?.callback?.({ message: decoder.decode(message).replace(/\n$/, "") });
238
+ }).stderr.on("data", (error) => {
239
+ options?.callback?.({ error: decoder.decode(error) });
240
+ });
184
241
  });
185
242
  });
186
243
  }
@@ -210,16 +267,14 @@ function uploadFiles(sourceFiles, source, destination, sshConnection) {
210
267
  return new Promise((resolve, reject) => {
211
268
  sshConnection.sftp(async (err, sftp) => {
212
269
  if (err) {
213
- console.error("uploadFiles error");
214
270
  reject(err);
215
271
  } else {
216
272
  if (Object.keys(sourceFiles).length == 1) {
217
273
  const lstat2 = fs3.lstatSync(source);
218
274
  if (lstat2.isFile()) {
219
- const dest = path3.join(destination, sourceFiles[0]).replace(/\\/g, "/");
275
+ const dest = path3.join(destination, Object.keys(sourceFiles)[0]).replace(/\\/g, "/");
220
276
  const src = source;
221
277
  await _uploadFile(src, dest, sftp).then(() => resolve()).catch((e) => {
222
- console.error(src);
223
278
  reject(e);
224
279
  });
225
280
  return;
@@ -235,8 +290,6 @@ function uploadFiles(sourceFiles, source, destination, sshConnection) {
235
290
  const dest = path3.join(destination, baseName).replace(/\\/g, "/");
236
291
  const promise = new Promise((res, rej) => {
237
292
  _uploadFile(absPath, dest, sftp).then(() => res()).catch((e) => {
238
- console.error(absPath);
239
- console.error(e);
240
293
  rej(e);
241
294
  });
242
295
  });
@@ -253,7 +306,7 @@ async function connect(sshConfig) {
253
306
  try {
254
307
  return await new Promise((resolve, reject) => {
255
308
  conn.on("error", (e) => {
256
- reject(new Error(`Target host error: ${e}`));
309
+ reject(e);
257
310
  }).on("ready", () => {
258
311
  resolve(conn);
259
312
  }).connect({
@@ -273,7 +326,6 @@ async function connect(sshConfig) {
273
326
  });
274
327
  });
275
328
  } catch (e) {
276
- console.error("Connection failed", e);
277
329
  conn.destroy();
278
330
  throw e;
279
331
  }
@@ -333,7 +385,7 @@ function getCredentials(options) {
333
385
  }
334
386
  } else {
335
387
  const uzduPassword = process.env.UZDU_SSH_PASSWORD;
336
- if (!uzduPassword) throw new Error("Specify either --privateKeyPath or password in SFTP URL. Otherwise consider using --dotenv and one of environment variables: UZDU_SSH_KEY_PATH, UZDU_SSH_KEY, UZDU_SSH_PASSWORD");
388
+ if (!uzduPassword) throw new Error("Specify password in SFTP URL. Otherwise consider using one of environment variables: UZDU_SSH_KEY_PATH, UZDU_SSH_KEY, UZDU_SSH_PASSWORD");
337
389
  password = uzduPassword;
338
390
  }
339
391
  }
@@ -345,17 +397,34 @@ function getCredentials(options) {
345
397
  return authConfig;
346
398
  }
347
399
  var sftpUrlRegex = /^sftp:\/\/(?:(?<username>[\w\.\-]{1,32})(?::(?<password>.+))?@)?(?:(?<host>[\w\.\-]+)|\[(?<ipv6>[\d:]+)\])(?::(?<port>\d{1,5}))?\/(?<path>.*)$/g;
348
- function getConnectConfig(sftpUrl) {
400
+ var sshUrlRegex = /^(?:(?<username>[\w\.\-]{1,32})(?::(?<password>.+))?@)?(?:(?<host>[\w\.\-]+)|\[(?<ipv6>[\d:]+)\])(?::(?<port>\d{1,5}))?$/g;
401
+ var suspectSftpRegex = /^sftp:\/\/.+/g;
402
+ function getConnectConfig(url) {
403
+ let execArray;
404
+ sshUrlRegex.lastIndex = 0;
349
405
  sftpUrlRegex.lastIndex = 0;
350
- const execArray = sftpUrlRegex.exec(sftpUrl);
406
+ if (sftpUrlRegex.test(url)) {
407
+ sftpUrlRegex.lastIndex = 0;
408
+ execArray = sftpUrlRegex.exec(url);
409
+ } else if (sshUrlRegex.test(url)) {
410
+ sshUrlRegex.lastIndex = 0;
411
+ suspectSftpRegex.lastIndex = 0;
412
+ if (suspectSftpRegex.test(url)) {
413
+ throw new Error(`SSH URL starts with "sftp://". If it is sftp URL, then add trailing slash after hostname[:port] - ${url}/, if it is SSH URL, consider password that does not start with 2 slashes.`);
414
+ }
415
+ execArray = sshUrlRegex.exec(url);
416
+ } else {
417
+ throw new Error(`Not an SFTP or SSH address: ${url}`);
418
+ }
351
419
  const { groups } = execArray ?? {};
352
420
  const host = groups?.host || groups?.ipv6;
353
- if (!host) throw new Error(`Wrong URL "${sftpUrl}": host or ivp6 is not specified`);
421
+ if (!host) throw new Error(`Wrong URL "${url}": host or ivp6 is not specified`);
354
422
  const username = groups?.username;
355
423
  const password = groups?.password;
424
+ const path4 = groups?.path;
356
425
  const _port = parseInt(groups.port);
357
426
  const port = isNaN(_port) ? void 0 : _port;
358
- const connectConfig = { username, password, host, port };
427
+ const connectConfig = { username, password, host, port, path: path4 };
359
428
  return connectConfig;
360
429
  }
361
430
  function getRemoteDestination(sftpUrl) {
@@ -364,21 +433,27 @@ function getRemoteDestination(sftpUrl) {
364
433
  if (!execArray) throw new Error("Wrong sftp URL");
365
434
  if (!execArray.groups) throw new Error("Wrong URL: path is not specified");
366
435
  const path4 = execArray.groups.path;
367
- const re = /^(?<first>[^\/]+)(?:\/)?(?<second>.*)?/g;
436
+ return normilizeSftpPath(execArray.groups?.path) || "";
437
+ }
438
+ function normilizeSftpPath(path4) {
439
+ if (path4 == void 0) return void 0;
440
+ const re = /^(?<first>[^\/]*)(?<root>\/)?(?<second>.*)?/g;
368
441
  re.lastIndex = 0;
369
442
  const execPathArray = re.exec(path4);
370
443
  const { groups } = execPathArray ?? {};
371
444
  const first = groups?.first;
372
445
  const second = groups?.second;
446
+ const root = groups?.root;
373
447
  let dest;
374
448
  if (first) {
375
449
  const execTild = /^(?<tild>~)/.exec(first);
376
450
  const { groups: groups2 } = execTild ?? {};
377
- dest = groups2?.tild ? `./${second}` : `/${first}${second ? `/${second}` : ""}`;
451
+ dest = groups2?.tild ? `${second ? second : ""}` : `/${first}${second ? `/${second}` : ""}`;
378
452
  } else {
379
- dest = path4;
453
+ if (!root && !second) dest = "/";
454
+ else dest = path4;
380
455
  }
381
- const destination = dest.replace(/\/+$/, "");
456
+ const destination = dest != "/" ? dest.replace(/\/+$/, "") : dest;
382
457
  return destination;
383
458
  }
384
459
 
@@ -388,6 +463,5 @@ export {
388
463
  upload2,
389
464
  s3_exports,
390
465
  upload3,
391
- getCredentials,
392
466
  ssh_exports
393
467
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __export,
3
3
  listFiles
4
- } from "./chunk-OIXJ4D3Z.js";
4
+ } from "./chunk-WWXWWCCX.js";
5
5
 
6
6
  // src/http.ts
7
7
  var http_exports = {};
@@ -7,6 +7,7 @@ var __export = (target, all) => {
7
7
  // src/utils.ts
8
8
  var utils_exports = {};
9
9
  __export(utils_exports, {
10
+ SequentilRunError: () => SequentilRunError,
10
11
  addMetadata: () => addMetadata,
11
12
  checkIsFile: () => checkIsFile,
12
13
  doUnzip: () => doUnzip,
@@ -17,6 +18,7 @@ __export(utils_exports, {
17
18
  makeZip: () => makeZip,
18
19
  outputConfiguration: () => outputConfiguration,
19
20
  resolvePath: () => resolvePath,
21
+ runSequentially: () => runSequentially,
20
22
  safeIndex: () => safeIndex,
21
23
  shouldBeDirectory: () => shouldBeDirectory,
22
24
  shouldBeFile: () => shouldBeFile
@@ -230,6 +232,35 @@ function parseEnvironment(src) {
230
232
  }
231
233
  return obj;
232
234
  }
235
+ async function runSequentially(tasks, breaksOnError = true) {
236
+ const results = [];
237
+ for (let i = 0; i < tasks.length; i++) {
238
+ try {
239
+ const result = await tasks[i]();
240
+ results.push(result);
241
+ } catch (err) {
242
+ if (breaksOnError) throw new SequentilRunError(i, `${err.message || err}`);
243
+ else {
244
+ console.error(`Error in #${i}: ${err.message || err}`);
245
+ results.push(null);
246
+ }
247
+ }
248
+ }
249
+ ;
250
+ return results;
251
+ }
252
+ var SequentilRunError = class extends Error {
253
+ /**
254
+ *
255
+ * @param message Text of the error
256
+ * @param index where in the sequense the error happened
257
+ */
258
+ constructor(index, message = "Sequential Error") {
259
+ super(message);
260
+ this.index = index;
261
+ this.message = message;
262
+ }
263
+ };
233
264
 
234
265
  export {
235
266
  __export,
@@ -243,5 +274,6 @@ export {
243
274
  shouldBeDirectory,
244
275
  outputConfiguration,
245
276
  resolvePath,
277
+ runSequentially,
246
278
  utils_exports
247
279
  };
package/lib/uzdu-copy.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  checkIsFile,
4
4
  outputConfiguration
5
- } from "./chunk-OIXJ4D3Z.js";
5
+ } from "./chunk-WWXWWCCX.js";
6
6
 
7
7
  // src/uzdu-copy.ts
8
8
  import { Command } from "commander";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  download
3
- } from "./chunk-7B56UNA6.js";
3
+ } from "./chunk-LFEIDM4S.js";
4
4
  import {
5
5
  getEnvironment,
6
6
  initEnvironment,
7
7
  outputConfiguration
8
- } from "./chunk-OIXJ4D3Z.js";
8
+ } from "./chunk-WWXWWCCX.js";
9
9
 
10
10
  // src/uzdu-download.ts
11
11
  import { Command, Option } from "commander";
@@ -2,7 +2,7 @@ import {
2
2
  addMetadata,
3
3
  outputConfiguration,
4
4
  shouldBeDirectory
5
- } from "./chunk-OIXJ4D3Z.js";
5
+ } from "./chunk-WWXWWCCX.js";
6
6
 
7
7
  // src/uzdu-metadata.ts
8
8
  import { Argument, Command } from "commander";
package/lib/uzdu-unzip.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  doUnzip,
4
4
  outputConfiguration
5
- } from "./chunk-OIXJ4D3Z.js";
5
+ } from "./chunk-WWXWWCCX.js";
6
6
 
7
7
  // src/uzdu-unzip.ts
8
8
  import { Command } from "commander";
@@ -1,19 +1,18 @@
1
1
  import {
2
- getCredentials,
3
2
  upload as upload2,
4
3
  upload2 as upload3,
5
4
  upload3 as upload4
6
- } from "./chunk-VO6FBXH2.js";
5
+ } from "./chunk-463DKYHI.js";
7
6
  import {
8
7
  upload
9
- } from "./chunk-7B56UNA6.js";
8
+ } from "./chunk-LFEIDM4S.js";
10
9
  import {
11
10
  getEnvironment,
12
11
  initEnvironment,
13
12
  outputConfiguration,
14
13
  resolvePath,
15
14
  shouldBeDirectory
16
- } from "./chunk-OIXJ4D3Z.js";
15
+ } from "./chunk-WWXWWCCX.js";
17
16
 
18
17
  // src/uzdu-upload.ts
19
18
  import { Argument, Command, Option } from "commander";
@@ -38,8 +37,8 @@ command.command("aws").description("upload to AWS S3").argument("<from>", "the d
38
37
  const optConfig = { bucket: bucketName, endpoint };
39
38
  if (region) optConfig.region = region;
40
39
  const config = Object.assign(env, optConfig);
41
- if (!config.accessKeyId) throw new Error("AWS Access Key ID is not specified. Provide an environement variable S3_ACCESS_KEY_ID.");
42
- if (!config.secretAccessKey) throw new Error("AWS Secret Key is not specified. Provide an environment variable S3_SECRET_ACCESS_KEY.");
40
+ if (!config.accessKeyId) throw new Error("AWS Access Key ID is not specified. Provide an environement variable AWS_ACCESS_KEY_ID.");
41
+ if (!config.secretAccessKey) throw new Error("AWS Secret Key is not specified. Provide an environment variable AWS_SECRET_ACCESS_KEY.");
43
42
  if (!config.region) throw new Error("AWS region is not specified. Provide it in a bucket address or as an envronment variable S3_REGION.");
44
43
  await upload3(from, config);
45
44
  } catch (e) {
@@ -72,7 +71,7 @@ command.command("azure").alias("az").description("upload to Azure Blob Storage")
72
71
  }
73
72
  const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
74
73
  if (!connectionString) {
75
- throw new Error("AZURE_STORAGE_CONNECTION_STRING is absent in environment variables. Consider option --dotenv to laod it.");
74
+ throw new Error("AZURE_STORAGE_CONNECTION_STRING is absent in environment variables. Consider the command option --dotenv to load it from a file.");
76
75
  }
77
76
  shouldBeDirectory(from);
78
77
  const azOpt = {
@@ -88,10 +87,8 @@ command.command("ssh").description("upload via SFTP. In addition to sftpURL cons
88
87
  new Option("-d|--dotenv [file]", 'load environment variables from a property file, i.e. a file with "key=value" lines.').preset(".env")
89
88
  ).addOption(new Option("--privateKeyPath [path to file]", "Path to SSH private key, fallback is UZDU_SSH_KEY_PATH environment variable. Also consider using UZDU_SSH_KEY to provide SSH private key content or UZDU_SSH_PASSWORD.")).action(async (source, sftpUrl, options, thisCommand) => {
90
89
  try {
91
- const sshCredentials = getCredentials(options);
92
- await upload4(resolvePath(source), sftpUrl, sshCredentials);
90
+ await upload4(resolvePath(source), sftpUrl, options);
93
91
  } catch (e) {
94
- console.error(e);
95
92
  thisCommand.error(e.message || e, { exitCode: 127, code: "ssh.upload.error" });
96
93
  }
97
94
  });
package/lib/uzdu-zip.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  makeZip,
4
4
  outputConfiguration
5
- } from "./chunk-OIXJ4D3Z.js";
5
+ } from "./chunk-WWXWWCCX.js";
6
6
 
7
7
  // src/uzdu-zip.ts
8
8
  import { Command } from "commander";
package/lib/uzdu.d.ts CHANGED
@@ -73,8 +73,28 @@ declare function safeIndex<T>(arr: T[], index: number): T | undefined;
73
73
  * @return '/home/bob/GitHub/Repo/file.png'
74
74
  */
75
75
  declare function resolvePath(filePath: string): string;
76
+ /**
77
+ * Sequential runner
78
+ * @param tasks array of functions to be executed sequentially
79
+ * @param breaksOnError breaks all if any function fails.
80
+ * @returns array of results
81
+ * @throws SequentialRunError
82
+ */
83
+ declare function runSequentially(tasks: Function[], breaksOnError?: boolean): Promise<any[]>;
84
+ declare class SequentilRunError extends Error {
85
+ readonly index: number;
86
+ readonly message: string;
87
+ /**
88
+ *
89
+ * @param message Text of the error
90
+ * @param index where in the sequense the error happened
91
+ */
92
+ constructor(index: number, message?: string);
93
+ }
76
94
 
77
95
  type utils_BlobObject = BlobObject;
96
+ type utils_SequentilRunError = SequentilRunError;
97
+ declare const utils_SequentilRunError: typeof SequentilRunError;
78
98
  declare const utils_addMetadata: typeof addMetadata;
79
99
  declare const utils_checkIsFile: typeof checkIsFile;
80
100
  declare const utils_doUnzip: typeof doUnzip;
@@ -85,11 +105,12 @@ declare const utils_listFiles: typeof listFiles;
85
105
  declare const utils_makeZip: typeof makeZip;
86
106
  declare const utils_outputConfiguration: typeof outputConfiguration;
87
107
  declare const utils_resolvePath: typeof resolvePath;
108
+ declare const utils_runSequentially: typeof runSequentially;
88
109
  declare const utils_safeIndex: typeof safeIndex;
89
110
  declare const utils_shouldBeDirectory: typeof shouldBeDirectory;
90
111
  declare const utils_shouldBeFile: typeof shouldBeFile;
91
112
  declare namespace utils {
92
- export { type utils_BlobObject as BlobObject, utils_addMetadata as addMetadata, utils_checkIsFile as checkIsFile, utils_doUnzip as doUnzip, utils_getEnvironment as getEnvironment, utils_initEnvironment as initEnvironment, utils_listBlobs as listBlobs, utils_listFiles as listFiles, utils_makeZip as makeZip, utils_outputConfiguration as outputConfiguration, utils_resolvePath as resolvePath, utils_safeIndex as safeIndex, utils_shouldBeDirectory as shouldBeDirectory, utils_shouldBeFile as shouldBeFile };
113
+ export { type utils_BlobObject as BlobObject, utils_SequentilRunError as SequentilRunError, utils_addMetadata as addMetadata, utils_checkIsFile as checkIsFile, utils_doUnzip as doUnzip, utils_getEnvironment as getEnvironment, utils_initEnvironment as initEnvironment, utils_listBlobs as listBlobs, utils_listFiles as listFiles, utils_makeZip as makeZip, utils_outputConfiguration as outputConfiguration, utils_resolvePath as resolvePath, utils_runSequentially as runSequentially, utils_safeIndex as safeIndex, utils_shouldBeDirectory as shouldBeDirectory, utils_shouldBeFile as shouldBeFile };
93
114
  }
94
115
 
95
116
  declare function upload$3(dirOrFile: string, url: URL, headers?: string[]): Promise<void>;
@@ -132,7 +153,25 @@ type SshCredentials = {
132
153
  password?: undefined;
133
154
  privateKey: Buffer | string;
134
155
  };
135
- declare function upload(source: string, sftpUrl: string, sshCredentials?: SshCredentials): Promise<void>;
156
+ type ShellCallbackParams = {
157
+ message?: string;
158
+ error?: string;
159
+ signal?: number;
160
+ code?: number;
161
+ };
162
+ type ShellCommandCallback = (value: ShellCallbackParams) => void;
163
+ type SftpConnectConfig = ConnectConfig & {
164
+ path?: string;
165
+ };
166
+ declare function upload(source: string, sftpUrl: string, options?: {
167
+ privateKeyPath?: string;
168
+ dotenv?: string;
169
+ }): Promise<void>;
170
+ declare function execute(sshAddress: string, commands: string[], options?: {
171
+ privateKeyPath?: string;
172
+ dotenv?: string;
173
+ callback?: ShellCommandCallback;
174
+ }): Promise<void>;
136
175
  type FileMapEntry = {
137
176
  [key: string]: false | FileMapEntry;
138
177
  };
@@ -163,12 +202,13 @@ declare function getCredentials(options?: {
163
202
  * sftp://ubuntu:pa55w0rd@example.com/opt/file
164
203
  * sftp://root@[2001:db8::5]:222/opt/file
165
204
  * sftp://203.0.113.5/opt/file
205
+ * root:pa55w0rd@example.com
166
206
  * ```
167
- * @param sftpUrl
207
+ * @param url
168
208
  *
169
209
  * @throws Wrong URL: host or ivp6 is not specified
170
210
  */
171
- declare function getConnectConfig(sftpUrl: string): ConnectConfig;
211
+ declare function getConnectConfig(url: string): SftpConnectConfig;
172
212
  /**
173
213
  *
174
214
  * @param sftpUrl
@@ -178,7 +218,11 @@ declare function getConnectConfig(sftpUrl: string): ConnectConfig;
178
218
  */
179
219
  declare function getRemoteDestination(sftpUrl: string): string;
180
220
 
221
+ type ssh_SftpConnectConfig = SftpConnectConfig;
222
+ type ssh_ShellCallbackParams = ShellCallbackParams;
223
+ type ssh_ShellCommandCallback = ShellCommandCallback;
181
224
  type ssh_SshCredentials = SshCredentials;
225
+ declare const ssh_execute: typeof execute;
182
226
  declare const ssh_getConnectConfig: typeof getConnectConfig;
183
227
  declare const ssh_getCredentials: typeof getCredentials;
184
228
  declare const ssh_getDirMap: typeof getDirMap;
@@ -186,7 +230,7 @@ declare const ssh_getMakeDirs: typeof getMakeDirs;
186
230
  declare const ssh_getRemoteDestination: typeof getRemoteDestination;
187
231
  declare const ssh_upload: typeof upload;
188
232
  declare namespace ssh {
189
- export { type ssh_SshCredentials as SshCredentials, ssh_getConnectConfig as getConnectConfig, ssh_getCredentials as getCredentials, ssh_getDirMap as getDirMap, ssh_getMakeDirs as getMakeDirs, ssh_getRemoteDestination as getRemoteDestination, ssh_upload as upload };
233
+ export { type ssh_SftpConnectConfig as SftpConnectConfig, type ssh_ShellCallbackParams as ShellCallbackParams, type ssh_ShellCommandCallback as ShellCommandCallback, type ssh_SshCredentials as SshCredentials, ssh_execute as execute, ssh_getConnectConfig as getConnectConfig, ssh_getCredentials as getCredentials, ssh_getDirMap as getDirMap, ssh_getMakeDirs as getMakeDirs, ssh_getRemoteDestination as getRemoteDestination, ssh_upload as upload };
190
234
  }
191
235
 
192
236
  export { azure, http, s3, ssh, utils };
package/lib/uzdu.js CHANGED
@@ -3,21 +3,21 @@ import {
3
3
  azure_exports,
4
4
  s3_exports,
5
5
  ssh_exports
6
- } from "./chunk-VO6FBXH2.js";
6
+ } from "./chunk-463DKYHI.js";
7
7
  import {
8
8
  http_exports
9
- } from "./chunk-7B56UNA6.js";
9
+ } from "./chunk-LFEIDM4S.js";
10
10
  import {
11
11
  outputConfiguration,
12
12
  utils_exports
13
- } from "./chunk-OIXJ4D3Z.js";
13
+ } from "./chunk-WWXWWCCX.js";
14
14
 
15
15
  // src/uzdu.ts
16
16
  import { Command } from "commander";
17
17
  var version;
18
18
  var description;
19
19
  try {
20
- version = "1.0.17";
20
+ version = "1.1.0";
21
21
  description = "UZDU - universal zipper, downloader and uploader. Move files to/from zip, clouds (AWS, Azure), to HTTP PUT (e.g. Nexus) and to SSH";
22
22
  } catch (e) {
23
23
  if (e instanceof ReferenceError) {
@@ -33,6 +33,7 @@ program.command("zip", "create zip-archive from a directory or a file");
33
33
  program.command("unzip", "unzip archive to a directory");
34
34
  program.command("copy", "copy files and directories");
35
35
  program.command("metadata", "create Amazon S3 metadata file. See https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html.").alias("meta");
36
+ program.command("exec", "execute shell command");
36
37
  program.configureOutput(outputConfiguration);
37
38
  async function main() {
38
39
  await program.parseAsync();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uzdu",
3
- "version": "1.0.17",
3
+ "version": "1.1.0",
4
4
  "description": "UZDU - universal zipper, downloader and uploader. Move files to/from zip, clouds (AWS, Azure), to HTTP PUT (e.g. Nexus) and to SSH",
5
5
  "bin": {
6
6
  "uzdu": "lib/uzdu.js"