Skip to content

Commit

Permalink
feat: improved update process
Browse files Browse the repository at this point in the history
support more mirror-site config for update
  • Loading branch information
CKylinMC committed Jul 18, 2023
1 parent a6d7ace commit 1aef195
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 24 deletions.
33 changes: 27 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cmand",
"version": "0.7.5",
"version": "0.7.6",
"author": "CKylinMC",
"description": "A simple command-line tool for Windows managing your small scripts.",
"main": "build/main/index.js",
Expand Down Expand Up @@ -50,10 +50,12 @@
"homedir": "^0.6.0",
"i": "^0.3.7",
"inquirer": "^8.2.5",
"markdown-to-txt": "^2.0.1",
"md5-file": "^5.0.0",
"nestdb": "github:CKylinMC/nestdb",
"ping": "^0.4.2",
"pkg": "^5.8.0",
"semver": "^7.5.4",
"sudo-prompt": "^9.2.1",
"yaml": "^2.2.2"
},
Expand Down
67 changes: 53 additions & 14 deletions src/actions/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import { execute } from './run';
import got from 'got';
import { Spinner } from '../lib/Spinner';
import { CONSTS, Settings } from '../lib/Db';
import markdownToTxt from 'markdown-to-txt';

import semver from 'semver';
import { ProgressBar } from '../lib/ProgressBar';

export async function update(download = false) {
if (!('pkg' in process)) {
Expand All @@ -35,22 +39,42 @@ export async function update(download = false) {
latest = releases[0];
}
const latestVersion = latest.tag_name;
const isBeta = latest.prerelease;
const isBeta = latest.prerelease??false;
const url = latest.html_url;
const asset = latest.assets.find((asset) => asset.name === 'cmand.exe');
let exe = asset?.browser_download_url;
const replaceHost = await Settings.get('replace_update_dl_host', ''); // mirror site
const staticURL = await Settings.get('replace_update_dl_url', ''); // github action auto push
if (replaceHost&&exe) {
let exeurl = new URL(exe);
exeurl.host = replaceHost;
exe = exeurl.toString();
console.log(chalk.gray(`Using download host: ${replaceHost}`));
} else if (staticURL && exe) {
exe = staticURL;
}
const size = asset?.size;
if (latestVersion != 'v' + Info.version) {
spinner1.success(chalk.yellow(`New version ${latestVersion}${isBeta?" (Beta)":""} found.`),"");
if(semver.gt(latestVersion, Info.version)) {
// if ( latestVersion != 'v' + Info.version) {
spinner1.success(chalk.yellow(`New version ${latestVersion}${isBeta ? " (Beta)" : ""} found.`), "");
const fullUpdateLog = markdownToTxt(latest.body??'');
if (fullUpdateLog.split('\n').length <= 15) {
console.log("\n"+"=".repeat(24),"\n * Update note:\n");
console.log(fullUpdateLog);
console.log("\n"+"=".repeat(24),"\n")
}
console.log(chalk.yellow(`Check out more information at ${url}`));
if (!exe) return Promise.resolve(0);
if (!exe) {
console.log(chalk.gray('This version does not have a vaild update package. You may need to update manually.'));
return Promise.resolve(0);
}
console.log(chalk.gray(`Download size: ${Math.round(size/1024/10.24)/100+" MB"}`))
if (!download) {
const { download } = await inquirer.prompt([
{
type: 'confirm',
name: 'download',
message: 'Download now?',
message: 'Download and update now?',
default: true,
},
]);
Expand All @@ -61,13 +85,22 @@ export async function update(download = false) {
try {
exceptSync(() => fs.mkdirSync(temp));
const filepath = path.join(temp, "cmand.update.exe");

await new Promise((r, j) => {
exe = proxyedUrl(cfproxy, exe);
const stream = got.stream(exe);
const stream = got.stream(exe,{https: { rejectUnauthorized: false }});
let lastdata = 0;
let lastTime = Date.now();
let speed = 0;
const fixNum = num => {
const str = num.toString();
const dot = str.indexOf('.');
if (dot === -1) return str + '.00';
const decimal = str.substr(dot + 1);
if (decimal.length === 2) return str;
if (decimal.length === 1) return str + '0';
return str.substr(0, dot + 3);
}
stream.on("downloadProgress", ({ transferred, total, percent }) => {
const now = Date.now();
const diff = transferred - lastdata;
Expand All @@ -80,8 +113,9 @@ export async function update(download = false) {
const percentage = isNaN(total)?"?":Math.round(percent * 100);
const transferredMB = isNaN(total)?"?":Math.round(transferred / 1024 / 10.24) / 100;
const totalMB = isNaN(total) ? "?" : Math.round(total / 1024 / 10.24) / 100;
const speedTxt = speed!=0?(` - ${speedKB} KB/s`):'';
spinner2.text(`Downloading... ${transferredMB} MB / ${totalMB} MB (${percentage}%)${speedTxt}`);
const speedTxt = speed != 0 ? (` - ${speedKB} KB/s`) : '';

spinner2.text(`Downloading... ${ProgressBar.render({ max: total, value: transferred })} ${fixNum(transferredMB)} MB / ${totalMB} MB (${percentage}%)${speedTxt}`);
})
stream.on('error', j);
const writer = fs.createWriteStream(filepath);
Expand All @@ -99,8 +133,8 @@ export async function update(download = false) {
taskkill /f /im cmand.exe
move /y "${selfpath}" "${selfpath}.old"
move /y "${filepath}" "${selfpath}"
del /f /Q "${selfpath}.old"
del /f /Q "${temp}" && echo Done. && exit /b
echo Update complete. Cleaning up...
del /f /Q "${selfpath}.old" && del /f /Q "${temp}" && echo Done. && exit /b
`.split("\n").map(line=>line.trimStart()).join("\n"));
fs.writeFileSync(scriptBootPath, `
@cmd /c ${scriptPath.indexOf(" ")!=-1?`"${scriptPath}"`:`${scriptPath}`}
Expand All @@ -115,18 +149,23 @@ export async function update(download = false) {
enabled: true,
}, []);
} catch (e) {
spinner2.fail(chalk.red('Error while updating:')+e,'');
spinner2.fail(chalk.red('Error while updating: ')+e,'');
return Promise.resolve(0);
} finally {
console.log("Cleaning up...");
exceptSync(()=>fs.unlinkSync(temp));
exceptSync(()=>fs.unlinkSync(`${process.execPath}.old`));
}
return Promise.resolve(0);
} else if (semver.lt(latestVersion, Info.version)) {
spinner1.success(chalk.cyan("You are using a future version of 'cmand'."),"");
return Promise.resolve(0);
} else {
spinner1.success(chalk.green('cmand is up to date.'),"");
spinner1.success(chalk.green("You are using the latest version of 'cmand'."),"");
return Promise.resolve(0);
}
}
).catch(() => {
spinner1.fail(chalk.red('Errored while fetching release information'),"");
})
}
}
4 changes: 2 additions & 2 deletions src/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import homedir from 'homedir';

export const Info = {
name: 'cmand',
version: '0.7.5',
version: '0.7.6',
description: 'A command line tool for managing your script snippets on Windows.',
author: 'CKylinMC',
}
Expand All @@ -13,4 +13,4 @@ export let scripthome = () => path.join(home, 'scripts');
export const dbpath = () => path.join(home, 'data.db');
export const settingspath = () => path.join(home, 'settings.db');
export const setHome = (p) => home = p;
export const setScriptHome = (p) => scripthome = () => p;
export const setScriptHome = (p) => scripthome = () => p;
4 changes: 3 additions & 1 deletion src/lib/Db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ export class Settings{
await Settings.set('disable_banner', false, true);
await Settings.set('allow_remote_install', true, true);
await Settings.set('stable_only', false, true);
await Settings.set('replace_update_dl_host', '', true);
await Settings.set('static_update_dl_url', '', true);
}
}

export default Db;
export default Db;
84 changes: 84 additions & 0 deletions src/lib/ProgressBar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import chalk from "chalk";

export class ProgressBar{
static symbols = {
prefix: ' ',
postfix: ' ',
filled: chalk.cyan('━'),
empty: chalk.grey('━'),
full: chalk.green('━'),
error: chalk.red('━'),
errorEmpty: chalk.redBright('━'),
}
value: number;
max: number;
min: number;
width: number;
useSymbols: any;

static percentize(value, max, min) {
return (value - min) / (max - min);
}

static render({
max= 100,
min= 0,
value= 0,
width = 20,
isDone = false,
isError = false,
showText = false,
customText = "$percent% $min/$max",
symbols = ProgressBar.symbols
} = {}) {
symbols = Object.assign({}, ProgressBar.symbols, symbols);
if (isDone) {
return `${symbols.prefix}${symbols.full.repeat(width)}${symbols.postfix}`;
}
value = Math.min(value, max);
value = Math.max(value, min);
value = Math.round(value * 100) / 100;

const percent = ProgressBar.percentize(value, max, min);
const filledLen = Math.round(width * percent);
const emptyLen = width - filledLen;
const filled = symbols[isError?'error':'filled'].repeat(filledLen);
const empty = symbols[isError?'errorEmpty':'empty'].repeat(emptyLen);
const text = `${filled}${empty}`;
let extraText = "";
if (showText) {
extraText = customText.replace(/\$percent/g, ""+(percent * 100))
.replace(/\$value/g, ""+value)
.replace(/\$min/g, ""+min)
.replace(/\$max/g, ""+max);
}

return `${symbols.prefix}${text}${symbols.postfix}${extraText}`;
}

constructor({value=0, max=100, min=0, width=20, symbols=ProgressBar.symbols}={}) {
this.value = value;
this.max = max;
this.min = min;
this.width = width;
this.useSymbols = symbols;
}

get bar() {
return ProgressBar.render({
max: this.max,
min: this.min,
value: this.value,
width: this.width,
symbols: this.useSymbols
});
}

step(value = 1) {
this.value += value;
// this.value must be in [min, max]
this.value = Math.min(this.value, this.max);
this.value = Math.max(this.value, this.min);
return this;
}
}

0 comments on commit 1aef195

Please sign in to comment.