Recently, I have been busy with my work, and I have less and less time to learn knowledge every day. I feel that this is not conducive to my technical improvement. Just remember what Uncle Wolf said “the best way to learn Node.js when confused is to read 10 NPM modules every day”. Although there is not enough time to read 10 modules every day, time is like a sponge. Squeeze it and read one module every day.

I hope that through this series of articles, on the one hand, I can remind myself to keep in mind the original intention of technology in my work, and on the other hand, I can urge myself to keep moving forward on the road of Node.js.

A one-sentence introduction

The first NPM module I choose is username, which is used to get the username of the current user. The current version is 3.0.0, and the weekly downloads are over 60,000.

usage

Username supports synchronous and Promise asynchronously:

const username = require('username');
 
/ / synchronize
console.log(username.sync()); // => 'elvin'

/ / asynchronous
username().then(username= > {
    console.log(username); // => 'elvin'
});
Copy the code

The source code to learn

There are more than 20 lines of core code, and the main logic is:

  1. First of all byprocess.envThe value in the variable retrieves the user name, or returns it if it exists.
  2. And then if there isos.userinfoFunction, passesos.userinfo().usernameGet the username and return it;
  3. If the preceding methods fail, run the command in OS X or Linuxid -unCommand to pass in WindowswhoamiCommand to get the user name and return.

The next three steps will be explored in combination with the source code.

process.env

// Source code 1-1
function getEnvVar() {
  const env = process.env;

  return env.SUDO_USER ||
    env.C9_USER /* Cloud9 */ ||
    env.LOGNAME ||
    env.USER ||
    env.LNAME ||
    env.USERNAME;
}

const envVar = getEnvVar();

if (envVar) {
  return Promise.resolve(envVar);
}
Copy the code

Process. env returns an object containing the user’s current environment variables. You can run the printenv command to view all environment variables, or you can run the printenv v_name command to obtain the value of an environment variable:

$ printenv
// => LANG=zh_CN.UTF-8
// => PWD=/Users/elvin/
// => SHELL=/bin/zsh
// => USER=elvin
// => ...

$ printenv USER
// => elvin
Copy the code

It is easy to confuse Shell variables with environment variables. You can view all Shell variables through the set command. How To Read and Set Environmental and Shell Variables on a Linux VPS.

There are three more things to know about process.env in Node.js:

  1. Environment variables can be set to process.env.foo = “bar”. Currently, all values are allowed and will be converted to string. In future releases, only String, number and Boolean values will be allowed, according to official documentation. Setting a value of any other type throws an exception.

    process.env.foo = undefined;
    console.log(process.env.foo, typeof process.env.foo);
    // => 'undefined', 'string'
    
    process.env.foo = {};
    console.log(process.env.foo, typeof process.env.foo);
    // => '[object Object]', 'string'
    Copy the code
  2. Environment variables can be deleted using the delete method.

    process.env.foo = undefined;
    delete process.env.foo
    console.log(process.env.foo)
    // => undefined
    Copy the code
  3. Changes to process.env in Node.js are not reflected outside of the Node process, but environment variables can be set externally and retrieved from node.js code. In practice, the NODE_ENV variable can be set this way. Its value is then read in the WebPack configuration code to determine the environment for different builds.

    $ node -e 'process.env.foo = "bar"' && echo $foo/ / = > empty
    $ NODE_ENV=production node -e 'console.log(process.env.NODE_ENV)'
    // => 'production'
    Copy the code

    In Windows, the direct NODE_ENV=production mode is not supported. You need to install the cross-env package for compatibility.

Going back to the getEnvVar function in source code 1-1, you can see that we try to get the USER name from the environment variables SUDO_USER, C9_USER, LOGNAME, USER, LNAME, and USERNAME in sequence from process.env, Here are the SUDO_USER and C9_USER variables:

  1. When the USER is root, the USER variable returns root, and the SUDO_USER variable returns the name of the account logged in as root, for example: When I change to root using sudo su as elvin, USER returns root and SUDO_USER returns elvin.

    $ sudo su
    // => input password
    
    $ printenv USER
    // => root
    
    $ printenv SUDO_USER
    // => elvin
    Copy the code
  2. C9_USER is an adaptation of Cloud9, amazon’s cloud IDE for writing, running, and debugging code

os.userInfo

If the user name cannot be obtained from process.env in the source code, the os.userinfo () function is tried:

// Source code 1-2
if (os.userInfo) {
    return Promise.resolve(os.userInfo().username);
}
Copy the code

Os.userinfo () returns some information about the current user, much less than process.env, and supported only by Node.js V6.0 and later:

const os = require('os');

console.log(os.userInfo());

/ / = > {
// => uid: 501,
// => gid: 20,
// => username: 'elvin',
// => homedir: '/Users/elvin',
// => shell: '/bin/zsh'
/ / = >}
Copy the code

The above fields mean:

  • Uid: indicates the user ID. Each user is identified by a unique ID in the system. For example, ID 501 indicates the user elvin. On Linux, UID information is stored in/etc/passwdIn the file, the UID of user root is 0.
  • Gid: indicates the group ID of the user. A user can belong to multiple groups. For example, GID 20 indicates that elvin belongs to the group whose ID is 20. On OS X/Linux systems, GID information is stored in/etc/groupIn the file, the GID of user root is 0.
  • Username: the current username. When you log in to root as elvin, it returns root instead of elvin.
  • Homedir: home directory of the current user.
  • Shell: shell path of the current user.

Execute command line commands

If the user name cannot be obtained in either of the two methods, the user name can be obtained by running the id-un command in OS X/Linux, or by running the whoami command in Windows.

// Source code 1-3
function cleanWinCmd(x) {
	return x.replace(/ ^. * \ \ /.' ');
}

function noop() {}

if (process.platform === 'darwin' || process.platform === 'linux') {
    return execa('id'['-un']).then(x= > x.stdout).catch(noop);
} else if (process.platform === 'win32') {
    return execa('whoami').then(x= > cleanWinCmd(x.stdout)).catch(noop);
}
Copy the code

The above code first identifies the operating system through process.platform. If OS X (Darwin) or Linux, execute id-un to obtain the user name. For Windows (i.e., Win32), execute whoami to get the platform & user name, and then use the regex to extract the user name through the cleanWinCmd function. A user name can be obtained with whoami on OS X/Linux, but the obsoleted command has been documented to be obsolete.

According to the Node. Js documents, process. The platform will return the current platform, including aix | Darwin | freebsd | | Linux openbsd | sunos | win32 | android, So you can actually see that the code above only considers three of these cases, and I think it would be appropriate to make the following changes:

if (process.platform === 'win32') {
    return execa('whoami').then(x= > cleanWinCmd(x.stdout)).catch(noop);
} else {
    return execa('id'['-un']).then(x= > x.stdout).catch(noop);
}
Copy the code

The improvements proposed here have been merged into the latest code via PR #20 😊

In source code 1-3, the use of noop empty functions is also worth learning: when the command executes an exception, the noop function swallows the error and returns undefined. At first I wondered why I didn’t return detailed exception information for error location, but from the perspective of the package user, I think returning undefined directly has two advantages:

  1. As a user, they usually only care about getting the correct result, not the abnormal information inside the package. In this case, the detailed error information is a kind of interference.
  2. returnundefinedIt is easier for the user to write the calling code, of course, depending on personal style.

It’s also important to note that execa, a third-party package, is used to execute command-line commands instead of the built-in Child_process. exec module in Node.js. Execa is an improvement on the native module and currently has about 6 million downloads per week. The main thing here is to take advantage of its interface for providing promises.

Write in the last

Username = 0; username = 0;

  1. Understand the system environment variables, got itSUDO_USER 与 USERThe difference between variables;
  2. In the society of the Node. Jsprocess.envAdd, delete, check and revise;
  3. Understanding of the Node. Jsos.userInfo()Information returned;
  4. knowprocess.platformThe value returned more than Darwin | win32 | Linux, perhapsusernameI can do better here;
  5. noopAn empty function has the advantage of swallowing an exception when a Promise fails.

In fact, username also uses the MEM package to buffer results to improve efficiency. Tomorrow I will read the MEM package to learn.

About me: graduated from huake, working in Tencent, elvin’s blog welcome to visit ^_^