Node. js checks for updates using the command line tool, and node. js command line

Source: Internet
Author: User

Node. js checks for updates using the command line tool, and node. js command line

With the popularity of Node. js, it becomes easier to develop command line tools using Node. js. A mature command line tool should give users an "elegant" idea of how to update later versions from the very beginning. The best way is to prompt the user with relevant information when the user executes commands on the terminal.

This article provides an easy-to-use, efficient, and customizable method. The source code is here: GITHUB. You are welcome to like it. Next, I will explain how it works.

Use

Let's take a brief look at the usage of this npm package:

Const updater = require ('pkg-updater '); const pkg = require ('. /package. json'); // The package information of the command line tool ({'pkg ': pkg }). then () = >{/ * Start the command line tool here */}); updater ({'pkg ': pkg, // custom registry 'registry ': 'http: // xxx.registry.com ', // The dist-tag of the custom request. The default value is latest 'tag': 'Next'. // The custom check interval, the default value is 1 h 'checkinterval': 24*60*60*1000. // The Custom update prompt message 'updatemessage ': 'package update from <% = current %> to <% = latest %>. ', // The version update level of the custom forced update. The default value is major 'level': 'minor '}). then () => {/* Start the command line tool */}); updater ({'pkg ': pkg, // The logic 'onversionchange' for fully custom version update: function * (opts ){}}). then () => {/* Start the command line tool here */});

Effect

Implementation

The usage method is very simple. Let's take a look at its implementation method.

Requirement

Let's sort out the requirements first. A command line check Updater should provide at least the following functions:

The latest version can be obtained remotely.

Prompt Based on check results

You can exit directly when the version is incompatible and force the user to upgrade the program.

Get version

To get the latest version, you can send a request to obtain information from "somewhere. However, we need to consider the following issues:

Where can I obtain the version information?

What is the policy for obtaining version information? (When to obtain it? How to handle the obtained information ?)

Where can I obtain the version information?

Generally, our command line tools use npm for distribution. The easiest way is to directly obtain them through registry. Requesthttps://registry.npmjs.org/{name}/{dist-tag}You can get the version information of the tag corresponding to the package. The result is similar to the following:

// https://registry.npmjs.org/co/latest{ "name": "co", "version": "4.5.0"}

In actual implementation, we should allow callers to customize the registry address and the requested dist-tag so that more customization can be made.

Policy for obtaining version information

The first method is to obtain the version information every time you execute the command. Such a retrieval policy should be the simplest and real-time.

However, this policy is not suitable:

Each time you run a command, you must send a request for check. If the network delay occurs, the command execution will be blocked, affecting the user experience.

In fact, tool version updates are not frequent and there is no need to perform real-time checks.

There are many factors that affect network requests, and they cannot be guaranteed to succeed each time. Therefore, a local cache mechanism should be provided to store the results of successful requests to avoid version information unavailability.

Based on the above points, we design the following acquisition policies:

Put the logic for sending network requests to get version information in an independent background process for execution, to ensure that the main command execution is not blocked

After the request is successful, the version information and check time are cached on the user's machine.

Each time a command is executed, only the version information cached locally is read, and no network request is sent.

Based on the cache check time and current time, no background check process is created at one interval.

Translating the above policy into code is probably as follows:

// Read the local cache check result const checkInfo = yield updater. readCheckInfo (opts); const lastCheck = checkInfo. lastCheck; const lastVersion = checkInfo. lastVersion; // the user is prompted based on the version information //... // return if (Date. now ()-lastCheck <opts. checkInterval) {return;} // create a background check process try {require ('child _ Process '). spawn (process.exe cPath, [require ('path '). join (_ dirname, '_ check. js'), JSON. stringify ({'pkg ': opts. pkg, // package information 'tag': opts. tag, // check the dist-tag 'logfile': opts. logFile, // cache file path 'registry ': opts. registry // registry address})], {'stdio ': ['ignore', 'ignore', 'ignore'], 'detached': true }). unref ();} catch (e ){}

Background Process Execution_check.jsThe file is also very simple, as shown below:

Const opts = JSON. parse (process. argv [2]); let lastVersion = ''; try {// send a request to obtain the latest const url = normalizeUrl (opts. registry + '/' + opts. pkg. name + '/' + (opts. tag | 'latest '); const res = yield got. get (url, {'json': true, 'timeout': 60*1000}); if (res & res. body & res. body. version) {lastVersion = res. body. version ;}} catch (e) {}// if the retrieval fails, the latest version is the current version (package. version) if (! LastVersion) {lastVersion = opts. pkg. version;} let data = yield util. readJson (opts. logFile); if (! Data [opts. pkg. name]) {data [opts. pkg. name] ={};} data [opts. pkg. name]. lastVersion = lastVersion; // the latest data [opts. pkg. name]. lastCheck = Date. now (); // check the time // write to the cache yield util. writeJson (opts. logFile, data );

Prompt

When the version is updated, we should prompt the user on the terminal. There are two problems:

Prompt text Problems

Prompt text display interval (always show? Display at intervals ?)

Here we adopt the following strategy:

Provides the default prompt text, which clearly describes the current version, the latest version, and the update method, and allows the caller to customize the prompt text.

As long as there is an update, the prompt text is always displayed, because we want the user to update it frequently.

The implementation code is as follows:

// Compare the version const type = updater. diffType (opts. pkg. version, lastVersion, opts. level); if (type) {// according to the template rendering prompt information const str = updater. template (opts. updateMessage | updater. defaultOpts. updateMessage) ({'colors ': updater. colors, 'name': opts. pkg. name, 'current': opts. pkg. version, 'latest ': opts. lastVersion, 'command': 'npm I-G' + opts. pkg. name}); // prompts console. log (updater. boxen (str, {'padding': 1, 'margin ': 1, 'borderstyle': 'classic '}));}

Force update

For the npm module, update of Version a. B. c generally involves three situations:

Patch: c-bit, minor version update, usually bug fixing

Minor: B-bit. It is a medium version update. New Features and bug fixes are generally added.

Major, a-bit, major version update, usually incompatible upgrade

We hope that when the remote version is updated in the form of major, the command line tool will exit and force the user to upgrade before using it. This ensures that after a major version is pushed, all users can immediately update it, instead of continuing to use the old version, resulting in version fragmentation issues.

The implementation code is roughly as follows:

// Compare the version const type = updater. diffType (opts. pkg. version, lastVersion, opts. level); if (type) {// according to the template rendering prompt information const str = updater. template (opts. updateMessage | updater. defaultOpts. updateMessage) ({'colors ': updater. colors, 'name': opts. pkg. name, 'current': opts. pkg. version, 'latest ': opts. lastVersion, 'command': 'npm I-G' + opts. pkg. name}); // prompts console. log (updater. boxen (str, {'padding': 1, 'margin ': 1, 'borderstyle': 'classic'}); // incompatible update, directly let the process exit if (type = 'compatible ') {process. exit (1 );}}

Summary

The command line check for updates seems simple. In fact, there are still many details for careful consideration. I hope this article will inspire you.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.