omnitool_on_hf / setup /updater.js
manu-sapiens's picture
copy of omnitool_latest - should be working
b39afbe
raw
history blame
5.94 kB
/**
* Copyright (c) 2023 MERCENARIES.AI PTE. LTD.
* All rights reserved.
*/
const fs = require('node:fs');
const path = require('node:path');
const { exec } = require('child_process');
const assert = require('node:assert');
const { execSync } = require('node:child_process');
const { getSHA256Checksum, statuslogger, omniCwd } = require('./utils.js');
const { extract } = require('tar');
const config = JSON.parse(
fs.readFileSync(path.join(omniCwd(), 'package.json'), { encoding: 'utf-8' }));
const path_destination_folder = path.join(omniCwd(), 'setup', 'updates');
const remote_releases_url = config.dependenciesBin.updates_base_url;
function _get_updater_url() {
const platform = process.platform;
const arch = process.arch;
assert(platform === 'win32' || platform === 'darwin' || platform === 'linux');
assert(arch === 'x64' || arch === 'arm64');
return `${remote_releases_url}/${_get_updater_file()}`;
}
function _get_updater_checksum_url() {
return `${remote_releases_url}/${_get_updater_checksum_file()}`;
}
function _get_updater_checksum_file() {
const platform = process.platform;
const arch = process.arch;
assert(platform === 'win32' || platform === 'darwin' || platform === 'linux');
assert(arch === 'x64' || arch === 'arm64');
return `${platform}_${arch}_updates_checksum.txt`;
}
function _get_updater_file() {
const platform = process.platform;
const arch = process.arch;
assert(platform === 'win32' || platform === 'darwin' || platform === 'linux');
assert(arch === 'x64' || arch === 'arm64');
return `${platform}_${arch}_updates.tar.gz`;
}
/**
* Fetches the contents of a remote file using curl.
* @param {string} url - The URL of the file to fetch.
* @returns {Promise<string>} - Resolves with the file contents as a string.
*/
function curl_remote_textfile(url) {
return new Promise((resolve, reject) => {
const cmd = `curl -L "${url}"`;
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
reject(error);
return;
}
// test for SHA256
const regexExp = /^[a-f0-9]{64}$/gi;
if (!regexExp.test(stdout)) {
reject('Failed to retrieve valid SHA256 checksum.');
return;
}
console.log('Remote found: ' + stdout);
resolve(stdout);
});
});
}
async function get_remote_checksum() {
// update if different
console.log('Checking for updates...' + _get_updater_checksum_url());
return await curl_remote_textfile(_get_updater_checksum_url());
}
function verify_checksum(incoming) {
const checksum_file_path = path.join(path_destination_folder, _get_updater_checksum_file());
if (!fs.existsSync(path_destination_folder)) {
fs.mkdirSync(path_destination_folder);
return false;
}
// if local file doesn't exist create and return checksum fail
if (!fs.existsSync(checksum_file_path)) {
return false;
}
const local_checksum = fs.readFileSync(checksum_file_path, { encoding: 'ascii' });
return local_checksum === incoming;
}
async function run_update(new_checksum) {
// download bundle
let retries = 2;
const bundle_file = _get_updater_file();
console.log('Downloading update bundle ' + bundle_file);
while (retries > 0) {
const download_cmd = `curl -L "${_get_updater_url()}" -o ${bundle_file}`;
execSync(download_cmd, { cwd: path_destination_folder, stdio: 'inherit' });
// verify checksum
const download_checksum = await getSHA256Checksum(path.join(path_destination_folder, bundle_file));
if (new_checksum !== download_checksum) {
console.log(`Checksum failed expected ${new_checksum} got ${download_checksum}`);
fs.rmSync(path.join(path_destination_folder, bundle_file), { force: true });
retries--;
console.log(`Retrying download...${retries} retries`);
if (retries === 0) {
throw new Error(`Update bundle checksum failed too many times. Aborting.`);
}
} else {
console.log(`Downloaded ${path.join(path_destination_folder, bundle_file)}`);
break;
}
}
// copy to project base dir and unpack
fs.copyFileSync(path.join(path_destination_folder, bundle_file), path.join(omniCwd(), bundle_file));
console.log(`Extracting ${bundle_file}`);
const exclude_executable = process.platform === 'win32' ? 'omnitool.exe' : 'omnitool';
await extract({
file: bundle_file,
filter: (p) => {
const filepath = path.parse(p);
if (p === exclude_executable) {
return false;
} else {
void statuslogger(`Unpacking ${filepath.name}${filepath.ext}`);
return true;
}
}
});
// cleanup
fs.rmSync(path.join(path_destination_folder, bundle_file));
}
function seal_update(new_checksum) {
assert(new_checksum !== null);
const checksum_file_path = path.join(path_destination_folder, _get_updater_checksum_file());
fs.writeFileSync(checksum_file_path, new_checksum);
}
async function update_build() {
// skip updates if there's any remote failures
let need_update = false;
let remote_checksum = null;
try {
remote_checksum = await get_remote_checksum();
need_update = !verify_checksum(remote_checksum);
} catch (e) {
console.warn('Error fetching update checksum. Skipping updates.');
console.error(e);
// continue
need_update = false;
}
if (need_update) {
try {
console.log('New version found! Updating...');
await run_update(remote_checksum);
seal_update(remote_checksum);
console.log(`Build updated to ${remote_checksum}`);
return true;
} catch (e) {
console.log('Update failed, cleaning up...');
// always reset on any update error
fs.rmSync(path_destination_folder, { recursive: true, force: true });
throw e;
}
} else {
console.log('Current version is the latest available.');
return false;
}
}
module.exports = {
update_build
};