FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Allow ln destination to be an existing directory, fixes #832 by loilo · Pull Request #833 · shelljs/shelljs · GitHub

Allow ln destination to be an existing directory, fixes #832 - #833

Open
loilo wants to merge 7 commits into
shelljs:mainfrom
loilo:ln-directory-dest
Open

Allow ln destination to be an existing directory, fixes #832#833
loilo wants to merge 7 commits into
shelljs:mainfrom
loilo:ln-directory-dest

Conversation

loilo commented Apr 5, 2018

Copy link
Copy Markdown

This allows symlinking destinations to be existing directories. Symlinks will be placed inside those, as described in #832.

codecov-io commented Apr 5, 2018
edited
Loading

Copy link
Copy Markdown

Codecov Report

Merging #833 into master will increase coverage by 0.03%.
The diff coverage is 100%.

@@            Coverage Diff             @@
##           master     #833      +/-   ##
==========================================
+ Coverage   95.49%   95.53%   +0.03%     
==========================================
  Files          34       34              
  Lines        1266     1276      +10     
==========================================
+ Hits         1209     1219      +10     
  Misses         57       57
Impacted Files Coverage Δ
src/ln.js 97.61% <100%> (+0.74%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9035b27...c57f7ff. Read the comment docs.

nfischer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Looks pretty good, a few things to fix. Thanks for fixing this up, we've received an unusually high number of bug reports related to ln() recently (let me know if you're interested in fixing those too)...

Comment thread test/ln.js Outdated
const result = shell.ln('-s', 'file1', './');
t.truthy(shell.error());
t.is(result.code, 1);
shell.cd('..');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This line isn't necessary. We restore state inside beforeEach().

loilo Apr 5, 2018
edited
Loading

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Are you sure that's working correctly? If I omit restoring the original working directory, the following test will fail, afaict due to non-existing file paths.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Sorry, nevermind. I get the described behaviour when I remove the shell.cd('..') at line 158, not here.

loilo Apr 5, 2018
edited
Loading

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Removed line 56.

Re-added line 56, see comment below.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ah, this is a bug. As a safer workaround, could you edit these lines:

shelljs/test/ln.js

Lines 18 to 20 in 9035b27

test.afterEach.always(t => {
shell.rm('-rf', t.context.tmp);
});

to include process.chdir(CWD) before the rm() call? I've filed #834 to provide a better, long-term solution.

The problem with cd('..') is that our code might throw exceptions, causing the cd('..') to not be executed (and so state would never be restored). Also, I think ava stops running a test case as soon as the first assertion fails, which is another case where cd('..') would be skipped.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Yes, I've already had that case where an unrelated test would fail just because the previous one couldn't cd('..') anymore.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I have added chdiring to the CWD after each test and also removed all now-gratuitous cd('..') lines in the file.

Comment thread test/ln.js
test('Inside existing directory', t => {
shell.cd(t.context.tmp);
const result = shell.ln('-s', 'external/node_script.js', './');
t.is(result.code, 0);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

nit: also assert .stderr and shell.error() are empty

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Going to add those. It's not been done anywhere in the ln() tests, and I mostly got inspiration from the other tests around there. 🙈

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Check.

Comment thread test/ln.js Outdated
fs.readFileSync('external/node_script.js').toString(),
fs.readFileSync('node_script.js').toString()
);
shell.rm('node_script.js');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Cleanup isn't necessary

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Removed that line.

Comment thread src/ln.js Outdated
var isAbsolute = (path.resolve(source) === sourcePath);
dest = path.resolve(process.cwd(), String(dest));

if (fs.existsSync(dest) && common.statFollowLinks(dest).isDirectory(dest)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I don't think isDirectory() accepts arguments: https://nodejs.org/api/fs.html#fs_stats_isdirectory

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Oh, right. That was definitely not on purpose. 😅

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Done.

Comment thread src/ln.js Outdated
dest = path.resolve(process.cwd(), String(dest));

if (fs.existsSync(dest) && common.statFollowLinks(dest).isDirectory(dest)) {
dest = path.resolve(dest, path.basename(sourcePath));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think this should be path.join(). The docs for path.resolve() claim it produces an absolute path. ln -s actually cares if it's passed an absolute path vs. relative path, however, and path.join() preserves that.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

However, that shouldn't matter here, should it? It has been path.resolved three lines earlier anyway.

So given that we are guaranteed that dest already is an absolute path, path.join and path.resolve should return the exact same result and I decided to go for the one that was used in the code around it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Done. I've replaced resolve with join. Shouldn't change anything, but it doesn't hurt either. 😁

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ah, you're right. It's ok to resolve the destination, but not OK to resolve the source. Either join or resolve is fine.

nfischer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Looks pretty good, a few things to fix. Thanks for fixing this up, we've received an unusually high number of bug reports related to ln() recently (let me know if you're interested in fixing those too)...

loilo commented Apr 5, 2018

Copy link
Copy Markdown
Author

I'm going to take a look at your comments tomorrow, it's already night time over here. Thanks for the initial feedback. 🙂

Regaring the other ln() issues: I'd be glad to go for those if they're similarly low-hanging fruit as this one was. I'll take a look tomorrow.

loilo commented Apr 5, 2018
edited
Loading

Copy link
Copy Markdown
Author

Okay, I've adjusted the the things you mentioned. Let me know if there's anything else I can help with. 🙂

EDIT: Seems that, for some reason, the temporary test folders are not cleaned up correctly. AppVeyor tries to lint them. Let's see if I can find the cause.

EDIT 2: Weirdly, this was actually caused by removing the working directory cleanup line. I've re-added it to make tests work again.

It somehow caused temporary test folders not to get cleaned up correctly.

nfischer commented Apr 6, 2018

Copy link
Copy Markdown
Member

Regaring the other ln() issues: I'd be glad to go for those if they're similarly low-hanging fruit as this one was. I'll take a look tomorrow.

I think #829 is low-hanging.

Comment thread test/ln.js Outdated
const result = shell.ln('-s', 'file1', './');
t.truthy(shell.error());
t.is(result.code, 1);
shell.cd('..');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ah, this is a bug. As a safer workaround, could you edit these lines:

shelljs/test/ln.js

Lines 18 to 20 in 9035b27

test.afterEach.always(t => {
shell.rm('-rf', t.context.tmp);
});

to include process.chdir(CWD) before the rm() call? I've filed #834 to provide a better, long-term solution.

The problem with cd('..') is that our code might throw exceptions, causing the cd('..') to not be executed (and so state would never be restored). Also, I think ava stops running a test case as soon as the first assertion fails, which is another case where cd('..') would be skipped.

Comment thread src/ln.js Outdated
dest = path.resolve(process.cwd(), String(dest));

if (fs.existsSync(dest) && common.statFollowLinks(dest).isDirectory(dest)) {
dest = path.resolve(dest, path.basename(sourcePath));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Ah, you're right. It's ok to resolve the destination, but not OK to resolve the source. Either join or resolve is fine.

loilo commented Apr 6, 2018
edited
Loading

Copy link
Copy Markdown
Author

Added a commit which should fix #829, possibly also #830. I can't say for sure since both issues don't provide concrete examples.

This commit now allows you to use dead symlinks

  1. as destination (overriding them with -f).

  2. as source.

    It's not covered by the mentioned issues, but I stumbled upon it while fixing those: You can create a symlink pointing to another (dead) symlink via ln -s dead-source-symlink dest-symlink.

    ln() didn't do that until now, basically for the same reason as in 1. (existsSync vs lstatSync).

(This thing is kind of turning into a "general fixing of some ln() issues" branch, I hope you're okay with that. 😅)

nfischer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

his thing is kind of turning into a "general fixing of some ln() issues" branch, I hope you're okay with that.

My preference is to split into multiple PRs. We squash PRs to a single commit, and it's nice to have commits focused on a single root issue.

But I won't reject the PR if it's too much trouble to split. I left feedback on the new changes regardless, it's up to you if you want to cherry pick to a new branch.

Comment thread test/ln.js
t.is(result.code, 0);
t.falsy(result.stderr);
t.falsy(shell.error());
fs.lstatSync('link-to-dead-link');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Can we turn this into a real assertion? This would be a good use of common.isBrokenLink().

Comment thread test/ln.js
});

test('Override dead destination links with -sf', t => {
shell.cd(t.context.tmp);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

optional: you could assert the precondition (that this link is in fact a dead link). I'd be fine with t.falsy(fs.existsSync('badlink')).

Comment thread src/ln.js
var resolvedSourcePath = isAbsolute ? sourcePath : path.resolve(process.cwd(), path.dirname(dest), source);
if (!fs.existsSync(resolvedSourcePath)) {

var resolvedSourceExists;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

How about we move this to common.isBrokenLink(nameOfPossibleLink)? This is something I wanted for #835 anyway (and it makes more sense in common than utils). Some ideas for the behavior:

isBrokenLink(pointsToMissingFile)       === true
isBrokenLink(realRegularFile)           // throws an exception
isBrokenLink(someDirectory)             // throws an exception
isBrokenLink(doesNotExist)              // throws an exception
isBrokenLink(pointsToFileOrDirectory)   === false
isBrokenLink(pointsToAnotherBrokenLink) === true // `ls` highlights this just like other broken links

WDYT?

Comment thread src/ln.js
resolvedSourceExists = false;
}

if (!resolvedSourceExists) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Hmm, was this behavior ever correct with ln -s?

$ ls this-does-not-exist
ls: cannot access 'this-does-not-exist': No such file or directory
$ rm bad-link
$ ln -s this-does-not-exist bad-link
$ ls bad-link # it's highlighted link a broken link
bad-link

I think, long term, the correct logic is if (!resolvedSourceExists && !options.symlink). I wonder if this would be too big of a change (@freitagbr , what do you think?).

@loilo which bug does this address?

loilo commented Apr 8, 2018

Copy link
Copy Markdown
Author

EDIT: Removed this comment. That wasn't supposed to be posted here, I wanted to create a Gist that helped me remember how to split a pull request — sorry.

Copy link
Copy Markdown
Member

@loilo just checking in. I think this is basically good if we revert c57f7ff (to limit the fix to #832). You can cherry-pick that commit to a new branch and create a new PR.

loilo commented Apr 13, 2018

Copy link
Copy Markdown
Author

I think so too, yes. Didn't have the time to handle this in the last days, I'll take a look around the weekend.

Copy link
Copy Markdown
Member

@loilo are you interested in continuing this? Otherwise, I'll take this over and merge the fix for #832.

nfischer added this to the v0.8.x milestone Jul 12, 2018

loilo commented Jul 12, 2018

Copy link
Copy Markdown
Author

Oh dear, I totally forgot this. 😅
I'll try to take a look later today. 🙈

loilo commented Jul 12, 2018
edited
Loading

Copy link
Copy Markdown
Author

So, I looked into it and if you don't mind, I'd like to give that task back to you. I'm currently on vacation with my family and couldn't re-wrap my head around the codebase as quickly as I'd have needed to.

Otherwise I could set a reminder for after my vacation in 1-2 weeks. 🙂

Copy link
Copy Markdown
Member

@loilo no worries, I'll just cherry pick your commits for #832. Feel free to revisit a fix for #829 when you're back.

nfischer self-assigned this Jul 13, 2018
nfischer added bash compat Compatibility issues with bash or POSIX behavior fix Bug/defect, or a fix for such a problem labels Jul 13, 2018
nfischer removed this from the v0.8.x milestone Apr 6, 2021
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bash compat Compatibility issues with bash or POSIX behavior fix Bug/defect, or a fix for such a problem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants


Back | FazBrowse Home | New Git URL