marcosnils / bin

Effortless binary manager
MIT License
666 stars 45 forks source link

Feature Request: Treating additional args as stdin inputs and coding options arguments as cobra [--]flags #54

Open ZacWolf opened 3 years ago

ZacWolf commented 3 years ago

To be able to use Bin in a fully automated "batch" way, I'd like to introduce changes to implement passing option choices as additional arguments.

Currently, arguments seem to be handled in a context-specific way.

Example: Bin install {source} {installdir} i.e., there's code in /cmd/install.go:48-58 that queries for an additional arg to use as the installdir.

It would be trivial to use this same approach for handling "option choices" by lopping over additional args to treat as the value to use in lieu of a prompt.

It would just have to be assumed that the user provides the arguments in the order they would otherwise be prompted in.

Thoughts?

marcosnils commented 3 years ago

It would just have to be assumed that the user provides the arguments in the order they would otherwise be prompted in.

I guess this could be possible but I have some questions / concerns that it'd be great to discuss here.

  1. Currently, option choices are not ordered in any shape or form. So basically, two bin install for the same package could potentially display two different option choices.

  2. What's your preliminary idea about how to specify this argument / flag? Is it going to be an integer with the option number? Is it going to be a string that tries to match a specific string from the options? I'd like to know more about what you had in your head

    1. We need to be aware that bin is not really a package manager, so I think it's going to be difficult for it to provide a "consistent" way to install things. I.e if we use the feature in step 2 above, and all of the sudden someone releases a new bundle with more files in the release list, it's very likely that option 2 just breaks. It's important to acknowledge this contextual nature of releases and see how we can overcome them
  3. What's going to happen in the case of tar files? Since it's probable that you have two define two options, one for the release file and the second to extract a specific file. How that would work in bin?

ZacWolf commented 3 years ago

So given today's context: bin {cmd} {arg1} {arg2} {etc}

Let's take cmd/install.go as an example.

bin install github.com/cmderdev/cmder C:\myStuff\CMDER

Looks like you're already processing three args install, {source}, {installdir}. So basically any time that you would otherwise request input from stdin [via fmt.Scanln], if there are more args, (i.e. arg[count]) then use that arg in place of stdin?

As an example, the command above currently results in two prompts to stdin: 1) Which file to install 2) Since it's a zip, it prompts me which of the files from the zip I want to install

So to automate that I would just issue the command:

bin install github.com/cmderdev/cmder C:\myStuff\CMDER 1 2

1 (the first choice "[1] cmder.zip") 2 (extract the 2nd file from the zip)

One issue might be that in the example above, the third arg is "optional". To get around that we could either beef up your current code [cmd/install.go:48-59] to test if args[1] is a directory that exists, and just stipulate in the docs that if the user provides that "optional" arg they need to make sure that whatever directory they want to install into already exists?

-OR- A neater approach would be to use spf13/cobra's concept of flags vs. args. So we just use a paradigm that "optional" arguments should always be flagged whereas non-flagged arguments are just read in order.

Using the second approach the final command would look like: bin install github.com/cmderdev/cmder 1 2 --installdir=C:\myStuff\CMDER -or- bin --installdir=C:\myStuff\CMDER github.com/cmderdev/cmder 1 2 -or- bin install github.com/cmderdev/cmder --installdir=C:\myStuff\CMDER 1 2

Where the optional arguments fall wouldn't matter, because they are "flagged" vs what is assumed to be ordered stdin responses.

Does that make sense?

Regarding your example about tar.gz, since you already have readers for each "type" of asset, you don't really have to do anything differently, since a tar.gz is already automatically extracted to a "tar" and then recurses through processReader, without any need for stdin prompts (until you're in the tar reader). The individual asset Reader is where we code/consume any args in place of stdin.

We can just create a "pkg/args.go" as a convenience class such that the next value from the original args[] array is just popped off the beginning of the array, and if there are no values left in args, then do a call to fmt.Scanln instead.

The user is responsible for providing the non-tagged[--] args in the specific order of stdin prompts, which could be different for each install. But with that second approach I outlined we could also "record" any stdin inputs via /pkg/args.go, and store that into the config, so that a call to update, would just repeat the same argument they entered via stdin the first time. If the options were to somehow change from one install to the next, then it breaks and so be it. Like you said you're not shooting for full package manager status, but basic installs/upgrades could be fully automated as long as nothing changes on the source end.

Make sense? [I edited this Wed morning as I read more about Cobra]

ZacWolf commented 3 years ago

OK, I see the larger problem now…

pkg/assets.go is just responsible for returning a reader that represents the content of a single file to "install", so the concept of how you're handling archive type files (.tar/.zip/etc) complicates that.

So for my use-case, I can't think of a single instance where I would want to install/upgrade just a single-file from a source archive. I would always want to extract all the files if the "source" points to an archive file.

So my question is if that is really a use-case that you use (selecting a single file from an archive .vs unarchiving all the files)? I ask because a much easier approach would be to test if the file being downloaded is a known archive filetype and if so just create a temp file and then use "github.com/mholt/archiver" to uncompress it to the install path. That addon automagically handles all the various archive types including compression.

This saves you from having to do the steps in assets.go:247-268, and having to read through the entire archive content to create a selection list of all the individual files (for example, the zip file I was testing with had 7000+ entries in it).

I'm trying to determine if it just makes sense for me to take my fork in a completely different direction, or if you see any value in going down the pull-requests path if you don't use the tool the way I want to use it.

THANKS! -Zac