Rewrite install
This commit is contained in:
parent
9bcce8ede3
commit
dcccb8d4c0
22
README.md
22
README.md
|
@ -117,3 +117,25 @@ const stream = new WritableBuffer();
|
||||||
sourceStream.pipe(stream);
|
sourceStream.pipe(stream);
|
||||||
sourceStream.on('end', () => useData(stream.get()));
|
sourceStream.on('end', () => useData(stream.get()));
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## utils.js
|
||||||
|
|
||||||
|
* `read` - (async) Reads a whole file to string, NOT A Buffer.
|
||||||
|
* `write` - (async) Write a file.
|
||||||
|
* `copy` - (async) Copy a file.
|
||||||
|
* `exists` - (async) Check if a file/folder exists.
|
||||||
|
* `mkdir` - (async) Create an empty folder.
|
||||||
|
* `stat` - (async) Get status on a file.
|
||||||
|
* `isDir` - (async) Check if the path is a folder.
|
||||||
|
* `isFile` - (async) Check if the path is a file.
|
||||||
|
* `dirUp` - Cut the path one folder up.
|
||||||
|
* `ensuredir` - (async) Like `mkdir -p`, makes sure a directory exists.
|
||||||
|
* `copysafe` - (async) Copy a file, `dest` folder is created if needed.
|
||||||
|
* `readdir` - (async) Get file/folder names of the 1st level.
|
||||||
|
* `subdirs` - (async) Get folder paths (concatenated with input) of the 1st level.
|
||||||
|
* `subfiles` - (async) Get file paths (concatenated with input) of the 1st level.
|
||||||
|
* `traverse` - (async) Get all nested files recursively.
|
||||||
|
* `copyall` - (async) Copy a folder with all the contained files.
|
||||||
|
* `rmdir` - (async) Like `rm -rf`, removes everything recursively.
|
||||||
|
* `rm` - (async) Remove a file. Must be a file, not a folder. Just `fs.unlink`.
|
||||||
|
|
49
install.js
49
install.js
|
@ -8,6 +8,7 @@ const fs = require('fs');
|
||||||
const AdmZip = require('adm-zip');
|
const AdmZip = require('adm-zip');
|
||||||
|
|
||||||
const { bin, platform } = require('.');
|
const { bin, platform } = require('.');
|
||||||
|
const { mkdir, rm } = require('./utils');
|
||||||
|
|
||||||
|
|
||||||
const protocols = { http, https };
|
const protocols = { http, https };
|
||||||
|
@ -20,11 +21,16 @@ const onError = msg => {
|
||||||
const zipPath = `${bin}/${bin}.zip`;
|
const zipPath = `${bin}/${bin}.zip`;
|
||||||
|
|
||||||
|
|
||||||
const install = (url, count = 1) => {
|
const install = async (url, count = 1) => {
|
||||||
|
try {
|
||||||
const proto = protocols[url.match(/^https?/)[0]];
|
|
||||||
|
const proto = protocols[url.match(/^https?/)[0]];
|
||||||
const request = proto.get(url, response => {
|
|
||||||
|
const response = await new Promise((res, rej) => {
|
||||||
|
const request = proto.get(url, response => res(response));
|
||||||
|
request.on('error', err => rej(err));
|
||||||
|
});
|
||||||
|
response.on('error', err => { throw err; });
|
||||||
|
|
||||||
// Handle redirects
|
// Handle redirects
|
||||||
if ([301, 302, 303, 307].includes(response.statusCode)) {
|
if ([301, 302, 303, 307].includes(response.statusCode)) {
|
||||||
|
@ -32,36 +38,37 @@ const install = (url, count = 1) => {
|
||||||
return install(response.headers.location, count + 1);
|
return install(response.headers.location, count + 1);
|
||||||
}
|
}
|
||||||
console.log(url);
|
console.log(url);
|
||||||
return onError('Error: Too many redirects.');
|
throw new Error('Error: Too many redirects.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle bad status
|
// Handle bad status
|
||||||
if (response.statusCode !== 200) {
|
if (response.statusCode !== 200) {
|
||||||
console.log(url);
|
console.log(url);
|
||||||
return onError(`Response status was ${response.statusCode}`);
|
throw new Error(`Response status was ${response.statusCode}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.on('error', err => onError(err.message));
|
await mkdir(bin);
|
||||||
|
|
||||||
fs.mkdirSync(bin);
|
await new Promise((res, rej) => {
|
||||||
const zipWriter = fs.createWriteStream(zipPath);
|
const zipWriter = fs.createWriteStream(zipPath);
|
||||||
zipWriter.on('error', err => onError(err.message));
|
zipWriter.on('error', err => rej(err));
|
||||||
response.pipe(zipWriter);
|
zipWriter.on('finish', () => res());
|
||||||
|
response.pipe(zipWriter);
|
||||||
zipWriter.on('finish', () => {
|
|
||||||
const zip = new AdmZip(zipPath);
|
|
||||||
zip.extractAllTo(bin, true);
|
|
||||||
fs.unlinkSync(zipPath);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
const zip = new AdmZip(zipPath);
|
||||||
|
zip.extractAllTo(bin, true);
|
||||||
request.on('error', err => onError(err.message));
|
|
||||||
|
await rm(zipPath);
|
||||||
|
|
||||||
|
} catch (ex) {
|
||||||
|
onError(ex.message);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = folder => {
|
module.exports = folder => {
|
||||||
const url = `${folder}/${platform}.zip`;
|
const url = `${folder}/${platform}.zip`;
|
||||||
install(url);
|
install(url).then();
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// (async) Reads a whole file to string, NOT A Buffer
|
||||||
|
const read = name => new Promise(
|
||||||
|
(res, rej) => fs.readFile(
|
||||||
|
name,
|
||||||
|
(err, data) => (err ? rej(err) : res(data.toString()))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Write a file
|
||||||
|
const write = (name, text) => new Promise(
|
||||||
|
(res, rej) => fs.writeFile(name, text, err => (err ? rej(err) : res()))
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Copy a file
|
||||||
|
const copy = async (src, dest) => {
|
||||||
|
try {
|
||||||
|
await new Promise(
|
||||||
|
(res, rej) => fs.copyFile(src, dest, err => (err ? rej(err) : res()))
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'EBUSY') {
|
||||||
|
console.warn('WARNING\n', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Check if a file/folder exists
|
||||||
|
const exists = name => new Promise(
|
||||||
|
res => fs.access(
|
||||||
|
name,
|
||||||
|
fs.constants.F_OK,
|
||||||
|
err => res(err ? false : true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Create an empty folder
|
||||||
|
const mkdir = async name => {
|
||||||
|
if (await exists(name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return new Promise(
|
||||||
|
(res, rej) => fs.mkdir(name, err => (err ? rej(err) : res()))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Get status on a file
|
||||||
|
const stat = name => new Promise(
|
||||||
|
(res, rej) => fs.stat(name, (err, stats) => (err ? rej(err) : res(stats)))
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Check if the path is a folder
|
||||||
|
const isDir = async name => (await stat(name)).isDirectory();
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Check if the path is a file
|
||||||
|
const isFile = async name => (await stat(name)).isFile();
|
||||||
|
|
||||||
|
|
||||||
|
// Cut the path one folder up
|
||||||
|
const dirUp = dir => dir.replace(/\\/g, '/').split('/').slice(0, -1).join('/');
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Like `mkdir -p`, makes sure a directory exists
|
||||||
|
const ensuredir = async dir => {
|
||||||
|
if (await exists(dir) && await isDir(dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await ensuredir(dirUp(dir));
|
||||||
|
await mkdir(dir);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Copy a file, `dest` folder is created if needed
|
||||||
|
const copysafe = async (src, dest) => {
|
||||||
|
await ensuredir(dirUp(dest));
|
||||||
|
await copy(src, dest);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Get file/folder names of the 1st level
|
||||||
|
const readdir = name => new Promise(
|
||||||
|
(res, rej) => fs.readdir(
|
||||||
|
name,
|
||||||
|
(err, dirents) => (err ? rej(err) : res(dirents))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Get folder paths (concatenated with input) of the 1st level
|
||||||
|
const subdirs = async name => {
|
||||||
|
const all = await readdir(name);
|
||||||
|
const mapped = await Promise.all(all.map(d => isDir(`${name}/${d}`)));
|
||||||
|
return all.filter((_, i) => mapped[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Get file paths (concatenated with input) of the 1st level
|
||||||
|
const subfiles = async name => {
|
||||||
|
const all = await readdir(name);
|
||||||
|
const mapped = await Promise.all(all.map(d => isFile(`${name}/${d}`)));
|
||||||
|
return all.filter((_, i) => mapped[i]).map(f => `${name}/${f}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Get all nested files recursively
|
||||||
|
// Folder paths are omitted by default
|
||||||
|
// Order is: shallow-to-deep, each subdirectory lists dirs-then-files.
|
||||||
|
const traverse = async (name, showDirs = false) => {
|
||||||
|
const dirs = [];
|
||||||
|
const stack = [name];
|
||||||
|
while (stack.length) {
|
||||||
|
const dir = stack.pop();
|
||||||
|
dirs.push(dir);
|
||||||
|
(await subdirs(dir)).forEach(d => stack.push(`${dir}/${d}`));
|
||||||
|
}
|
||||||
|
return (showDirs ? dirs : []).concat(
|
||||||
|
...(await Promise.all(dirs.map(subfiles)))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Copy a folder with all the contained files
|
||||||
|
const copyall = async (src, dest) => {
|
||||||
|
const files = (await traverse(src, true)).reverse();
|
||||||
|
while (files.length) {
|
||||||
|
const target = files.pop();
|
||||||
|
const dir = await isDir(target);
|
||||||
|
if (dir) {
|
||||||
|
await mkdir(target.replace(src, dest));
|
||||||
|
} else {
|
||||||
|
await copy(target, target.replace(src, dest));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Like `rm -rf`, removes everything recursively
|
||||||
|
const rmdir = async name => {
|
||||||
|
if ( ! await exists(name) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const paths = await traverse(name, true);
|
||||||
|
while (paths.length) {
|
||||||
|
const target = paths.pop();
|
||||||
|
const dir = await isDir(target);
|
||||||
|
await new Promise(
|
||||||
|
(res, rej) => fs[dir ? 'rmdir' : 'unlink'](
|
||||||
|
target,
|
||||||
|
err => (err ? rej(err) : res())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// (async) Remove a file. Must be a file, not a folder. Just `fs.unlink`.
|
||||||
|
const rm = async name => {
|
||||||
|
if ( ! await exists(name) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await new Promise(
|
||||||
|
(res, rej) => fs.unlink(name, err => (err ? rej(err) : res()))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
read,
|
||||||
|
write,
|
||||||
|
copy,
|
||||||
|
exists,
|
||||||
|
mkdir,
|
||||||
|
stat,
|
||||||
|
isDir,
|
||||||
|
isFile,
|
||||||
|
dirUp,
|
||||||
|
ensuredir,
|
||||||
|
copysafe,
|
||||||
|
readdir,
|
||||||
|
subdirs,
|
||||||
|
subfiles,
|
||||||
|
traverse,
|
||||||
|
copyall,
|
||||||
|
rmdir,
|
||||||
|
rm,
|
||||||
|
};
|
Loading…
Reference in New Issue