Partial export processing

This commit is contained in:
2020-06-17 16:57:57 -05:00
parent e69dfa9565
commit 53a236000e
9 changed files with 436 additions and 137 deletions

View File

@@ -9,7 +9,6 @@ const Constants = require('./constants');
const RandomString = require('randomstring');
let vcRuntimeExists;
const _vcRuntimeExists = () => {
return new Promise((resolve, reject) => {
if (os.platform() !== 'win32') {
@@ -19,7 +18,7 @@ const _vcRuntimeExists = () => {
resolve(true);
} else {
const cmd = path.join(process.env.windir, 'system32', 'reg.exe');
const args = ["QUERY", "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"];
const args = ['QUERY', 'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'];
_execProcessGetOutput(cmd, null, args)
.then(lines => {
const parseLine = index => {
@@ -62,7 +61,93 @@ const _vcRuntimeExists = () => {
});
};
const _executeProcess = (command, working, args=[]) => {
// https://stackoverflow.com/questions/19531453/transform-file-directory-structure-into-tree-in-javascript
const _createTreeNodes = fileList => {
let tree = {}
const directorySort = (a, b) => {
return !!a.directory === !!b.directory ? a.name.localeCompare(b.name) : a.directory ? -1 : 1;
};
const addNode = obj => {
const fullPath = path.join(obj.directory, obj.filename).replace(/\\/g, '/');
const pathParts = fullPath.replace(/^\/|\/$/g, '').split('/');
let ptr = tree;
for (let i = 0; i < pathParts.length; i++) {
const node = {
directory: true,
name: pathParts[i],
};
if (i === pathParts.length - 1) {
node.directory = false;
node.path = fullPath;
}
ptr[pathParts[i]] = ptr[pathParts[i]] || node;
ptr[pathParts[i]].children = ptr[pathParts[i]].children || {};
ptr = ptr[pathParts[i]].children;
}
}
const objectToArray = node => {
Object.keys(node || {}).map((k) => {
if (node[k].children) {
objectToArray(node[k])
}
})
if (node.children) {
node.children = Object.values(node.children);
node.children.forEach(objectToArray)
node.children = node.children.sort(directorySort);
}
}
fileList.map(addNode);
objectToArray(tree);
return Object.values(tree).sort(directorySort);
};
const _exportAllSkylinks = version => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
const processOptions = {
cwd: repertoryExec.working,
detached: true,
shell: false,
windowsHide: true,
};
const args = _getDefaultRepertoryArgs('Skynet');
args.push('-ea');
let result = '';
const process = new spawn(repertoryExec.cmd, args, processOptions);
process.on('error', (err) => {
reject(err);
});
process.stdout.on('data', (d) => {
result += d;
});
process.stderr.on('data', (d) => {
result += d;
});
process.on('exit', code => {
if (code === 0) {
result = result.substr(result.indexOf('{'));
resolve(JSON.parse(result));
} else {
reject(new Error('Failed to import: ' + code + ':' + result));
}
});
process.unref();
});
};
const _executeProcess = (command, working, args = []) => {
return new Promise((resolve, reject) => {
let processOptions = {
detached: true,
@@ -144,16 +229,16 @@ const _getRepertoryExec = version => {
const _removeDirectoryRecursively = dir => {
if (fs.existsSync(dir)) {
fs
.readdirSync(dir)
.forEach(file => {
const curPath = path.join(dir, file);
if (fs.lstatSync(curPath).isDirectory()) {
module.exports.removeDirectoryRecursively(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(dir);
.readdirSync(dir)
.forEach(file => {
const curPath = path.join(dir, file);
if (fs.lstatSync(curPath).isDirectory()) {
module.exports.removeDirectoryRecursively(curPath);
} else {
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(dir);
}
};
@@ -206,13 +291,13 @@ module.exports.cleanupOldReleases = versionList => {
if (versionList && versionList.length > 0) {
const dataDir = _getDataDirectory();
const directoryList = fs
.readdirSync(dataDir, {withFileTypes: true})
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent);
.readdirSync(dataDir, {withFileTypes: true})
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent);
const removeList = directoryList
.filter(dirent => !versionList.includes(dirent.name))
.map(dirent => dirent.name);
.filter(dirent => !versionList.includes(dirent.name))
.map(dirent => dirent.name);
for (const dir of removeList) {
try {
@@ -320,51 +405,51 @@ module.exports.downloadFile = (url, destination, progressCallback, completeCallb
}
axios
.get(url, {
responseType: 'stream',
})
.then(response => {
try {
const total = parseInt(response.headers['content-length'], 10);
if (total === 0) {
completeCallback(Error('No data available for download'));
} else {
const stream = fs.createWriteStream(destination);
.get(url, {
responseType: 'stream',
})
.then(response => {
try {
const total = parseInt(response.headers['content-length'], 10);
if (total === 0) {
completeCallback(Error('No data available for download'));
} else {
const stream = fs.createWriteStream(destination);
let downloaded = 0;
response.data.on('data', (chunk) => {
stream.write(Buffer.from(chunk));
downloaded += chunk.length;
if (progressCallback) {
progressCallback((downloaded / total * 100.0).toFixed(2));
let downloaded = 0;
response.data.on('data', (chunk) => {
stream.write(Buffer.from(chunk));
downloaded += chunk.length;
if (progressCallback) {
progressCallback((downloaded / total * 100.0).toFixed(2));
}
});
response.data.on('end', () => {
stream.end(() => {
if (downloaded === 0) {
completeCallback(Error('Received 0 bytes'));
} else if (downloaded !== total) {
completeCallback(Error('Received incorrect number of bytes'));
} else {
completeCallback();
}
});
});
response.data.on('end', () => {
stream.end(() => {
if (downloaded === 0) {
completeCallback(Error('Received 0 bytes'));
} else if (downloaded !== total) {
completeCallback(Error('Received incorrect number of bytes'));
} else {
completeCallback();
}
});
response.data.on('error', error => {
stream.end(() => {
completeCallback(error);
});
response.data.on('error', error => {
stream.end(() => {
completeCallback(error);
});
});
}
} catch (error) {
completeCallback(error);
});
}
})
.catch(error => {
} catch (error) {
completeCallback(error);
});
}
})
.catch(error => {
completeCallback(error);
});
};
module.exports.executeAndWait = (command, ignoreResult) => {
@@ -392,7 +477,7 @@ module.exports.executeAndWait = (command, ignoreResult) => {
});
};
module.exports.executeAsync = (command, args=[]) => {
module.exports.executeAsync = (command, args = []) => {
return new Promise((resolve, reject) => {
const launchProcess = (count, timeout) => {
let cmd = path.basename(command);
@@ -416,7 +501,7 @@ module.exports.executeAsync = (command, args=[]) => {
reject(err, pid);
} else {
clearTimeout(timeout);
setTimeout(()=> launchProcess(count, setTimeout(() => resolve(), 3000)), 1000);
setTimeout(() => launchProcess(count, setTimeout(() => resolve(), 3000)), 1000);
}
});
@@ -458,7 +543,7 @@ module.exports.executeScript = script => {
reject(err);
});
process.stdout.on('data', (d)=> {
process.stdout.on('data', (d) => {
result += d;
});
@@ -510,6 +595,8 @@ module.exports.executeMount = (version, provider, remote, location, exitCallback
});
};
module.exports.exportAllSkylinks = _exportAllSkylinks;
module.exports.getConfig = (version, provider, remote) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
@@ -530,14 +617,14 @@ module.exports.getConfig = (version, provider, remote) => {
reject(err);
});
process.stdout.on('data', (d)=> {
process.stdout.on('data', (d) => {
result += d;
});
process.on('exit', () => {
const lines = result
.replace(/\r\n/g, '\n')
.split('\n');
.replace(/\r\n/g, '\n')
.split('\n');
const code = parseInt(lines[0], 10);
if (code === 0) {
@@ -574,7 +661,7 @@ module.exports.getConfigTemplate = (version, provider, remote) => {
reject(err);
});
process.stdout.on('data', (d)=> {
process.stdout.on('data', (d) => {
result += d;
});
@@ -607,16 +694,16 @@ module.exports.getMissingDependencies = dependencies => {
if (index >= dep.registry.length) {
if (dep.display === 'VC Runtime 2015-2019') {
_vcRuntimeExists()
.then(exists => {
if (!exists) {
missing.push(dep);
}
resolveIfComplete();
})
.catch(() => {
.then(exists => {
if (!exists) {
missing.push(dep);
resolveIfComplete();
})
}
resolveIfComplete();
})
.catch(() => {
missing.push(dep);
resolveIfComplete();
})
} else {
missing.push(dep);
resolveIfComplete();
@@ -666,7 +753,7 @@ module.exports.getMissingDependencies = dependencies => {
};
for (const dependency of dependencies) {
checkRegistry(dependency,0);
checkRegistry(dependency, 0);
}
} else {
for (const dep of dependencies) {
@@ -683,6 +770,22 @@ module.exports.getMissingDependencies = dependencies => {
});
};
module.exports.grabSkynetFileTree = version => {
return new Promise((resolve, reject) => {
_exportAllSkylinks(version)
.then(results => {
resolve([{
name: '/',
directory: true,
children: _createTreeNodes(results.success),
}]);
})
.catch(e => {
reject(e);
});
});
};
module.exports.importSkylinks = (version, jsonArray) => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
@@ -704,11 +807,11 @@ module.exports.importSkylinks = (version, jsonArray) => {
reject(err);
});
process.stdout.on('data', (d)=> {
process.stdout.on('data', (d) => {
result += d;
});
process.stderr.on('data', (d)=> {
process.stderr.on('data', (d) => {
result += d;
});
@@ -726,7 +829,7 @@ module.exports.importSkylinks = (version, jsonArray) => {
};
//https://stackoverflow.com/questions/31645738/how-to-create-full-path-with-nodes-fs-mkdirsync
module.exports.mkDirByPathSync = (targetDir, { isRelativeToScript = false } = {}) => {
module.exports.mkDirByPathSync = (targetDir, {isRelativeToScript = false} = {}) => {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
@@ -761,55 +864,55 @@ module.exports.performWindowsUninstall = names => {
reject('Windows OS is not being used');
} else {
const cmd = path.join(process.env.windir, 'system32', 'reg.exe');
const args = ["QUERY", "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"];
const args = ['QUERY', 'HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall'];
_execProcessGetOutput(cmd, null, args)
.then(lines => {
const parseLine = index => {
if (index < lines.length) {
const line = lines[index];
if (line.startsWith('HKEY_LOCAL_MACHINE\\')) {
let args2 = JSON.parse(JSON.stringify(args));
args2[1] = 'HKLM\\' + line.substr(19);
args2.push('/v');
args2.push('DisplayName');
args2.push('/t');
args2.push('REG_SZ');
_execProcessGetOutput(cmd, null, args2)
.then(lines => {
const value = lines[2].trim().substr(args2[3].length).trim().substr(6).trim();
if (names.includes(value)) {
const items = line.split('\\');
const productCode = items[items.length - 1];
_executeProcess('msiexec.exe', null,['/x', productCode, '/norestart'])
.then(code => {
if ((code === 0) || (code === 3010) || (code === 1641)) {
resolve(true);
} else {
reject('[' + value + '] uninstall failed: ' + code);
}
})
.catch(err => {
reject(err);
});
.then(lines => {
const parseLine = index => {
if (index < lines.length) {
const line = lines[index];
if (line.startsWith('HKEY_LOCAL_MACHINE\\')) {
let args2 = JSON.parse(JSON.stringify(args));
args2[1] = 'HKLM\\' + line.substr(19);
args2.push('/v');
args2.push('DisplayName');
args2.push('/t');
args2.push('REG_SZ');
_execProcessGetOutput(cmd, null, args2)
.then(lines => {
const value = lines[2].trim().substr(args2[3].length).trim().substr(6).trim();
if (names.includes(value)) {
const items = line.split('\\');
const productCode = items[items.length - 1];
_executeProcess('msiexec.exe', null, ['/x', productCode, '/norestart'])
.then(code => {
if ((code === 0) || (code === 3010) || (code === 1641)) {
resolve(true);
} else {
parseLine(++index);
reject('[' + value + '] uninstall failed: ' + code);
}
})
.catch(() => {
parseLine(++index);
.catch(err => {
reject(err);
});
} else {
} else {
parseLine(++index);
}
})
.catch(() => {
parseLine(++index);
}
});
} else {
resolve(false);
parseLine(++index);
}
};
parseLine(0);
})
.catch( err => {
reject(err);
});
} else {
resolve(false);
}
};
parseLine(0);
})
.catch(err => {
reject(err);
});
}
});
};
@@ -898,16 +1001,16 @@ module.exports.testRepertoryBinary = version => {
return new Promise((resolve, reject) => {
const repertoryExec = _getRepertoryExec(version);
_executeProcess(repertoryExec.cmd, repertoryExec.working, ['-dc'])
.then(code => {
if (code === 0) {
resolve();
} else {
reject(Error('Invalid exit code: ' + code));
}
})
.catch(error => {
reject(error);
});
.then(code => {
if (code === 0) {
resolve();
} else {
reject(Error('Invalid exit code: ' + code));
}
})
.catch(error => {
reject(error);
});
});
};