Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os: add userInfo() method #6104

Merged
merged 1 commit into from
Apr 12, 2016
Merged

os: add userInfo() method #6104

merged 1 commit into from
Apr 12, 2016

Conversation

cjihrig
Copy link
Contributor

@cjihrig cjihrig commented Apr 7, 2016

Checklist
  • tests and code linting passes
  • a test and/or benchmark is included
  • documentation is changed or added
  • the commit message follows commit guidelines
Affected core subsystem(s)

os

Description of change

os.getpw() calls libuv's uv_os_get_passwd() function. It returns an object containing the current effective user's username, uid, gid, shell, and homedir. On Windows, the uid and gid are -1, and the shell is null.

@cjihrig cjihrig added os Issues and PRs related to the os subsystem. semver-minor PRs that contain new features and should be released in the next minor version. labels Apr 7, 2016
@addaleax
Copy link
Member

addaleax commented Apr 7, 2016

Might it be a good idea to name this differently? os.getpw sounds a lot like it returns some actual password, and I think users who are not so familiar with unices will be thrown off by this; and even for those who are it might take a bit to get from getpw to /etc/passwd.

passwd has been a misnomer for a long time now, but it has the advantage of being an identifier that many people recognize. I think libuv made a good call by naming it uv_os_get_passwd, and I’d suggest using either os.getPasswd or os.getUserInfo (or similar) – the latter having the advantage of describing what the method actually does, the former having the advantage of describing where the returned data comes from.

@mscdex
Copy link
Contributor

mscdex commented Apr 7, 2016

I agree that it should probably be named something else. I don't have any suggestions at the moment though. I suppose os.getUserInfo() as @addaleax suggested would be alright.

@bnoordhuis
Copy link
Member

os.userinfo() or os.userInfo() then; the os module has a tradition of dropping the 'get' prefix.

Alternatively, you could expose the individual properties as functions. uid and gid aren't relevant on Windows and arguably neither on Unices (because process.uid and process.gid exist), homedir duplicates os.homedir() to some extent, leaving username and shell -although the latter should probably be named loginShell or something like that.

If you stick with the object-with-properties approach, then the documentation should explain the difference between os.homedir() and os.getpw().homedir.

@Fishrock123
Copy link
Contributor

+1 to renaming, or separating out username and default shell.

@Fishrock123 Fishrock123 added the discuss Issues opened for discussions and feedbacks. label Apr 7, 2016
@jasnell
Copy link
Member

jasnell commented Apr 7, 2016

+1 to renaming. The change LGTM with that change made.

@cjihrig cjihrig force-pushed the passwd branch 2 times, most recently from 78722ca to 4abd014 Compare April 8, 2016 15:37
@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 8, 2016

Updated. I decided to rename to userInfo(), mostly to give a direct OS alternative to homedir(), as there has already been at least one request to bypass the environment variable checks.

}

entry->Set(env->homedir_string(),
OneByteString(env->isolate(), pwd.homedir));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick nit: given the likelihood that this is running on linux, there's a possibility that this may not actually be a OneByteString. It complicates things just a bit, but it might be worthwhile allowing an optional options (e.g. {encoding:'utf8'} to be passed in to GetUserInfo so that the encoding of the path can be specified. This would make it consistent with the new Buffer support in the fs module.

@jasnell
Copy link
Member

jasnell commented Apr 8, 2016

LGTM. Left a comment that could be deferred to a separate PR if necessary.

@Fishrock123 Fishrock123 changed the title os: add getpw() method os: add userInfo() method Apr 8, 2016
## os.userInfo()

Returns a subset of the password file entry for the current effective user. The
returned object includes the `username`, `uid`, `gid`, `shell`, and `homedir`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shell and homedir should be swapped here because that's the way they appear in passwd.

@silverwind
Copy link
Contributor

I'm also worried about the duplication and the fact that it's not Windows compatible.

Are there use cases where process.env.USER and process.env.SHELL are not suitable?

@Fishrock123
Copy link
Contributor

What about loginShell or defaultShell vs shell? I don't super mind one way or other but wanted to make sure we discussed it too.

@jasnell
Copy link
Member

jasnell commented Apr 8, 2016

@silverwind ... as I understand it, yes. I cannot recall the exact issue number but there is an open request to be able to retrieve the actual user information separately from the environment variables in certain use cases. The reason is that the env var could actually be incorrect in those edge cases.

The fact that this is not Windows compatible is not too concerning to me. We already have plenty of similar cases.

@jasnell
Copy link
Member

jasnell commented Apr 8, 2016

I'd prefer keeping it to just shell simply because it's more concise.

@silverwind
Copy link
Contributor

How about adding gecos and password (yeah, I know it's mostly unused today) fields? Would give this method at least some value.

@sindresorhus
Copy link

How about adding gecos

👍 On OS X at least it contains the user's fullname, which I could use for my fullname module.

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 10, 2016

@jasnell I changed to UTF8 for consistency with os.homedir(). How do you see an encoding argument working? Hypothetical situation, but what if the shell, home directory, and username all had different encodings?

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 10, 2016

re: gecos, support would need to land in libuv first.

@jasnell
Copy link
Member

jasnell commented Apr 10, 2016

In that edge case, the dev could pass encoding: 'buffer' and get back
Buffer instances for those instead of strings.
On Apr 10, 2016 6:38 AM, "Colin Ihrig" notifications@github.com wrote:

@jasnell https://github.com/jasnell I changed to UTF8 for consistency
with os.homedir(). How do you see an encoding argument working?
Hypothetical situation, but what if the shell, home directory, and username
all had different encodings?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#6104 (comment)

@jasnell
Copy link
Member

jasnell commented Apr 12, 2016

Refs: #5582

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 12, 2016

@jasnell updated to include an encoding option.

operating system. This differs from the result of `os.homedir()`, which queries
several environment variables for the home directory before falling back to the
operating system response.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: perhaps add a short note that if encoding is passed as 'buffer' the username, homedir, and shell will be returned as Buffer instances.

@jasnell
Copy link
Member

jasnell commented Apr 12, 2016

LGTM with a nit.

@cjihrig
Copy link
Contributor Author

cjihrig commented Apr 12, 2016

nit addressed. CI is green: https://ci.nodejs.org/job/node-test-pull-request/2248/

os.userInfo() calls libuv's uv_os_get_passwd() function. It returns
an object containing the current effective user's username, uid,
gid, shell, and home directory. On Windows, the uid and gid are
-1, and the shell is null.

Refs: nodejs#5582
PR-URL: nodejs#6104
Reviewed-By: James M Snell <jasnell@gmail.com>
@cjihrig cjihrig merged commit d6e56fd into nodejs:master Apr 12, 2016
@cjihrig cjihrig deleted the passwd branch April 12, 2016 21:23
@sindresorhus
Copy link

I made a polyfill for anyone needing this for existing Node.js versions (all the way back to 0.10): https://github.com/sindresorhus/user-info

@rvagg
Copy link
Member

rvagg commented Apr 14, 2016

Can someone justify this please? Most of this doesn't make sense cross-platform and as @bnoordhuis has pointed out we already expose most of these properties. Can we please not just implement things here because libuv does, we need to have more discipline than that. Too many tiny new features are getting in just because we can without much attention paid to is it worth it.

@rvagg
Copy link
Member

rvagg commented Apr 14, 2016

Adding a temporary dont-land-on-v5.x so we can discuss further.

  • username - can be fetched from environment variable, is there a compelling case for providing direct access to this?
  • uid - available at process.uid
  • gid - available at process.gid
  • shell - available via environment variable (usually), what is the use-case here? have there been calls for this? If there even prior art for use of this?
  • homedir - available via os.homedir() with justification for providing a different mechanism given in Issue about os.homedir() #5582 which boils down to a criticism of the way we implemented homedir() yet we skipped over the part where we have a discussion about the API design decisions we made and whether we should have allowed $HOME to override what the system says. I'd actually argue that we change homedir() to not use $HOME since that's a decision that can be made at the application layer as process.env.HOME is already available. So now we have two ways to access homedir and they can be different!

I'm not a fan of this and would personally prefer a revert.

@silverwind
Copy link
Contributor

silverwind commented Apr 14, 2016

I too feel that the added functionality seems rather unnecessary and that it was landed too fast without enough consensus.

@jasnell
Copy link
Member

jasnell commented Apr 15, 2016

Can't really agree with the "landed too fast" part. The PR was opened 8 days ago and landed 2 days ago. The standard rule in the collaborator's guide is 48/72 hours (weekday/weekend). We've had plenty of stuff land in far less time. While I can certainly understand regarding the not enough consensus part, given that I'm the only one who gave it an LGTM, it cannot be said that there wasn't enough time to review it. On the consensus part, this was looked at by six people, four of whom are CTC, none of whom objected. Again, we've had stuff land with less.

That said, @rvagg makes a fair request with regards to use case. For my part, I consider this an ok fix for #5582 because it does not change the existing behavior of homedir(). I'd much rather have the existing code continue to work as it has and expose the new functionality as a semver-minor addition.

bash-3.2$ sudo -u root ./node -pe "require('os').userInfo()"
{ uid: 0,
  gid: 0,
  username: 'root',
  homedir: '/var/root',
  shell: '/bin/sh' }
bash-3.2$ sudo -u root ./node -pe "require('os').homedir()"
/Users/james
bash-3.2$

I agree that the uid and gid are of significantly less value here given process.getgid() and process.getuid() work perfectly well.

@jbergstroem
Copy link
Member

(Sorry for joining post-merge as well)

I feel that the new homedir is confusing, being named after os.homedir. I personally don't have a strong opinion about reading $HOME or not (if sudo is acting up I don't feel Node.js is to blame) but the naming is unfortunate since we now have two very similar names returning different things. The other attributes available might fit well into userInfo but is already available elsewhere. I would prefer changing how os.homedir works if that indeed is a problem.

@jasnell
Copy link
Member

jasnell commented Apr 15, 2016

One thing to note is that, as it is currently implemented, os.userInfo() is slower than the existing ways of getting this information.

Given the benchmark:

'use strict';

const common = require('../common.js');
const os = require('os');

const bench = common.createBenchmark(main, {
  method: ['old', 'new'],
  millions: [2]
});

function main(conf) {
  const n = +conf.millions * 1e6;

  var i = 0;
  switch (conf.method) {
    case 'old':
      bench.start();
      for (; i < n; i++) {
        var m = {
          user: process.env.USER,
          shell: process.env.SHELL,
          homedir: os.homedir(),
          gid: process.getgid(),
          uid: process.getuid()
        }
      }
      bench.end(n / 1e6);
      break;
    case 'new':
      bench.start();
      for (; i < n; i++) {
        os.userInfo();
      }
      bench.end(n / 1e6);
      break;
    default:
      throw new Error('Unexpected');
  }
}

We see:

bash-3.2$ ./node benchmark/process/userinfo.js 
process/userinfo.js method=old millions=2: 1.11115
process/userinfo.js method=new millions=2: 0.50853

If I modify the os.userInfo() implementation to use some basic caching keyed off the encoding option:

const _userInfo = {};
exports.userInfo = function(options = {encoding: 'utf'}) {
  if (typeof options === 'string')
    options = {encoding: options};
  if (!_userInfo[options.encoding]) {
    _userInfo[options.encoding] = binding.getUserInfo(options);
  }
  return _userInfo[options.encoding];
}

The benchmark changes to:

bash-3.2$ ./node benchmark/process/userinfo.js 
process/userinfo.js method=old millions=2: 1.12694
process/userinfo.js method=new millions=2: 59.45691

Given that it's not likely that this function will be called multiple times within a single process, however, the benchmark itself (and adding caching) may be of little value.

jasnell pushed a commit that referenced this pull request Apr 26, 2016
os.userInfo() calls libuv's uv_os_get_passwd() function. It returns
an object containing the current effective user's username, uid,
gid, shell, and home directory. On Windows, the uid and gid are
-1, and the shell is null.

Refs: #5582
PR-URL: #6104
Reviewed-By: James M Snell <jasnell@gmail.com>
@Fishrock123
Copy link
Contributor

This landed in v6, and as far as I can tell should not have. Should we issue a revert? (Getting in was a bug of our release process, by the sounds of it.)

@ChALkeR
Copy link
Member

ChALkeR commented Apr 27, 2016

@Fishrock123 Strictly speaking, reverting a semver-minor feature would be a semver-major… Or is this feature broken?

@addaleax
Copy link
Member

This feature is not broken, and I agree, fully removing this in v6 is probably not a good idea.

@Fishrock123
Copy link
Contributor

We should deprecate it in the docs then.

@Fishrock123
Copy link
Contributor

No-one is significantly using it yet, so we can do that immediately.

@jasnell
Copy link
Member

jasnell commented Apr 27, 2016

It should go through the normal deprecation dance if anything. I certainly disagree with the sentiment that it shouldn't have landed in v6. It was part of master, it landed through the normal processes, there was no revert PR before v6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discuss Issues opened for discussions and feedbacks. os Issues and PRs related to the os subsystem. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.