Badgerati / Fudge

Fudge is a PowerShell tool to help manage software packages via Chocolatey for specific development projects. Think NPM and Bower, but for Chocolatey
MIT License
21 stars 3 forks source link

Dynamic args and params #42

Open jayvdb opened 5 years ago

jayvdb commented 5 years ago

Composer needs to know where php is located, so it would look something like this:

        {
            "name": "php",
            "version": "7.3.6",
            "params": "/InstallDir:C:\\tools\\php"
        },
        {
            "name": "composer",
            "args": "/PHP=C:\\tools\\php\\php.exe"
        },

But it would be much nicer if there were not hard-coded directories could be something like

        {
            "name": "php",
            "version": "7.3.6",
        },
        {
            "name": "composer",
            "args": "/PHP=$(fudge which php)"
        },

or perhaps

        {
            "name": "composer",
            "dynamic-args": "name-of-script-returning-args-as-string"
        },

There is already a dependency between the composer and php packages, so the dynamic scriptlet only needs to be run just before composer is ready to be installed.

jayvdb commented 5 years ago

Or even better would be to have a hook system like @pnpm , so a custom chunk of ps1 can re-process the dependency entry and fiddle with it before fudge processes it.

jayvdb commented 5 years ago

Another important use of this would be loading the version dynamically from .nvmrc and similar.

jayvdb commented 5 years ago

Hooks in choco itself is https://github.com/chocolatey/choco/issues/1185

Badgerati commented 5 years ago

This could actually be really easily achieved using the "args": "/PHP=$(fudge which php)" syntax, as embedded PowerShell (or other script calls). There's currently something very similar over in Pode.

Idea is to basically take the string, convert it to a scriptblock, and invoke it like PowerShell:

# take the args from the fudgefile
$args = "path=$(where.exe choco)"
$args = (. ([scriptblock]::Create('return "$($args)"')))

# args is now
"path=C:\ProgramData\chocolatey\bin\choco.exe"

This also raises a point for fudge which, as it doesn't just return the path - maybe something that could be changed in #45?

For the hooks, I really like the idea; be good as a new feature request! You could have both this and the hooks. Right now there's pre/post hooks for before/after all packages, but we could have pre/post-package hooks that run before/after each package. Then maybe let each package have it's own individual pre/post hooks?

jayvdb commented 5 years ago

Embedding PS into JSON? :P Hence https://github.com/Badgerati/Fudge/issues/59 , as YAML is better for writing code snippets inside config.

Another approach for some dynamic uses of "args" and "params", slightly less pretty but less convoluted and more consistent, is to use CMD syntax, "/PHP=%PHP_ROOT%" . The users might set those envvars before calling Fudge, or Fudge could have a "environment" section which adds defaults. Then it becomes the responsibility of per-package hooks to define any new envvars which can only be known after one package is installed and needed by the args/params of a subsequent package.

This doesnt provide a nice approach for dynamically choosing whether to --forcex86 depending on an envvar, unless a more complete CMD.exe batch script parser is introduced ;-)

(It would be very useful to have a PS implementation of .CMD file parser.)

Badgerati commented 5 years ago

Haha, yeeeeah it's not great, but for simple inline stuff like /PHP=$(where.exe php) it's not too bad!

In which case, we could have:

jayvdb commented 5 years ago

Another option is to allow Fudgefile.psd1 as an alternative to Fudgefile, which allows basic PS1 to be embedded easily/naturally.

This is like Gemfile which is ruby-ish syntax. But one of the strengths of npm and pip is that their requirements formats are not language specific, so parsing is easy to do in other languages.

Badgerati commented 5 years ago

I was just thinking about changing the JSON file to a Hashtable format last night - possibly better than #59?

Since changing the file format is a v2.0 change - maybe having the args/script-args change here for v1.4?

jayvdb commented 5 years ago

Why not support both JSON and .psd1 ? That avoids a breaking change , avoids needing to rewrite all the documentation, and lets the .psd1 support be 'beta' and allowed to change over the next few versions until we're confident it is ready to be stable.

For my part, my next iteration will be importing Fudge.ps1 and FudgeTools into the coala central mobans repo, so you cant break us - you can only prevent us from upgrading fudge.

With my learnings at https://github.com/Badgerati/Fudge/issues/58#issuecomment-504761227 , I think $(..) and script-args are unnecessary hacks, and are still limited by the fact that args/script-args are a single snippet, and will not be suitable for all choco actions (install/uninstall/etc). Providing a pre-install per-package hook would allow for args and params etc to be dynamic, or if $action is in the scope only pre per-package hook is needed (and the hook logic can check if it is install/uninstall/etc).

e.g. the original problem can be solved by hook

$package.args = ("/PHP=" + (fudge which php))

And if that args breaks the choco uninstall, the hook script can be easily enhanced to

if ($action -eq 'install') {
    $package.args = ("/PHP=" + (fudge which php))
}

And %foo% style syntax can be implemented easily with a pre-install hook, if the Fudge writer feels that is more user-friendly.

if ($action -eq 'install') {
    $package.args = $package.args -replace '%PHP_ROOT%',(fudge which php)
}
else {
    $package.args = $null
}

script-args is implicitly a pre-something per-package hook, but it is limited in what it can change.