deploy.sh 2.0.0 → 3.0.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/.claude/settings.local.json +36 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +105 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +56 -0
- package/.github/workflows/ci.yml +15 -34
- package/.github/workflows/pages.yml +48 -0
- package/.oxfmtrc.json +7 -0
- package/.oxlintrc.json +11 -0
- package/LICENSE +183 -183
- package/README.md +99 -10
- package/app/actions/deployments.ts +82 -0
- package/app/actions/metrics.ts +13 -0
- package/app/root.tsx +60 -0
- package/app/routes/dashboard/detail/history.tsx +73 -0
- package/app/routes/dashboard/detail/layout.tsx +125 -0
- package/app/routes/dashboard/detail/logs.tsx +85 -0
- package/app/routes/dashboard/detail/overview.tsx +119 -0
- package/app/routes/dashboard/detail/requests.tsx +163 -0
- package/app/routes/dashboard/detail/resources.tsx +268 -0
- package/app/routes/dashboard/detail/shared.tsx +59 -0
- package/app/routes/dashboard/index.tsx +360 -0
- package/app/routes/dashboard/layout.tsx +30 -0
- package/app/routes/docs/architecture.tsx +155 -0
- package/app/routes/docs/cli.tsx +122 -0
- package/app/routes/docs/deploying.tsx +105 -0
- package/app/routes/docs/index.tsx +104 -0
- package/app/routes/docs/layout.tsx +58 -0
- package/app/routes/home.tsx +134 -0
- package/app/routes/root.client.tsx +46 -0
- package/app/routes.ts +21 -0
- package/app/styles.css +15 -0
- package/app/theme.css +134 -0
- package/bin/deploy.js +362 -138
- package/docs-site/404.html +33 -0
- package/docs-site/home.tsx +130 -0
- package/docs-site/index.html +35 -0
- package/docs-site/layout.tsx +57 -0
- package/docs-site/main.tsx +41 -0
- package/docs-site/shell.tsx +34 -0
- package/docs-site/styles.css +4 -0
- package/drizzle.config.js +8 -0
- package/examples/docker/Dockerfile +5 -5
- package/examples/docker/server.js +18 -0
- package/examples/node/package.json +3 -11
- package/examples/node/pnpm-lock.yaml +9 -0
- package/examples/node/server.js +12 -0
- package/examples/static/index.html +41 -15
- package/package.json +40 -64
- package/public/favicon.ico +0 -0
- package/react-router-vite/entry.browser.tsx +49 -0
- package/react-router-vite/entry.rsc.single.tsx +7 -0
- package/react-router-vite/entry.rsc.tsx +36 -0
- package/react-router-vite/entry.ssr.tsx +29 -0
- package/react-router-vite/plugin.ts +114 -0
- package/react-router-vite/types.d.ts +11 -0
- package/react-router.config.ts +5 -0
- package/server/api.test.ts +344 -0
- package/server/api.ts +445 -0
- package/server/docker.ts +268 -0
- package/server/index.ts +17 -0
- package/server/metrics-collector.ts +29 -0
- package/server/schema.ts +56 -0
- package/server/store.test.ts +278 -0
- package/server/store.ts +398 -0
- package/tsconfig.json +21 -0
- package/vite.config.ts +45 -0
- package/vite.docs.config.ts +31 -0
- package/.eslintignore +0 -6
- package/.eslintrc +0 -12
- package/.husky/pre-commit +0 -5
- package/.prettierrc +0 -0
- package/.release-it.json +0 -5
- package/CHANGELOG.md +0 -56
- package/__tests__/fixtures/unknown/.gitkeep +0 -0
- package/__tests__/lib/classifier.test.js +0 -49
- package/__tests__/lib/helpers/util.test.js +0 -57
- package/bin/deploy-delete.js +0 -14
- package/bin/deploy-deploy.js +0 -36
- package/bin/deploy-list.js +0 -40
- package/bin/deploy-login.js +0 -43
- package/bin/deploy-logout.js +0 -16
- package/bin/deploy-logs.js +0 -26
- package/bin/deploy-open.js +0 -26
- package/bin/deploy-register.js +0 -45
- package/bin/deploy-server.js +0 -11
- package/bin/deploy-whoami.js +0 -14
- package/examples/docker/index.js +0 -12
- package/examples/node/index.js +0 -8
- package/examples/static/main.css +0 -9
- package/examples/static/out.gifcd +0 -0
- package/generate-docs.js +0 -55
- package/index.js +0 -69
- package/jsdoc.json +0 -27
- package/lib/classifier.js +0 -63
- package/lib/deploy.js +0 -70
- package/lib/helpers/cli.js +0 -262
- package/lib/helpers/util.js +0 -140
- package/lib/models/deployment.js +0 -474
- package/lib/models/request.js +0 -101
- package/lib/models/user.js +0 -147
- package/lib/server.js +0 -211
- package/lib/static/not-found.html +0 -30
- package/lib/static/page-could-not-load.html +0 -30
- package/lib/static/static-server.js +0 -70
- package/website/README.md +0 -41
- package/website/babel.config.js +0 -3
- package/website/docs/api/_category_.yml +0 -1
- package/website/docs/api/lib/classifier.js.md +0 -11
- package/website/docs/api/lib/deploy.js.md +0 -13
- package/website/docs/api/lib/helpers/cli.js.md +0 -193
- package/website/docs/api/lib/helpers/util.js.md +0 -65
- package/website/docs/api/lib/models/deployment.js.md +0 -171
- package/website/docs/api/lib/models/request.js.md +0 -67
- package/website/docs/api/lib/models/user.js.md +0 -92
- package/website/docs/api/lib/server.js.md +0 -0
- package/website/docs/api/lib/static/static-server.js.md +0 -0
- package/website/docs/intro.md +0 -57
- package/website/docusaurus.config.js +0 -82
- package/website/package-lock.json +0 -25218
- package/website/package.json +0 -39
- package/website/sidebars.js +0 -31
- package/website/src/components/HomepageFeatures/index.js +0 -79
- package/website/src/components/HomepageFeatures/styles.module.css +0 -11
- package/website/src/css/custom.css +0 -39
- package/website/src/pages/index.js +0 -57
- package/website/src/pages/index.module.css +0 -23
- package/website/static/.nojekyll +0 -0
- package/website/static/example.gif +0 -0
- package/website/static/example.mov +0 -0
- package/website/static/img/favicon.ico +0 -0
- package/website/static/img/intro/deploy.png +0 -0
- package/website/static/img/intro/logs.png +0 -0
- package/website/static/img/logo.png +0 -0
- package/website/static/img/logo.pxm +0 -0
- package/website/static/img/logo@2x.png +0 -0
package/lib/helpers/cli.js
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import tar from "tar";
|
|
2
|
-
import os from "os";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import { promisify } from "util";
|
|
6
|
-
import FormData from "form-data";
|
|
7
|
-
|
|
8
|
-
import { request } from "./util.js";
|
|
9
|
-
|
|
10
|
-
const unlink = promisify(fs.unlink);
|
|
11
|
-
const writeFile = promisify(fs.writeFile);
|
|
12
|
-
const readFile = promisify(fs.readFile);
|
|
13
|
-
|
|
14
|
-
class CLI {
|
|
15
|
-
/**
|
|
16
|
-
* the cli instance that holds all options and methods to talk to the deploy.sh service
|
|
17
|
-
* @class CLI
|
|
18
|
-
* @param {Object} options - contains defaults and overrides
|
|
19
|
-
* @param {String} options.url - the url of the remote deploy.sh service
|
|
20
|
-
* @param {String} options.application - the deployed application name to alter
|
|
21
|
-
* @param {String} options.mongo - the mongo connection string used by deploy.sh service when running `deploy serve --mongo ''`
|
|
22
|
-
*/
|
|
23
|
-
constructor(options) {
|
|
24
|
-
this.url = options.url;
|
|
25
|
-
this.application = options.application;
|
|
26
|
-
this.mongo = options.mongo;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* creates a bundle to send to the server for deployment
|
|
30
|
-
* @memberof CLI
|
|
31
|
-
* @method createBundle
|
|
32
|
-
* @param {String} directory - the directory that is to be turned into a tar
|
|
33
|
-
* @return {Promise}
|
|
34
|
-
*/
|
|
35
|
-
createBundle(directory) {
|
|
36
|
-
return tar.c(
|
|
37
|
-
{
|
|
38
|
-
gzip: true,
|
|
39
|
-
portable: true,
|
|
40
|
-
file: "bundle.tgz",
|
|
41
|
-
},
|
|
42
|
-
fs.readdirSync(directory)
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* removes the bundle from the given directory
|
|
47
|
-
* @memberof CLI
|
|
48
|
-
* @method removeBundle
|
|
49
|
-
* @param {String} directory - path to directory
|
|
50
|
-
* @return {Promise}
|
|
51
|
-
*/
|
|
52
|
-
async removeBundle(directory) {
|
|
53
|
-
return await unlink(path.resolve(directory, "bundle.tgz"));
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Deals with uploading a specified bundle
|
|
57
|
-
* @memberof CLI
|
|
58
|
-
* @method uploadBundle
|
|
59
|
-
* @param {Object} options
|
|
60
|
-
* @param {String} options.name - the name of the specified application
|
|
61
|
-
* @param {Stream} options.bundle - a file stream of the tar
|
|
62
|
-
* @return {Promise}
|
|
63
|
-
*/
|
|
64
|
-
async uploadBundle({ name, bundle, token, username }) {
|
|
65
|
-
const form = new FormData();
|
|
66
|
-
|
|
67
|
-
form.append("name", name);
|
|
68
|
-
form.append("bundle", bundle);
|
|
69
|
-
|
|
70
|
-
return await request("post", {
|
|
71
|
-
url: `${this.url}/upload`,
|
|
72
|
-
headers: {
|
|
73
|
-
"x-deploy-token": token,
|
|
74
|
-
"x-deploy-username": username,
|
|
75
|
-
...form.getHeaders(),
|
|
76
|
-
},
|
|
77
|
-
data: form.getBuffer(),
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* calls the login api to get a token to persist for future requests
|
|
82
|
-
* @method login
|
|
83
|
-
* @memberof CLI
|
|
84
|
-
* @param {Object} options
|
|
85
|
-
* @param {String} options.username - username of the account
|
|
86
|
-
* @param {String} options.password - password associated with the account
|
|
87
|
-
* @return {Promise}
|
|
88
|
-
*/
|
|
89
|
-
async login({ username, password }) {
|
|
90
|
-
return await request("post", {
|
|
91
|
-
url: `${this.url}/login`,
|
|
92
|
-
data: {
|
|
93
|
-
username,
|
|
94
|
-
password,
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* prompts the user to register account
|
|
100
|
-
* @method register
|
|
101
|
-
* @memberof CLI
|
|
102
|
-
* @param {Object} options
|
|
103
|
-
* @param {String} options.username - username of the account
|
|
104
|
-
* @param {String} options.password - password associated with the account
|
|
105
|
-
* @return {Promise}
|
|
106
|
-
*/
|
|
107
|
-
async register({ username, password }) {
|
|
108
|
-
return await request("post", {
|
|
109
|
-
url: `${this.url}/register`,
|
|
110
|
-
data: {
|
|
111
|
-
username,
|
|
112
|
-
password,
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* calls the logout api to invalidate token
|
|
118
|
-
* @memberof CLI
|
|
119
|
-
* @method logout
|
|
120
|
-
* @param {Object} options
|
|
121
|
-
* @param {String} options.token - token to make authenticated calls
|
|
122
|
-
* @param {String} options.username - username linked to the token
|
|
123
|
-
* @return {Promise}
|
|
124
|
-
*/
|
|
125
|
-
async logout({ token, username }) {
|
|
126
|
-
return await request("get", {
|
|
127
|
-
url: `${this.url}/api/logout`,
|
|
128
|
-
headers: {
|
|
129
|
-
"x-deploy-token": token,
|
|
130
|
-
"x-deploy-username": username,
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* gets the application logs
|
|
136
|
-
* @memberof CLI
|
|
137
|
-
* @method getLogs
|
|
138
|
-
* @param {Object} options
|
|
139
|
-
* @param {String} options.token - token to make authenticated calls
|
|
140
|
-
* @param {String} options.username - username linked to the token
|
|
141
|
-
* @param {String} options.name - name of the deployment
|
|
142
|
-
* @return {Promise}
|
|
143
|
-
*/
|
|
144
|
-
async getLogs({ token, username, name }) {
|
|
145
|
-
return await request("get", {
|
|
146
|
-
url: `${this.url}/api/deployments/${name}/logs`,
|
|
147
|
-
headers: {
|
|
148
|
-
"x-deploy-token": token,
|
|
149
|
-
"x-deploy-username": username,
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* gets the user's deployed applications
|
|
155
|
-
* @memberof CLI
|
|
156
|
-
* @method getDeployments
|
|
157
|
-
* @param {Object} options
|
|
158
|
-
* @param {String} options.token - token to make authenticated calls
|
|
159
|
-
* @param {String} options.username - username linked to the token
|
|
160
|
-
* @param {String=} options.name - name of the deployment
|
|
161
|
-
* @return {Promise}
|
|
162
|
-
*/
|
|
163
|
-
async getDeployments({ token, username, name }) {
|
|
164
|
-
let uri = `${this.url}/api/deployments`;
|
|
165
|
-
if (name) uri += `/${name}`;
|
|
166
|
-
|
|
167
|
-
return await request("get", {
|
|
168
|
-
url: uri,
|
|
169
|
-
headers: {
|
|
170
|
-
"x-deploy-token": token,
|
|
171
|
-
"x-deploy-username": username,
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* deletes the specified deployment
|
|
177
|
-
* @memberof CLI
|
|
178
|
-
* @method deleteDeployment
|
|
179
|
-
* @param {Object} options
|
|
180
|
-
* @param {String} options.token - token to make authenticated calls
|
|
181
|
-
* @param {String} options.username - username linked to the token
|
|
182
|
-
* @param {String} options.name - name of the deployment
|
|
183
|
-
* @return {Promise}
|
|
184
|
-
*/
|
|
185
|
-
async deleteDeployment({ name, token, username }) {
|
|
186
|
-
return await request("delete", {
|
|
187
|
-
url: `${this.url}/api/deployments/${name}`,
|
|
188
|
-
headers: {
|
|
189
|
-
"x-deploy-token": token,
|
|
190
|
-
"x-deploy-username": username,
|
|
191
|
-
},
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
/**
|
|
195
|
-
* gets the user details
|
|
196
|
-
* @memberof CLI
|
|
197
|
-
* @method getUserDetails
|
|
198
|
-
* @param {String} options.token - token to make authenticated calls
|
|
199
|
-
* @param {String} options.username - username linked to the token
|
|
200
|
-
* @return {Promise}
|
|
201
|
-
*/
|
|
202
|
-
async getUserDetails({ token, username }) {
|
|
203
|
-
return await request("get", {
|
|
204
|
-
url: `${this.url}/api/user`,
|
|
205
|
-
headers: {
|
|
206
|
-
"x-deploy-token": token,
|
|
207
|
-
"x-deploy-username": username,
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
/**
|
|
212
|
-
* persists the token and username locally
|
|
213
|
-
* @memberof CLI
|
|
214
|
-
* @method cacheCredentials
|
|
215
|
-
* @param {Object} options
|
|
216
|
-
* @param {String} options.token - token to make authenticated calls
|
|
217
|
-
* @param {String} options.username - username linked to the token
|
|
218
|
-
* @return {Promise}
|
|
219
|
-
*/
|
|
220
|
-
async cacheCredentials({ username, token }) {
|
|
221
|
-
const credentials = {
|
|
222
|
-
username,
|
|
223
|
-
token,
|
|
224
|
-
};
|
|
225
|
-
const configPath = path.resolve(os.homedir(), ".deployrc");
|
|
226
|
-
|
|
227
|
-
await writeFile(configPath, JSON.stringify(credentials, null, 4));
|
|
228
|
-
|
|
229
|
-
return {
|
|
230
|
-
username,
|
|
231
|
-
token,
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* gets the token and username that were persisted locally
|
|
236
|
-
* @memberof CLI
|
|
237
|
-
* @method getCredentials
|
|
238
|
-
* @return {Promise}
|
|
239
|
-
*/
|
|
240
|
-
async getCredentials() {
|
|
241
|
-
try {
|
|
242
|
-
const configPath = path.resolve(os.homedir(), ".deployrc");
|
|
243
|
-
const credentials = JSON.parse(await readFile(configPath));
|
|
244
|
-
const { username, token } = credentials;
|
|
245
|
-
if (username && token) {
|
|
246
|
-
return {
|
|
247
|
-
username,
|
|
248
|
-
token,
|
|
249
|
-
};
|
|
250
|
-
} else {
|
|
251
|
-
throw new Error("credentials not found");
|
|
252
|
-
}
|
|
253
|
-
} catch (ex) {
|
|
254
|
-
if (ex.code === "ENOENT") {
|
|
255
|
-
throw new Error("You are not logged in, please login to view identity");
|
|
256
|
-
}
|
|
257
|
-
throw new Error(ex);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export default CLI;
|
package/lib/helpers/util.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module lib/helpers/util
|
|
3
|
-
*/
|
|
4
|
-
import net from "net";
|
|
5
|
-
|
|
6
|
-
import fs from "fs";
|
|
7
|
-
import { promisify } from "util";
|
|
8
|
-
import axios from "axios";
|
|
9
|
-
|
|
10
|
-
const readdir = promisify(fs.readdir);
|
|
11
|
-
const stat = promisify(fs.stat);
|
|
12
|
-
const unlink = promisify(fs.unlink);
|
|
13
|
-
const rmdir = promisify(fs.rmdir);
|
|
14
|
-
const mkdir = promisify(fs.mkdir);
|
|
15
|
-
|
|
16
|
-
let portrange = 45032;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* gets an open port
|
|
20
|
-
* @method getPort
|
|
21
|
-
* @return {Promise}
|
|
22
|
-
*/
|
|
23
|
-
export const getPort = function getPort() {
|
|
24
|
-
return new Promise((resolve, reject) => {
|
|
25
|
-
try {
|
|
26
|
-
portrange += 1;
|
|
27
|
-
var server = net.createServer();
|
|
28
|
-
|
|
29
|
-
server.listen(portrange, () => {
|
|
30
|
-
server.once("close", () => {
|
|
31
|
-
return resolve(portrange);
|
|
32
|
-
});
|
|
33
|
-
server.close();
|
|
34
|
-
});
|
|
35
|
-
server.on("error", () => resolve(getPort()));
|
|
36
|
-
} catch (ex) {
|
|
37
|
-
return reject(ex);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* makes a directory recursively
|
|
44
|
-
* @param {String} directory - path to future directory
|
|
45
|
-
* @return {Promise}
|
|
46
|
-
*/
|
|
47
|
-
export const mk = async function mk(directory) {
|
|
48
|
-
let cwd = "";
|
|
49
|
-
let path = directory.split("/");
|
|
50
|
-
// If the first value is blank that means we were given an absolute path and should respect that
|
|
51
|
-
if (path[0] == "") {
|
|
52
|
-
path[1] = `/${path[1]}`;
|
|
53
|
-
}
|
|
54
|
-
// remove all of the empty entries
|
|
55
|
-
path = path.filter((p) => p !== "");
|
|
56
|
-
|
|
57
|
-
for (var i = 0; i <= path.length - 1; i++) {
|
|
58
|
-
cwd += `${path[i]}${i === path.length - 1 ? "" : "/"}`;
|
|
59
|
-
try {
|
|
60
|
-
// try to open the directory, if we can't we will create it
|
|
61
|
-
await readdir(cwd);
|
|
62
|
-
} catch (ex) {
|
|
63
|
-
if (ex.message.indexOf("no such file or directory") > -1) {
|
|
64
|
-
await mkdir(cwd);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return cwd;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* gets a lowercase random string with specified length
|
|
73
|
-
* @method hash
|
|
74
|
-
* @param {Number} length - the specified length of the random string
|
|
75
|
-
* @return {String}
|
|
76
|
-
*/
|
|
77
|
-
const possible = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
78
|
-
|
|
79
|
-
export const hash = function hash(length) {
|
|
80
|
-
let text = "";
|
|
81
|
-
|
|
82
|
-
for (let i = 0; i < length; i++) {
|
|
83
|
-
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return text;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const request = async function request(type, options) {
|
|
90
|
-
const { data } = await axios({
|
|
91
|
-
method: type,
|
|
92
|
-
...options,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
return data;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* contains is a function that takes an array and see if the condition matches
|
|
100
|
-
* @method contains
|
|
101
|
-
* @param {Array} arr - array to check with rules
|
|
102
|
-
* @param {Array} contains - rules to make sure the arr contains the following
|
|
103
|
-
* @return {Boolean} - responds back with a boolean value
|
|
104
|
-
* @example
|
|
105
|
-
* contains(['index.html', 'main.css'], ['index.html', '!Dockerfile', '!package.json'])
|
|
106
|
-
*/
|
|
107
|
-
export const contains = function contains(arr, contains) {
|
|
108
|
-
var conditions = [];
|
|
109
|
-
for (var i in contains) {
|
|
110
|
-
var key =
|
|
111
|
-
contains[i].substring(0, 1) === "!"
|
|
112
|
-
? contains[i].substring(1, contains[i].length)
|
|
113
|
-
: contains[i];
|
|
114
|
-
conditions.push(
|
|
115
|
-
contains[i].substring(0, 1) === "!"
|
|
116
|
-
? arr.indexOf(key) === -1
|
|
117
|
-
: arr.indexOf(key) > -1
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
if (conditions.indexOf(false) > -1) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
return true;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
export const rm = async function rm(dir) {
|
|
127
|
-
let files = await readdir(dir);
|
|
128
|
-
|
|
129
|
-
if (files.length > 0) {
|
|
130
|
-
for (var i = 0; i < files.length; i++) {
|
|
131
|
-
var file = dir + "/" + files[i];
|
|
132
|
-
if ((await stat(file)).isFile()) {
|
|
133
|
-
await unlink(file);
|
|
134
|
-
} else {
|
|
135
|
-
await rm(file);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
await rmdir(dir);
|
|
140
|
-
};
|