Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@oclif/plugin-update

Package Overview
Dependencies
Maintainers
2
Versions
204
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@oclif/plugin-update - npm Package Compare versions

Comparing version 1.1.0 to 1.1.1

lib/tar.d.ts

11

CHANGELOG.md

@@ -0,1 +1,12 @@

<a name="1.1.1"></a>
## [1.1.1](https://github.com/oclif/plugin-update/compare/v1.1.0...v1.1.1) (2018-04-09)
### Bug Fixes
* add targets ([68f6fa8](https://github.com/oclif/plugin-update/commit/68f6fa8))
* npm pack on circle ([9ca2c9c](https://github.com/oclif/plugin-update/commit/9ca2c9c))
* updater fixes ([c65c556](https://github.com/oclif/plugin-update/commit/c65c556))
* updater seems to be working ([9b3e33b](https://github.com/oclif/plugin-update/commit/9b3e33b))
<a name="1.1.0"></a>

@@ -2,0 +13,0 @@ # [1.1.0](https://github.com/oclif/plugin-update/compare/v1.0.5...v1.1.0) (2018-04-07)

17

lib/commands/update.d.ts
import Command from '@oclif/command';
import { Updater } from '..';
export default class UpdateCommand extends Command {

@@ -23,8 +22,18 @@ static description: string;

};
updater: Updater;
autoupdate: boolean;
private autoupdate;
private channel;
private readonly clientRoot;
private readonly clientBin;
private readonly s3Host;
run(): Promise<void>;
logChop(): Promise<void>;
private s3url(p);
private fetchManifest();
private update(manifest);
private needsUpdate();
private logChop();
private mtime(f);
private debounce();
private tidy();
private reexec();
private createBin(version);
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const color_1 = require("@heroku-cli/color");
const command_1 = require("@oclif/command");
const cli_ux_1 = require("cli-ux");
const dateAddHours = require("date-fns/add_hours");
const dateIsAfter = require("date-fns/is_after");
const spawn = require("cross-spawn");
const fs = require("fs-extra");
const path = require("path");
const __1 = require("..");
const tar_1 = require("../tar");
const util_1 = require("../util");

@@ -14,3 +14,5 @@ class UpdateCommand extends command_1.default {

super(...arguments);
this.updater = __1.fetchUpdater(this.config);
this.clientRoot = path.join(this.config.dataDir, 'client');
this.clientBin = path.join(this.clientRoot, 'bin', this.config.windows ? `${this.config.bin}.cmd` : this.config.bin);
this.s3Host = this.config.pjson.oclif.update.s3.host;
}

@@ -20,13 +22,9 @@ async run() {

this.autoupdate = !!flags.autoupdate;
if (this.autoupdate) {
if (this.autoupdate)
await this.debounce();
}
else {
// on manual run, also log to file
cli_ux_1.default.config.errlog = path.join(this.config.cacheDir, 'autoupdate');
}
cli_ux_1.default.action.start(`${this.config.name}: Updating CLI`);
let channel = args.channel || this.updater.channel;
if (!await this.updater.needsUpdate(channel)) {
if (!process.env.OCLIF_HIDE_UPDATED_MESSAGE) {
this.channel = args.channel || this.config.channel || 'stable';
const manifest = await this.fetchManifest();
if (!await this.needsUpdate()) {
if (!this.config.scopedEnvVar('HIDE_UPDATED_MESSAGE')) {
cli_ux_1.default.action.stop(`already on latest version: ${this.config.version}`);

@@ -36,14 +34,65 @@ }

else {
await this.updater.update({ channel });
await this.update(manifest);
}
this.debug('log chop');
await this.logChop();
this.debug('tidy');
await this.updater.tidy();
await this.config.runHook('update', { channel });
await this.tidy();
await this.config.runHook('update', { channel: this.channel });
this.debug('done');
cli_ux_1.default.action.stop();
}
s3url(p) {
if (!this.s3Host)
throw new Error('S3 host not defined');
// TODO: handle s3Prefix
return `${this.s3Host}/${this.config.name}/channels/${this.channel}/${p}`;
}
async fetchManifest() {
const http = require('http-call').HTTP;
try {
let { body } = await http.get(this.s3url(`${this.config.platform}-${this.config.arch}`));
return body;
}
catch (err) {
if (err.statusCode === 403)
throw new Error(`HTTP 403: Invalid channel ${this.channel}`);
throw err;
}
}
async update(manifest) {
const { version, channel } = manifest;
cli_ux_1.default.action.start(`${this.config.name}: Updating CLI from ${color_1.default.green(this.config.version)} to ${color_1.default.green(version)}${channel === 'stable' ? '' : ' (' + color_1.default.yellow(channel) + ')'}`);
const _ = require('lodash');
const http = require('http-call').HTTP;
const filesize = require('filesize');
const output = path.join(this.clientRoot, version);
const { response: stream } = await http.stream(manifest.gz);
let extraction = tar_1.extract(stream, this.config.bin, output, manifest.sha256gz);
// TODO: use cli.action.type
if (cli_ux_1.default.action.frames) {
// if spinner action
let total = stream.headers['content-length'];
let current = 0;
const updateStatus = _.throttle((newStatus) => {
cli_ux_1.default.action.status = newStatus;
}, 500, { leading: true, trailing: false });
stream.on('data', data => {
current += data.length;
updateStatus(`${filesize(current)}/${filesize(total)}`);
});
}
await extraction;
await this.createBin(version);
await this.reexec();
}
async needsUpdate() {
if (this.autoupdate && this.config.scopedEnvVar('DISABLE_AUTOUPDATE') === '1')
return;
if (this.channel !== this.config.channel)
return true;
let manifest = await this.fetchManifest();
return this.config.version !== manifest.version;
}
async logChop() {
try {
this.debug('log chop');
const logChopper = require('log-chopper').default;

@@ -60,8 +109,9 @@ await logChopper.chop(this.config.errlog);

}
// when autoupdating, wait until the CLI isn't active
async debounce() {
const lastrunfile = path.join(this.config.cacheDir, 'lastrun');
const m = await this.mtime(lastrunfile);
const waitUntil = dateAddHours(m, 1);
if (dateIsAfter(waitUntil, new Date())) {
await cli_ux_1.default.log(`waiting until ${waitUntil.toISOString()} to update`);
m.setHours(m.getHours() + 1);
if (m < new Date()) {
await cli_ux_1.default.log(`waiting until ${m.toISOString()} to update`);
await util_1.wait(60 * 1000); // wait 1 minute

@@ -72,3 +122,81 @@ return this.debounce();

}
// removes any unused CLIs
async tidy() {
try {
if (!this.config.binPath)
return;
if (!this.config.binPath.includes(this.config.version))
return;
let root = this.clientRoot;
if (!await fs.pathExists(root))
return;
let files = await util_1.ls(root);
let promises = files.map(async (f) => {
if (['bin', this.config.version].includes(path.basename(f.path)))
return;
const mtime = f.stat.mtime;
mtime.setHours(mtime.getHours() + 7 * 24);
if (mtime < new Date()) {
await fs.remove(f.path);
}
});
for (let p of promises)
await p;
await this.logChop();
}
catch (err) {
cli_ux_1.default.warn(err);
}
}
async reexec() {
cli_ux_1.default.action.stop();
return new Promise((_, reject) => {
this.debug('restarting CLI after update', this.clientBin);
spawn(this.clientBin, ['update'], {
stdio: 'inherit',
env: Object.assign({}, process.env, { [this.config.scopedEnvVarKey('HIDE_UPDATED_MESSAGE')]: '1' }),
})
.on('error', reject)
.on('close', (status) => {
try {
this.exit(status);
}
catch (err) {
reject(err);
}
});
});
}
async createBin(version) {
let dst = this.clientBin;
if (this.config.windows) {
let body = `@echo off
"%~dp0\\..\\${version}\\bin\\${this.config.bin}.cmd" %*
`;
await fs.outputFile(dst, body);
}
else {
let body = `#!/usr/bin/env bash
set -e
get_script_dir () {
SOURCE="\${BASH_SOURCE[0]}"
# While $SOURCE is a symlink, resolve it
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$( readlink "$SOURCE" )"
# If $SOURCE was a relative symlink (so no "/" as prefix, need to resolve it relative to the symlink base directory
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo "$DIR"
}
DIR=$(get_script_dir)
HEROKU_CLI_REDIRECTED=1 "$DIR/../${version}/bin/${this.config.bin}" "$@"
`;
await fs.remove(dst);
await fs.outputFile(dst, body);
await fs.chmod(dst, 0o755);
}
}
}
UpdateCommand.description = 'update the <%= config.bin %> CLI';

@@ -75,0 +203,0 @@ UpdateCommand.args = [{ name: 'channel', optional: true }];

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const http_call_1 = require("http-call");
const _1 = require(".");
class GithubUpdater extends _1.Updater {
async update() {
const release = await this.fetchRelease();
const version = release.tag_name.split('v')[1];
const base = this.base(version);
const asset = release.assets.find((a) => a.name === `${base}.tar.gz`);
if (!asset)
throw new Error('release not found');
return super.update({ url: asset.browser_download_url, version });
}
async needsUpdate() {
const version = (await this.fetchRelease()).tag_name.split('v')[1];
return this.config.version !== version;
}
async fetchRelease() {
const [owner, repo] = this.config.pjson.repository.split('/');
const { body } = await http_call_1.default.get(`https://api.github.com/repos/${owner}/${repo}/releases/latest`);
return this.release = body;
}
}
exports.GithubUpdater = GithubUpdater;
// import HTTP from 'http-call'
// import {Updater} from '.'
// export class GithubUpdater extends Updater {
// release?: {tag_name: string}
// async update() {
// const release = await this.fetchRelease()
// const version = release.tag_name.split('v')[1]
// const base = this.base(version)
// const asset = release.assets.find((a: any) => a.name === `${base}.tar.gz`)
// if (!asset) throw new Error('release not found')
// return super.update({url: asset.browser_download_url, version})
// }
// async needsUpdate() {
// const version = (await this.fetchRelease()).tag_name.split('v')[1]
// return this.config.version !== version
// }
// private async fetchRelease() {
// const [owner, repo] = this.config.pjson.repository.split('/')
// const {body} = await HTTP.get(`https://api.github.com/repos/${owner}/${repo}/releases/latest`)
// return this.release = body
// }
// }

@@ -5,4 +5,2 @@ "use strict";

const spawn = require("cross-spawn");
const dateIsAfter = require("date-fns/is_after");
const dateSubHours = require("date-fns/sub_hours");
const fs = require("fs-extra");

@@ -23,3 +21,5 @@ const path = require("path");

cli_ux_1.default.config.errlog = opts.config.errlog;
const binPath = this.config.scopedEnvVar('CLI_BINPATH') || this.config.bin;
const binPath = this.config.binPath;
if (!binPath)
return this.debug('no binpath set');
const lastrunfile = path.join(this.config.cacheDir, 'lastrun');

@@ -33,3 +33,4 @@ const autoupdatefile = path.join(this.config.cacheDir, 'autoupdate');

const m = await mtime(autoupdatefile);
return dateIsAfter(m, dateSubHours(new Date(), 5));
m.setHours(m.getHours() + 5);
return m < new Date();
}

@@ -47,5 +48,4 @@ catch (err) {

const clientDir = path.join(clientRoot, this.config.version);
if (await fs.pathExists(clientDir)) {
if (await fs.pathExists(clientDir))
await util_1.touch(clientDir);
}
if (!await autoupdateNeeded())

@@ -52,0 +52,0 @@ return;

{
"name": "@oclif/plugin-update",
"version": "1.1.0",
"version": "1.1.1",
"author": "Jeff Dickey @jdxcode",

@@ -8,9 +8,8 @@ "bugs": "https://github.com/oclif/plugin-update/issues",

"@heroku-cli/color": "^1.1.3",
"@oclif/command": "^1.4.7",
"@oclif/config": "^1.3.67",
"@oclif/errors": "^1.0.3",
"@oclif/command": "^1.4.10",
"@oclif/config": "^1.4.7",
"@oclif/errors": "^1.0.4",
"@types/semver": "^5.5.0",
"cli-ux": "^3.3.27",
"cli-ux": "^3.3.28",
"cross-spawn": "^6.0.5",
"date-fns": "^1.29.0",
"debug": "^3.1.0",

@@ -26,3 +25,3 @@ "filesize": "^3.6.1",

"devDependencies": {
"@oclif/dev-cli": "^1.7.3",
"@oclif/dev-cli": "^1.9.11",
"@oclif/plugin-help": "^1.2.3",

@@ -33,3 +32,5 @@ "@oclif/test": "^1.0.4",

"@types/cross-spawn": "^6.0.0",
"@types/execa": "^0.9.0",
"@types/fs-extra": "^5.0.1",
"@types/glob": "^5.0.35",
"@types/lodash": "^4.14.106",

@@ -39,5 +40,7 @@ "@types/mocha": "^5.0.0",

"@types/supports-color": "^3.1.0",
"@types/write-json-file": "^2.2.1",
"chai": "^4.1.2",
"globby": "^8.0.1",
"mocha": "^5.0.5",
"qqjs": "^0.3.6",
"ts-node": "5",

@@ -73,9 +76,5 @@ "tslib": "^1.9.0",

"scripts": {
"build": "rm -rf lib && tsc",
"clean": "rm -f .oclif.manifest.json",
"lint": "tsc -p test --noEmit && tslint -p test -t stylish",
"postpublish": "yarn run clean",
"postpack": "rm -f .oclif.manifest.json",
"posttest": "tsc -p test --noEmit && tslint -p test -t stylish",
"prepublishOnly": "yarn run build && oclif-dev manifest && oclif-dev readme",
"preversion": "yarn run clean",
"prepack": "rm -rf lib && tsc && oclif-dev manifest && oclif-dev readme",
"test": "mocha --forbid-only \"test/**/*.test.ts\"",

@@ -82,0 +81,0 @@ "version": "oclif-dev readme && git add README.md"

@@ -24,3 +24,3 @@ @oclif/plugin-update

$ oclif-example (-v|--version|version)
@oclif/plugin-update/1.1.0 linux-x64 node-v9.11.1
@oclif/plugin-update/1.1.1 linux-x64 node-v9.11.1
$ oclif-example --help [COMMAND]

@@ -45,3 +45,3 @@ USAGE

_See code: [src/commands/update.ts](https://github.com/oclif/plugin-update/blob/v1.1.0/src/commands/update.ts)_
_See code: [src/commands/update.ts](https://github.com/oclif/plugin-update/blob/v1.1.1/src/commands/update.ts)_
<!-- commandsstop -->
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc