@cloud-cli/vm 1.0.3 → 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/dist/index.d.ts CHANGED
@@ -1,14 +1,19 @@
1
1
  interface NameOption {
2
2
  name: string;
3
3
  }
4
+ interface NameAndPathOption {
5
+ name: string;
6
+ path?: string;
7
+ }
4
8
  declare function list(): Promise<string[]>;
9
+ declare function ls(options: NameAndPathOption): Promise<string[]>;
5
10
  declare function show(options: NameOption): Promise<{
6
11
  name: any;
7
12
  createdAt: any;
8
13
  labels: any;
9
14
  }>;
10
- declare function add(options: NameOption): Promise<string>;
11
- declare function remove(options: NameOption): Promise<string>;
15
+ declare function add(options: NameOption): Promise<boolean>;
16
+ declare function remove(options: NameOption): Promise<boolean>;
12
17
  declare function prune(): Promise<string>;
13
18
  declare const _default: {
14
19
  add: typeof add;
@@ -16,5 +21,6 @@ declare const _default: {
16
21
  list: typeof list;
17
22
  show: typeof show;
18
23
  prune: typeof prune;
24
+ ls: typeof ls;
19
25
  };
20
26
  export default _default;
package/dist/index.js CHANGED
@@ -1,22 +1,34 @@
1
- import { exec } from '@cloud-cli/exec';
1
+ import { join } from "node:path";
2
+ import { exec } from "@cloud-cli/exec";
2
3
  const nameRe = /^[a-z][a-z0-9-]+$/;
3
4
  const isValidName = (name) => nameRe.test(name);
4
- const invalidNameError = new Error('Invalid name');
5
+ const invalidNameError = new Error("Invalid name");
5
6
  async function list() {
6
- const output = await exec('docker', ['volume', 'ls', '--format={{.Name}}']);
7
+ const output = await exec("docker", ["volume", "ls", "--format={{.Name}}"]);
7
8
  if (!output.ok) {
8
- throw new Error('Unable to list volumes');
9
+ throw new Error("Unable to list volumes");
9
10
  }
10
- return output.stdout.trim().split('\n');
11
+ return output.stdout.trim().split("\n");
12
+ }
13
+ async function ls(options) {
14
+ const { name, path = "" } = options;
15
+ const output = await exec("docker", ["volume", "inspect", name]);
16
+ const volumes = JSON.parse(output.stdout);
17
+ if (!volumes.length) {
18
+ throw new Error("Volume not found");
19
+ }
20
+ const root = volumes[0].Mountpoint;
21
+ const files = await exec("ls", ["-1", join(root, path)]);
22
+ return files.stdout.trim().split("\n");
11
23
  }
12
24
  async function show(options) {
13
25
  if (!isValidName(options.name)) {
14
26
  throw invalidNameError;
15
27
  }
16
- const output = await exec('docker', ['volume', 'inspect', options.name]);
28
+ const output = await exec("docker", ["volume", "inspect", options.name]);
17
29
  const list = JSON.parse(output.stdout);
18
30
  if (!list.length) {
19
- throw new Error('Volume not found');
31
+ throw new Error("Volume not found");
20
32
  }
21
33
  const { Name, Labels, CreatedAt } = list[0];
22
34
  return {
@@ -29,24 +41,24 @@ async function add(options) {
29
41
  if (!isValidName(options.name)) {
30
42
  throw invalidNameError;
31
43
  }
32
- const output = await exec('docker', ['volume', 'create', options.name]);
44
+ const output = await exec("docker", ["volume", "create", options.name]);
33
45
  if (output.ok) {
34
- return '';
46
+ return true;
35
47
  }
36
- throw new Error('Unable to create volume');
48
+ throw new Error("Unable to create volume");
37
49
  }
38
50
  async function remove(options) {
39
51
  if (!isValidName(options.name)) {
40
52
  throw invalidNameError;
41
53
  }
42
- const output = await exec('docker', ['volume', 'rm', options.name]);
54
+ const output = await exec("docker", ["volume", "rm", options.name]);
43
55
  if (output.ok) {
44
- return '';
56
+ return true;
45
57
  }
46
- throw new Error('Unable to remove volume');
58
+ throw new Error("Unable to remove volume");
47
59
  }
48
60
  async function prune() {
49
- await exec('docker', ['volume', 'prune']);
50
- return '';
61
+ await exec("docker", ["volume", "prune"]);
62
+ return "";
51
63
  }
52
- export default { add, remove, list, show, prune };
64
+ export default { add, remove, list, show, prune, ls };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud-cli/vm",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Docker volume management",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.spec.ts CHANGED
@@ -44,6 +44,25 @@ describe('volume manager', () => {
44
44
  });
45
45
  });
46
46
 
47
+ describe('ls', () => {
48
+ it('should list files of a volume and path', async () => {
49
+ const outputs = [inspectOutput, 'dir', inspectOutput, 'a.txt\nb.txt'];
50
+ execMocks.exec = jest.fn().mockImplementation(() => ({ ok: true, stdout: outputs.shift() }));
51
+
52
+ await expect(vm.ls({ name: 'test' })).resolves.toEqual(['dir']);
53
+ await expect(vm.ls({ name: 'test', path: 'dir' })).resolves.toEqual(['a.txt', 'b.txt']);
54
+
55
+ expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'inspect', 'test']);
56
+ expect(exec.exec).toHaveBeenCalledWith('ls', ['-1', '/var/lib/docker/volumes/test/_data']);
57
+ expect(exec.exec).toHaveBeenCalledWith('ls', ['-1', '/var/lib/docker/volumes/test/_data/dir']);
58
+ });
59
+
60
+ it('should throw an error if volume name is invalid', async () => {
61
+ execMocks.exec = jest.fn().mockImplementation(() => ({ ok: true, stdout: '[]' }));
62
+ await expect(vm.ls({ name: 'notfound' })).rejects.toThrowError('Volume not found');
63
+ });
64
+ });
65
+
47
66
  describe('show', () => {
48
67
  it('should show details of a volume', async () => {
49
68
  const execOutput = { ok: true, stdout: inspectOutput };
@@ -61,7 +80,7 @@ describe('volume manager', () => {
61
80
  expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'inspect', 'test']);
62
81
  });
63
82
 
64
- it('should throw error if volume name is invalid', async () => {
83
+ it('should throw an error if volume name is invalid', async () => {
65
84
  execMocks.exec = jest.fn();
66
85
  await expect(vm.show({ name: 'In$%valid' })).rejects.toThrowError('Invalid name');
67
86
  expect(exec.exec).not.toHaveBeenCalled();
@@ -80,7 +99,7 @@ describe('volume manager', () => {
80
99
  const execOutput = { ok: true, stdout: 'test' };
81
100
  execMocks.exec = jest.fn().mockResolvedValue(execOutput);
82
101
 
83
- await expect(vm.add({ name: 'test' })).resolves.toEqual('');
102
+ await expect(vm.add({ name: 'test' })).resolves.toEqual(true);
84
103
 
85
104
  expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'create', 'test']);
86
105
  });
@@ -99,12 +118,12 @@ describe('volume manager', () => {
99
118
  });
100
119
  });
101
120
 
102
- describe('delete', () => {
121
+ describe('remove', () => {
103
122
  it('should add a volume', async () => {
104
123
  const execOutput = { ok: true, stdout: '' };
105
124
  execMocks.exec = jest.fn().mockResolvedValue(execOutput);
106
125
 
107
- await expect(vm.remove({ name: 'test' })).resolves.toEqual('');
126
+ await expect(vm.remove({ name: 'test' })).resolves.toEqual(true);
108
127
 
109
128
  expect(exec.exec).toHaveBeenCalledWith('docker', ['volume', 'rm', 'test']);
110
129
  });
package/src/index.ts CHANGED
@@ -1,21 +1,42 @@
1
- import { exec } from '@cloud-cli/exec';
1
+ import { join } from "node:path";
2
+ import { exec } from "@cloud-cli/exec";
2
3
 
3
4
  const nameRe = /^[a-z][a-z0-9-]+$/;
4
5
  const isValidName = (name) => nameRe.test(name);
5
- const invalidNameError = new Error('Invalid name');
6
+ const invalidNameError = new Error("Invalid name");
6
7
 
7
8
  interface NameOption {
8
9
  name: string;
9
10
  }
10
11
 
12
+ interface NameAndPathOption {
13
+ name: string;
14
+ path?: string;
15
+ }
16
+
11
17
  async function list() {
12
- const output = await exec('docker', ['volume', 'ls', '--format={{.Name}}']);
18
+ const output = await exec("docker", ["volume", "ls", "--format={{.Name}}"]);
13
19
 
14
20
  if (!output.ok) {
15
- throw new Error('Unable to list volumes');
21
+ throw new Error("Unable to list volumes");
16
22
  }
17
23
 
18
- return output.stdout.trim().split('\n');
24
+ return output.stdout.trim().split("\n");
25
+ }
26
+
27
+ async function ls(options: NameAndPathOption) {
28
+ const { name, path = "" } = options;
29
+ const output = await exec("docker", ["volume", "inspect", name]);
30
+ const volumes = JSON.parse(output.stdout);
31
+
32
+ if (!volumes.length) {
33
+ throw new Error("Volume not found");
34
+ }
35
+
36
+ const root = volumes[0].Mountpoint;
37
+ const files = await exec("ls", ["-1", join(root, path)]);
38
+
39
+ return files.stdout.trim().split("\n");
19
40
  }
20
41
 
21
42
  async function show(options: NameOption) {
@@ -23,11 +44,11 @@ async function show(options: NameOption) {
23
44
  throw invalidNameError;
24
45
  }
25
46
 
26
- const output = await exec('docker', ['volume', 'inspect', options.name]);
47
+ const output = await exec("docker", ["volume", "inspect", options.name]);
27
48
  const list = JSON.parse(output.stdout);
28
49
 
29
50
  if (!list.length) {
30
- throw new Error('Volume not found');
51
+ throw new Error("Volume not found");
31
52
  }
32
53
 
33
54
  const { Name, Labels, CreatedAt } = list[0];
@@ -44,13 +65,13 @@ async function add(options: NameOption) {
44
65
  throw invalidNameError;
45
66
  }
46
67
 
47
- const output = await exec('docker', ['volume', 'create', options.name]);
68
+ const output = await exec("docker", ["volume", "create", options.name]);
48
69
 
49
70
  if (output.ok) {
50
- return '';
71
+ return true;
51
72
  }
52
73
 
53
- throw new Error('Unable to create volume');
74
+ throw new Error("Unable to create volume");
54
75
  }
55
76
 
56
77
  async function remove(options: NameOption) {
@@ -58,18 +79,18 @@ async function remove(options: NameOption) {
58
79
  throw invalidNameError;
59
80
  }
60
81
 
61
- const output = await exec('docker', ['volume', 'rm', options.name]);
82
+ const output = await exec("docker", ["volume", "rm", options.name]);
62
83
 
63
84
  if (output.ok) {
64
- return '';
85
+ return true;
65
86
  }
66
87
 
67
- throw new Error('Unable to remove volume');
88
+ throw new Error("Unable to remove volume");
68
89
  }
69
90
 
70
91
  async function prune() {
71
- await exec('docker', ['volume', 'prune']);
72
- return '';
92
+ await exec("docker", ["volume", "prune"]);
93
+ return "";
73
94
  }
74
95
 
75
- export default { add, remove, list, show, prune };
96
+ export default { add, remove, list, show, prune, ls };