Skip to content

Conversation

@nfischer
Copy link
Member

  1. This implements error codes for the builtin commands. Each command will now have an associated error code (common.status.code). I changed many of the commands to return the code that the corresponding Linux command would return (ex. ls('asdfasdf') returns 2).

  2. This fixes a bug with exec() as well. Previously, you would see the following results:

    $ cat test.js
    require('shelljs/global');
    exec('exit 5'); // or any code besides 1, 2, or 126+
    if (error())
     echo('caught the error');
    else
     echo('this error slips by');
    
    $ shjs test.js
    this error slips by
    
    

    Any non-zero exit code means that error() will return a truthy value.

  3. If config.fatal is set, then the process will exit with the last return code that was set, emulating Bash's behavior.

  4. This adds the errorCode() function to access the last error code, which is somewhat of a substitute for Bash's $? variable. This is good if a command's output may vary, but its return codes can be relied upon to stay consistent (or if output is inconvenient to type). It can be used like so:

    require('shelljs/global');
    var assert = require('assert');
    ls('missing_file1');
    var str1 = error(),
       code1 = errorCode();
    ls('missing_file2');
    var str2 = error(),
       code2 = errorCode();
    assert.ok(str1 !== str2);
    assert.ok(code1 === code2);

@nfischer nfischer added feature fix Bug/defect, or a fix for such a problem medium priority labels Jan 11, 2016
@nfischer
Copy link
Member Author

I've modified some of the calls to error() to explicitly use code 1 where appropriate (that's the default code). This makes for a messier diff, since it results in many files being modified.

Because the default error code is 1, I can actually go back and revert these lines, and they should have the same behavior. This cleans up the diff, but might make things more confusing (since it relies on that being the default). Let me know if this is preferred (this is actually the way I'm leaning).

src/common.js Outdated
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be _code != 0

Copy link
Member Author

Choose a reason for hiding this comment

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

I wrote it like this for two reasons:

  1. This prefers non-default return codes. If a command has two errors (and fatal === false, so it doesn't exit yet), and one is a non-default return code, then it prefers that value overall (which probably tells the user more useful information).
  2. This gives the user a way to send warning messages (output like an error, but don't change the status code) by providing _code === 0

I thought about changing it to if (state.errorCode === 0 || state.errorCode === DEFAULT_RETURN_CODE) instead, but that would allow error('...', 0) to wipe out a previous non-zero code, which it probably shouldn't do.

What do you think?

@ariporad
Copy link
Contributor

Looks Great, Just a few minor things I pointed out, and two bigger ones too:

  1. Why not just have error() return the code, and get rid of errorCode? Any non-zero value is truthy, so it would still work, and that would make it equivalent to bash's $?.
  2. Can you split this into two commits? One for the implimentation, and one for switching over all the functions.

Otherwise, looks great!

@nfischer
Copy link
Member Author

Thanks for the feedback! I responded inline to the minor comments. In response to the major comments:

  1. I thought about that with error(). I agree that the conditionals if (error()) and if (errorCode()) will behave the same. My concern is that error() already exists and provides a useful functionality in returning the error string. I'm not sure if anyone relies on it for its string value. One option is to rename error() to errorMsg() and errorCode() will become error(), but that may still break some scripts.
  2. I'll split this up and rebase in a moment.

Also, what do you think about camel case for errorCode()? I was also thinking of naming it errorcode(). This would be the only function in the API that is camel case.

We might also consider adding a warn() function that outputs to stderr without changing the error code. This would be very simple to implement with things the way they are written.

@nfischer
Copy link
Member Author

@ariporad I updated this and rebased off master. I reverted most of the calls to error(...1, true), but left my changes for the ones that change the status code to a non-default value. I can go back if and put those in a separate commit if you still prefer that (although this is enough to clean up the diff considerably).

If it looks good, feel free to merge. If not, leave some comments and I'll address them.

@nfischer
Copy link
Member Author

@ariporad I think this is ready for review now

@ariporad
Copy link
Contributor

@nfisher: Sorry for the delay.

I still think that we should just make error() return the error code. exec().stderr is there if you need the error string. This is what breaking changes are for.

And we should defiantly use cammelCase. What do we use now?

@nfischer
Copy link
Member Author

Right now everything is lower case. "tempdir" is an example.

I agree that works well for exec (and is more intuitive), but I think someone may still want this feature for a non-exec function. Maybe we name this to error() and rename that to errorMsg()?

Or we refactor things heavily so that every command returns an object that has a stderr field. I'm working right now to have each command return objects instead of simple strings (which should allow for pipes), and could add the stderr field. This isn't my preferred method though, since I think relying on error messages is fairly fragile (especially since we just fixed bugs related to error messages)

@ariporad
Copy link
Contributor

@nfischer: I think that we should wait till me and you and @arturadib (If he wants) to get together in gitter. It kind of revolves around how much we want to mess with shellljs. (I personally want to do a large refactor, and to standardize everything. Then we can just to a breaking change).

@nfischer
Copy link
Member Author

👍

@nfischer
Copy link
Member Author

Rebased off master

Implement error codes internally. The script will exit with the status of the
last command. The default code for errors is 1.
@ariporad
Copy link
Contributor

@nfischer: Since we're not meeting with Artur, I think we should just refactor everything to return an object with .stderr/.stdout, and have error() return the exit code.

@nfischer
Copy link
Member Author

My only concern is that it would break a lot of backwards compatibility. I agree it's a cleaner API, but do you think enough people are relying on the old behavior?

I can do that refactor either way, though 👍

@ariporad
Copy link
Contributor

@nfischer: Hmm... My comment didn't go through.

I meant to say (like 4 days ago) that I think breaking changes were invented for a reason.

@ariporad ariporad added this to the v0.6.0 milestone Jan 31, 2016
@nfischer
Copy link
Member Author

Hmm ok. It'll take me a couple days to sort out the bugs I ran into from the ShellString refactor. I'll try to prioritize that and make a separate PR for that, and then we can add error codes on top of that.

@nfischer nfischer modified the milestones: v0.7.0, v0.6.0 Feb 2, 2016
@ariporad
Copy link
Contributor

@nfischer: What's the status on this? Also, could you rebase off master?

@nfischer
Copy link
Member Author

@ariporad still in progress. I can rebase off master, but I think you'd prefer a different interface to expose return codes, so I'm waiting until I make some other changes. I'd at least like a stderr field being returned before we get rid of the current functionality of error()

@ariporad
Copy link
Contributor

@nfischer: bump.

@nfischer
Copy link
Member Author

@ariporad I think we should wait until #360 is merged, and then revisit alternate implementations. The way I see it it is that we can either do:

  • each ShellString has a code attribute (this wouldn't work well for commands like cp() that don't return anything)
  • error() returns the code, and we rely on the stderr attribute to get the error message (this also doesn't work well for commands like cp())

@nfischer nfischer mentioned this pull request Feb 20, 2016
@nfischer nfischer added medium priority and removed fix Bug/defect, or a fix for such a problem high priority labels Feb 20, 2016
@ariporad
Copy link
Contributor

@nfischer: Ok, since #360 is merged, can we move forward with having error return the error code?

@nfischer
Copy link
Member Author

Yup. I was working on it a bit yesterday. It's been a busy week, but I should have something out by Friday. I'll open this as a new PR.

@nfischer
Copy link
Member Author

nfischer commented Mar 5, 2016

I'm working on refactoring this today. I should have this out by tonight in a new PR.

@levithomason
Copy link
Contributor

Bump, this PR is tagged as blocking 1st release of shx. Anything I can do to help?

@nfischer
Copy link
Member Author

I'll wrap this up later this week, just a little in over my head right now.

@levithomason could you investigate a fix for how shelljs commands (that have fatal errors) don't output to the console sometimes? the issue was introduced when we converted config.fatal to throw an exception

@levithomason
Copy link
Contributor

Sure thing, I'll review this issue and see what I can find.

@nfischer
Copy link
Member Author

@levithomason I'll try to make a bug report that more clearly documents the problem.

And I'll get out a primitive implementation of error codes today (finally got some spare time).

@levithomason
Copy link
Contributor

Sounds good, I pulled this branch and perused around but needed more context. Will wait to hear back from you.

@nfischer
Copy link
Member Author

@levithomason the bug isn't in this branch. This branch is pretty ancient at this point (I'm refactoring everything in a new branch).

I'll ping you in the bug report, and describe it better there.

@nfischer
Copy link
Member Author

I'm closing this, since #394 is a better replacement

@nfischer nfischer closed this Mar 16, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants