twokeys-server
Version:
Server for 2Keys
213 lines (209 loc) • 8.14 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
Copyright 2018 Kishan Sambhi
This file is part of 2Keys.
2Keys is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
2Keys is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with 2Keys. If not, see <https://www.gnu.org/licenses/>.
*/
const mkdirp_1 = __importDefault(require("mkdirp"));
const path_1 = __importDefault(require("path"));
const progress_1 = __importDefault(require("progress"));
const fs_1 = __importStar(require("fs"));
const util_1 = require("util");
const logger_1 = __importDefault(require("./logger"));
const readdir = util_1.promisify(fs_1.readdir);
const stat = util_1.promisify(fs_1.stat);
const logger = new logger_1.default({
name: "copy"
});
/**
* Generates a file tree of all the files
* @param root Root dir to start at
*/
function generate_file_tree(root) {
return new Promise(async (resolve, reject) => {
const files = [];
try {
const contents = await readdir(root);
for (let file of contents) {
const absolutePath = path_1.default.join(root, file);
// Dir or file?
const status = await stat(absolutePath);
if (status.isDirectory()) {
// Is dir, run this func on it
const dirNode = {
type: "dir",
path: absolutePath,
contents: await generate_file_tree(absolutePath),
};
files.push(dirNode);
}
else {
// It's a file!
files.push({
type: "file",
path: absolutePath
});
}
}
}
catch (err) {
reject(err);
}
finally {
resolve(files);
}
});
}
/**
* Gets a list of dirs in a tree
* @param tree Tree generated byg enerate_file_tree()
*/
function get_dirs_from_tree(tree) {
return new Promise(async (resolve, reject) => {
const dirs = [];
for (let node of tree) {
// 1: check type
if (node.type === "file") {
continue;
}
else if (node.type === "dir") {
// Add to list, rerun function on it
dirs.push(node.path);
const nextDirs = await get_dirs_from_tree(node.contents); // Dirs in this current dir
nextDirs.forEach(dir => dirs.push(dir));
}
else {
reject(new Error(`Invalid file type! Only dir and file are allowed.`)); // TS complains if path is here
}
}
// Resolve
resolve(dirs);
});
}
/**
* Gets a list of files in a tree
* @param tree Tree generated byg enerate_file_tree()
*/
function get_files_from_tree(tree) {
return new Promise(async (resolve, reject) => {
const files = [];
for (let node of tree) {
// 1: check type
if (node.type === "dir") {
// Run function on dir to get files from it
const nextFiles = await get_files_from_tree(node.contents); // Dirs in this current dir
nextFiles.forEach(file => files.push(file));
}
else if (node.type === "file") {
// It's a file, add it
files.push(node.path);
}
else {
reject(new Error(`Invalid file type! Only dir and file are allowed`)); // TS complains if path is here
}
}
// Resolve
resolve(files);
});
}
function mkdirs(root, destination, progress_bar, dirs) {
return new Promise((resolve, reject) => {
// MKDIR
for (let dir of dirs) {
// Make relative to root, then attach dest to start i.e.
// C:\AHK\ahk-v2 => .\ahk-v2 -> D:\software\.\ahk-v2
const relativeDir = path_1.default.join(destination, path_1.default.relative(root, dir));
mkdirp_1.default(relativeDir)
.then(() => {
progress_bar.tick({
action: "mkdir",
symbol: ">>",
dest: relativeDir,
});
// At end?
if (dir === dirs[dirs.length - 1]) {
resolve();
}
})
.catch(reject);
}
});
}
/**
* Copies the contents of root to the directory destination (i.e. no sub-dir created at dest with the name of root)
* @param root Root directory with files to copy
* @param destination Destinatian directory (will be created if it does not exist)
*/
async function copy_contents(root, destination) {
return new Promise(async (resolve, reject) => {
logger.info(`Copying files from ${root} to ${destination}...`);
logger.debug("Generating file tree...");
try {
const tree = await generate_file_tree(root);
logger.debug("Creating dirs list...");
const dirs = await get_dirs_from_tree(tree);
// Do copy action
logger.debug("Creating file list....");
const files = await get_files_from_tree(tree);
// DO IT
logger.debug("Copying...");
const total = dirs.length + files.length;
// Progress bar
// Where action is "mkdir" or the file being copied
// And :dest is the file being copied to or dir being made
const progress_bar = new progress_1.default(':bar :percent .\\:action :symbol :dest', {
complete: '▓',
incomplete: '░',
width: 50,
total,
callback: () => resolve(),
});
let counter = 0;
// MKDIR
// Done this way to ensure dirs are ready
await mkdirs(root, destination, progress_bar, dirs);
// COPY
for (let file of files) {
const relativePath = path_1.default.join(destination, path_1.default.relative(root, file));
const reader = fs_1.default.createReadStream(file);
const writer = fs_1.default.createWriteStream(relativePath);
reader.on("error", err => reject(err));
writer.on("error", err => reject(err));
reader.pipe(writer);
reader.on("close", () => {
progress_bar.tick({
action: path_1.default.relative(root, file),
symbol: "->",
dest: path_1.default.relative(root, path_1.default.join(destination, path_1.default.relative(root, file))),
});
});
}
// We're done!
}
catch (err) {
reject(err);
}
});
}
exports.default = copy_contents;
//# sourceMappingURL=copy-contents.js.map