freshshell / fresh

Keep your dotfiles fresh.

Home Page:https://freshshell.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sourcing an entire directory (--file=foo/) should preserve executable bit

bjeanes opened this issue · comments

I have a git template directory which I am trying to "fresh" into my home directory. Git template has hooks, which git expects to be executable. However, fresh makes them all read-only:

$ ls -lah ~/.git_template/hooks
total 20K
drwx------ 1 bjeanes users 102 Aug 29 12:04 .
drwx------ 1 bjeanes users  10 Aug 29 12:04 ..
-r-------- 1 bjeanes users 234 Aug 29 12:04 ctags
-r-------- 1 bjeanes users  46 Aug 29 12:04 post-checkout
-r-------- 1 bjeanes users  46 Aug 29 12:04 post-commit
-r-------- 1 bjeanes users  46 Aug 29 12:04 post-merge
-r-------- 1 bjeanes users  69 Aug 29 12:04 post-rewrite

Does --bin=foo/ work?

Error: Could not find "vcs/git/git_template" source file.
~/.freshrc:32:   fresh --bin=~/.git_template/ vcs/git/git_template

In any case, I wouldn't want every file to be made executable, which is what I'd expect --bin to do if it had done anything at all...

My first thought is one should use --bin explicitly (rather than --file) to have the executable bit set on the target. --bin does not currently support sourcing whole directories though (but it probably should).

We could possibly add an option to preserve permission bits but I’m not sure if that’s in the spirit of what --file is meant for.

As a workaround you might be able to do something like:

while read HOOK; do
  fresh "${HOOK?}" --bin="$HOME/.git_template/hooks/$(basename "${HOOK?}")"
done < <(cd "${FRESH_LOCAL?}" && find git-hooks -type f)

Another workaround might be to have an after build hook to chmod +x.

We could possibly add an option to preserve permission bits but I’m not sure if that’s in the spirit of what --file is meant for.

Nor is whole-directory sourcing either. Honestly, it feels like it is its own thing that perhaps could do a better job of tracking executable bits. I agree when it comes to 1:1 file sourcing that +x should be opt-in, but I've run into the scenario with Fresh several times where I am sourcing a tree of files from somewhere and it feels brittle to have to reach into each one and keep track of what should be made executable.

Leaving aside "external" directory sourcing to focus on a local example (git templates being pretty good example as it is, IMO)...

This is a situation where the configuration is defined by multiple files in concert. The directory structure is already represented on disk and in the repo (and --file=foo/ honours that) but so is the permissions. I definitely am +1 in applying -w to the permissions to encourage immutability and tracked changes, but other bits should be preserved, even if this behaviour is not default.

What do you think?

It sounds quite reasonable to copy over the executable bit when in directory mode. I’m trying to think of where this would be a Bad Thing™ (especially when sourcing from remote repos) but I’m not coming up with too much. I can’t think of a scenario where I’d likely want to opt out of this behaviour so we probably don’t need it to be an option.

I guess we could copy the executable bit in non-directory mode too. There may be edge cases to consider like having multiple source files with different modes set merging into a single target. I’d prefer to error in this scenario rather than taking the state from the first or last source file.

I think it's better to be explicit when copying single files because you're logically splicing multiple files together already and it's an OK source of truth, but I also don't think it's awful if it does inherit.

However, erroring if multiple files conflict seems potentially annoying, esp if pulling from multiple remote sources who you can't corral into consensus. That example makes me biased towards preferring the bit-preserving behaviour to only apply in directory mode.

How's your Perl @bjeanes? 😛

Non-existent? Wait, when did you rewrite Fresh in Perl?!

When it got a 10x speed increase! c480cab

Merges could still occur in directory mode though. Maybe we go for “if any of the source files have the executable bit set, set it on the destination file”.

If merges happen in directories, to conflicts append or replace?

If they merge, I'd actually say perhaps the safer indicator is "if they all have u+x, then the output is u+x" though that sounds a bit more annoying to implement.

I just took a look at the Perl but at-a-glance I don't really understand where or how the directory special handling is. I was looking for some kind of recursion for linking files or similar. /shrug

I think it's the $is_dir_target logic. It's been a while since I've looked at this though unfortunately. I think I'll start adding comments next time I'm updating it.

It's pretty well tested though which makes editing it easier/safer.