Partial export processing
This commit is contained in:
357
src/helpers.js
357
src/helpers.js
@@ -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);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user