BahKoo / ChocolateStore

Cache chocolatey packages to efficiently provision multiple machines or VMs on a LAN

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Package download does not work when the URL is composed with variables in the powershell script.

BahKoo opened this issue · comments

For example, the following package is not able to download the installer for "sublime text 3":
http://chocolatey.org/api/v2/package/SublimeText3/3.0.0.3065

So I've had a bit of a play with System.Management.Automation.PowerShell and
using $ExecutionContext.InvokeCommand.ExpandString over a ScriptBlock which allows expanding static variables within the url.

However at least in the case of the Firefox chocolateyInstall.ps1 the $locale variable is defined by executing a function, which means the only way to evaluate it, is to call invoke on the script.

One option might be to remove any lines containing Install-ChocolateyPackage, invoke the script, then evaluate all the defined variables for ones containing http

I like the idea of invoking a modified version of the chocolateyInstall.ps1 script. One problem I foresee is highlighted in the SublimeText3 package. The URLs are defined in an else block which can be skipped if certain conditions are met.

Without an intimate understanding of the chocolateyInstall.ps1 scripts that exist in all the packages, I'm not sure a general solution can be achieved. I do think that more packages can work using a strategy like this and I'm willing to pull any modification that would increase the number of supported packages.

The only alternative I can think of is to modify the chocolatey source so that Install-ChocolateyPackage contains all the logic to cache and retrieve installers from a local source. With this strategy, the first time a package is installed the local installer would be missing so it would be downloaded and cached. On the next install, the local installer would be found and used instead of downloading it again.

yep, I fully appreciate that a general solution can't target all packages - another issue in the firefox package - if already installed it skips the definition block - so the machine used to update all the cached packages can't have firefox installed ...

Some psuedo code for ref;

private string CheckContent(string pattern, string destination, string content)
        {
            if (pattern.Contains('$'))
            {
                var ps = System.Management.Automation.PowerShell.Create();
                var contentWithoutInstall = Regex.Replace(content, @"Install-ChocolateyPackage(.*)", "", RegexOptions.IgnoreCase);
                ps.AddScript(contentWithoutInstall);
                ps.Invoke();

It'd also be pretty cool if, we inserted a block instead of just replacing source line - which checked if the local source exists, if not, uses the original url, maybe as a flag -allow_web_attempt

I agree. I like the command line argument -allow_web_attempt.

Another feature that could be helpful is some sort of dictionary which can be simply stored as a csv file. The key would be the original web URL and the value would be the local path. This would allow the ability to store various installers for the same chocolateyInstall.ps1 script. For example, with the firefox package this would allow caching or installers for multiple OSs.

You could recreate the script and replace Install-ChocolateyPackage command with the
Get-ChocolateyWebFile command as we have the package name, desired path and the web address, It could work for most cases...

https://github.com/chocolatey/chocolatey/blob/361389bbd0be287fff563de5112583dafd88282a/src/helpers/functions/Get-ChocolateyWebFile.ps1

I'm really close to being able to recreate repositories on offline environments, and those seems to be the only problems left... (already partially solved dependencies and getting an extensive list of all the available packages in a repository).

Any progress on this?

No sorry. I have not spent any time on this issue. I would accept pull request if someone wants to look at it.

No problem! I'm working on a solution for $variables here.

It doesn't try to automatically compute the values of variables. Instead it relies on the user to enter the values he wants when he calls ChocolateStore.

Examples:

ChocolateStore .\cache firefox $locale=de
ChocolateStore .\cache firefox $locale=de|en-US|fr

This is simpler to implement and has the advantage that the administrator can enter several options. So for example, he can download the cached package with several locales that he knows are used in his network and the original script will still select the appropriate one for a computer running chocolatey. My solution also works with several variables, as it downloads all possible permutations of variables.

I'm not finished yet, however:

  • I have to clean up and document the code.
  • I just noticed that specifying alternatives for variables with | is a bad idea, as this is a reserved character in cmd.exe - have to change this.
  • If there are several files (e.g. x86 + x64) in an installation script with the same file name but different URLs, the program currently will download the file several times and then put references to the last downloaded file into the install script. (Example: Firefox has the file name "Firefox Setup 58.0.2.exe" for x86 and x64, but they are downloaded from different paths) This issue was already there in the original version, but I'll try to think of a solution to fix this.

The code in the branch mentioned above is now feature complete. I‘ll submit a pull request soon, after I‘ve done some more extensive tests with packages from the repositories.