bitfield / script

Making it easy to write shell-like scripts in Go
MIT License
5.47k stars 313 forks source link

Easy Utility Functions to Create Symbolic/Hard Links #206

Closed elankath closed 1 month ago

elankath commented 3 months ago

One of the most common shell scripting needs is to create symbolic/hard links from/to files and directories. If script aims to live up to its stated goals 💪, it should offer easy utility one-liner functions to fulfill such a common need.

bitfield commented 3 months ago

Thanks, @elankath! Great suggestion!

How do you see this working, specifically? Can you show an example of the code you'd like to write using one of these functions? What kind of task would it make easier to solve using script?

elankath commented 3 months ago

What kind of task would it make easier to solve using script?

This is easy. Any kind of tasks where you need to create symlinks to files/dirs. dotfiles is one common use case. You have lots of configuration files in your dotfiles that you would like to link to from several places. Configuring tools/editors/IDE's which pick up files from hard-coded paths, etc

I haven't really thought on the API. I just imported script and realized I needed symlinks and it didn't have anything out of the box and thus created this issue. I am really not sure on how a clean API would look like. Does it make sense to add a SymLink method to Pipe ? So one can do something like:

script.ListFiles("~/dotfiles/cfg/*").SymLink("targetdir")

Ideally there should be some function to map target file names as well.

bitfield commented 3 months ago

So in that example, you envisage that every file in ~/dotfiles/cfg/* would be symlinked to a file of the same name in targetdir? That sounds reasonable, but would you really want to run that program? I'm not sure.

Bear in mind we're not trying to just duplicate the standard library here: os.Symlink is fine for creating individual symlinks. The extra value that script could add is creating lots of symlinks, but I suppose what I'm not seeing at the moment is when and why you'd want to do that.

Right now you could achieve this with script by using ExecForEach, for example: is it really so common a use case that it justifies a method specifically for symlinks?

elankath commented 3 months ago

Creating multiple symlinks to a target dir - ideally after a FilterLine and supporting an optional function is not a strange edge case. Taking a simple case: you can configure multiple dotfiles - .zshenv, .zshrc, .zfuncs, autorun with a tiny one liner. Especially, if you have a ~/dotfiles/zshcfg.

There are other use-cases like configuring IDE keymaps, build configs, project scripts, etc which can be symlinked (or hard-inked) quickly. Basically, creating multiple links quickly and efficiently could be considered enough of a common shell scripting need to put in Pipe. After all, one can propose the valid argument that every single convenience function can be replaced with ExecForEach.

bitfield commented 3 months ago

one can propose the valid argument that every single convenience function can be replaced with ExecForEach.

One can indeed! So, if you want to make a convincing case for adding a function especially to create symlinks, here's how to do it:

  1. Write a short but realistic program that solves a user problem relating to symlinks, using only the existing facilities, such as ExecForEach.
  2. Show the equivalent program, but this time using the proposed API (for example SymLink).

If the second program is demonstrably shorter, clearer, or otherwise better than the first, then you've made your case. If not, then you've still done valuable work in keeping the script API lean and purposeful. Your contribution will be greatly appreciated either way.

elankath commented 1 month ago

sorry for lack of response. Just as an update I used os.Symlink and proceeded. The use case for me was same as what GNU stow does