diff --git a/README.md b/README.md index 45fd611..25a0a1b 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ When running the command with no arguments, it will default to `dev info`. - [List](#list-4) - [Switch Environments](#switch-environments) - [Version](#version) + - [Update](#update-1) - [Cache](#cache) - [Clear](#clear) @@ -425,6 +426,17 @@ $ dev version minor Updated version to 2.1.0 ``` +### Update + +Updates the CLI with yarn. + +```sh + +$ dev update + +✔ Updated the CLI +``` + ### Cache #### Clear diff --git a/package.json b/package.json index b10d7bd..15d6b7e 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,26 @@ { "name": "@nix2/nix-cli", - "version": "1.1.0", + "version": "1.1.1", "description": "Command line interface for common tasks for Nix2 Infrastructure", "main": "./dist/index.js", "repository": "git@github.com:nix2io/cli.git", "author": "Max Koon ", "license": "CC-BY-1.0", "dependencies": { + "@nix2/nix-cli": "^1.1.0", "@nix2/service-core": "1.0.10", + "@types/semver": "^7.3.4", "axios": "^0.21.0", "cli-table": "^0.3.1", "commander": "^6.1.0", "faunadb": "^3.0.1", "friendly-time": "^1.1.1", + "global": "^4.4.0", "inquirer": "^7.3.3", "js-yaml": "^3.14.0", "ora": "^5.1.0", "pluralize": "^8.0.0", + "semver": "^7.3.2", "spinnies": "^0.5.1", "ts-morph": "^8.1.2" }, diff --git a/src/cache.ts b/src/cache.ts index cf9b637..1abee77 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -6,6 +6,7 @@ * Author: Max Koon (maxk@nix2.io) */ +import { Any } from '@nix2/service-core'; import { CACHE_PATH } from './constants'; import fs = require('fs'); import path = require('path'); @@ -54,10 +55,11 @@ class Cache { * // get the contents of the authors cache * cache.makePath('authors') // {authors: [...]} * @param {name} name Name of the cached file. + * @param {any} def Default value if none is returned. * @returns {Record} The returned object. */ - get(name: string): Record { - if (!this.exists(name)) return {}; + get(name: string, def: any = {}): Record { + if (!this.exists(name)) return def; try { return JSON.parse(fs.readFileSync(this.makePath(name), 'utf-8')); } catch (err) { diff --git a/src/cmds/index.ts b/src/cmds/index.ts index 2456a5d..a5d7b8b 100644 --- a/src/cmds/index.ts +++ b/src/cmds/index.ts @@ -17,3 +17,4 @@ export { default as plugins } from './plugins'; export { default as version } from './version'; export { default as env } from './env'; export { default as cache } from './cache'; +export { default as update } from './update'; diff --git a/src/cmds/plugins.ts b/src/cmds/plugins.ts index 9025e1b..5148583 100644 --- a/src/cmds/plugins.ts +++ b/src/cmds/plugins.ts @@ -10,15 +10,13 @@ import * as colors from 'colors'; import * as ora from 'ora'; import { NPR_URL, PLUGIN_PATH } from '../constants'; -import { deleteDirectoryRecursive, list } from '../util'; +import { asyncExec, deleteDirectoryRecursive, list } from '../util'; import Axios from 'axios'; import { CommanderStatic } from 'commander'; import { PluginNotFoundError } from '@nix2/service-core'; -import { exec } from 'child_process'; import { existsSync } from 'fs'; import { join } from 'path'; -import { promisify } from 'util'; import { serviceCore } from '../service'; // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -31,8 +29,6 @@ interface RemotePlugin { version: string; } -const asyncExec = promisify(exec); - const listPlugins = () => { if (serviceCore.plugins.length == 0) return console.log(colors.grey('No plugins installed')); diff --git a/src/cmds/update.ts b/src/cmds/update.ts new file mode 100644 index 0000000..e45910c --- /dev/null +++ b/src/cmds/update.ts @@ -0,0 +1,26 @@ +/* + * File: version.ts + * Created: 10/11/2020 13:03:39 + * ---- + * Copyright: 2020 Nix² Technologies + * Author: Max Koon (maxk@nix2.io) + */ + +import * as ora from 'ora'; + +import { CommanderStatic } from 'commander'; +import { PACKAGE_NAME } from '../constants'; +import { asyncExec } from '../util'; + +export default (program: CommanderStatic): void => { + program + .command('update') + .description('update the cli') + .action(async () => { + const spinner = ora('Updating CLI').start(); + await asyncExec(`yarn add global ${PACKAGE_NAME}`).catch((err) => { + spinner.fail(err.message); + }); + spinner.succeed('Updated the CLI'); + }); +}; diff --git a/src/constants.ts b/src/constants.ts index 0049d95..5435d9f 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,12 +6,14 @@ * Author: Max Koon (maxk@nix2.io) */ // eslint-disable-next-line @typescript-eslint/no-var-requires -const { version } = require('../package.json'); +const { version, name } = require('../package.json'); import * as colors from 'colors'; import * as path from 'path'; // package version export const VERSION = version; +// package name +export const PACKAGE_NAME = name; // file name for the service structure export const SERVICE_FILE_NAME = 'service.yaml'; @@ -52,6 +54,11 @@ export const NONE = colors.grey('none'); export const NPR_URL = 'https://raw.githubusercontent.com/nix2io/npr/main/npr'; +export const PACKAGE_URL = + 'https://raw.githubusercontent.com/nix2io/cli/master/package.json'; + +export const REFRESH_VERSION_INTERVAL = 1000 * 60 * 60 * 24; // Refresh 24 hours + // info template export const SERVICE_DISPLAY_TEMPLATE = ` ${SYMBOLS.PAPER} Local data ${colors.grey(`from ${SERVICE_FILE_NAME}`)} diff --git a/src/initalize.ts b/src/initalize.ts index ee579c8..e005884 100644 --- a/src/initalize.ts +++ b/src/initalize.ts @@ -6,6 +6,10 @@ * Author: Max Koon (maxk@nix2.io) */ +import * as colors from 'colors'; +// const path = require('path'); +import * as fs from 'fs'; + import { CACHE_PATH, CLI_PATH, @@ -13,9 +17,8 @@ import { ERRORS, PLUGIN_PATH, } from './constants'; -import colors = require('colors'); -// const path = require('path'); -import fs = require('fs'); + +import { checkForUpdates } from './updateChecker'; const createDir = () => { try { @@ -50,6 +53,7 @@ const createPluginDir = () => { }; const initalize = () => { + checkForUpdates(); // if the main dir does not exist, also create the cache and config if (!fs.existsSync(CLI_PATH)) { createDir(); diff --git a/src/updateChecker.ts b/src/updateChecker.ts new file mode 100644 index 0000000..685c616 --- /dev/null +++ b/src/updateChecker.ts @@ -0,0 +1,52 @@ +import * as semver from 'semver'; +import * as colors from 'colors'; + +import { + PACKAGE_URL, + REFRESH_VERSION_INTERVAL, + SYMBOLS, + VERSION, +} from './constants'; + +import Axios from 'axios'; +import cache from './cache'; + +interface VersionCacheType { + refreshed: number; + version: string; +} + +const updateCachedVersion = async (): Promise => { + console.log('checking for updates'); + await Axios.get(PACKAGE_URL).then((resp) => { + const version = resp.data.version; + cache.set('version', { refreshed: new Date().getTime(), version }); + }); + return; +}; + +export const checkForUpdates = (): void => { + const versionCacheInfo: VersionCacheType = ( + (cache.get('version', { refreshed: -1, version: VERSION })) + ); + if ( + new Date().getTime() - versionCacheInfo.refreshed >= + REFRESH_VERSION_INTERVAL + ) + updateCachedVersion(); + + if (semver.lte(versionCacheInfo.version, VERSION)) return; + console.warn( + colors.yellow( + `\n${ + SYMBOLS.WARNING + } You are using an out of date CLI: ${colors.cyan( + VERSION, + )} ${colors.white('→')} ${colors.cyan( + versionCacheInfo.version, + )}\n https://github.com/nix2io/cli/releases/tag/v${ + versionCacheInfo.version + }\n`, + ), + ); +}; diff --git a/src/util.ts b/src/util.ts index 09bba89..515274d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -5,6 +5,8 @@ import * as colors from 'colors'; import { Obj, Any } from '@nix2/service-core'; import { SERVICE_FILE_NAME } from './constants'; +import { promisify } from 'util'; +import { exec } from 'child_process'; export const getRootOptions = (options: Obj): Obj => { while ( @@ -115,3 +117,5 @@ export const deleteDirectoryRecursive = (dirPath: string): void => { fs.rmdirSync(dirPath); } }; + +export const asyncExec = promisify(exec); diff --git a/yarn.lock b/yarn.lock index be644b1..366d444 100644 --- a/yarn.lock +++ b/yarn.lock @@ -47,6 +47,24 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@nix2/nix-cli@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@nix2/nix-cli/-/nix-cli-1.1.0.tgz#ad3e9dd2cd5a586446185c0afa3cf3699b0d0b5f" + integrity sha512-5GRq7ypuwby7JYRJ3NnhbRJchEeHiT8MR6n9lxX60Cv/eVDCALsMy+rvHDrvpfaZixW1ESUsAjaFrnNfuLzHZA== + dependencies: + "@nix2/service-core" "1.0.10" + axios "^0.21.0" + cli-table "^0.3.1" + commander "^6.1.0" + faunadb "^3.0.1" + friendly-time "^1.1.1" + inquirer "^7.3.3" + js-yaml "^3.14.0" + ora "^5.1.0" + pluralize "^8.0.0" + spinnies "^0.5.1" + ts-morph "^8.1.2" + "@nix2/service-core@1.0.10": version "1.0.10" resolved "https://registry.yarnpkg.com/@nix2/service-core/-/service-core-1.0.10.tgz#8658d630d2a3ce1652c4ace8b7ea63809975a2cb" @@ -147,6 +165,11 @@ resolved "https://registry.yarnpkg.com/@types/pluralize/-/pluralize-0.0.29.tgz#6ffa33ed1fc8813c469b859681d09707eb40d03c" integrity sha512-BYOID+l2Aco2nBik+iYS4SZX0Lf20KPILP5RGmM1IgzdwNdTs0eebiFriOPcej1sX9mLnSoiNte5zcFxssgpGA== +"@types/semver@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" + integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== + "@types/through@*": version "0.0.30" resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" @@ -595,6 +618,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + dotenv@^8.2.0: version "8.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" @@ -944,6 +972,14 @@ glob@7.1.6, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +global@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + globals@^12.1.0: version "12.4.0" resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" @@ -1226,6 +1262,13 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -1457,6 +1500,11 @@ prettier@2.1.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5" integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"