chocolatey-archive / chocolatey

[DEPRECATED - https://github.com/chocolatey/choco] Chocolatey NuGet - Like apt-get, but for windows.
https://chocolatey.org
Apache License 2.0
2.81k stars 345 forks source link

Allow creating a dependency based on an operating system version #352

Open allensanborn opened 10 years ago

allensanborn commented 10 years ago

I would like to be able to add a dependency in a Chocolatey nuspec file to an OS version number using the same rules as Nuget versioning. This is primarily needed in cases where the scripts or programs rely on OS features that can't be fulfilled in earlier OS versions. e.g. Hyper-V doesn't exist in WinXP or Win7. http://docs.nuget.org/docs/reference/versioning

Windows OS version numbers

Windows 8.1 6.3
Windows Server 2012 R2 6.3
Windows 8 6.2
Windows Server 2012 6.2
... ...

http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx

rismoney commented 10 years ago

Interestingly - I was asked this question a few days ago. The long/short of it is that the chocolatey project doesn't directly manage the nuget and/or it's spec. What you are suggesting here, is a change in nuspec functionality not chocolatey.

Right now, you can build this logic in via powershell with wmi, but it has its own set of downsides starting with ambiguous connections of packages.

allensanborn commented 10 years ago

Why is this a change to the nuspec functionality? Can't we use Nuget/nuspec as a generalized tool for specifying dependencies? Isn't the resolution of dependencies to some extent left to the tooling and what nupkgs are installed i.e. Nuget, Chocolatey, BoxStarter, ...?

Would Chocolatey be able to install packages that only specify the OS or version number?

We could take a dependency on a specific OS name/SKU e.g. Win8 OR Server2012. We could take a dependency on the OS version e.g. 6.3 (8.1/2012R2), 6.2(8/2012).

I would envision Chocolatey installing two empty packages when you install it. One package for OS and one for Version. This is still a half baked idea and there are problems around forward compatibility but it seems like this might have some merit.

I'd rather see a Chocolatey level solution even if it is just some PowerShell helpers. Currently I'm doing this to guard against bad installs: [Environment]::OSVersion.Version -ge (new-object 'Version' 6,1)

Chocolatey-WindowsFeatures is doing this: "$osVersion = (Get-WmiObject -class Win32_OperatingSystem).Version"

I'd love to hear your thoughts on this since I'm still relatively new to creating Chocolatey packages and am not sure about a LOT of architectural details in the nuspec/NuGet/Chocolatey space.

rismoney commented 10 years ago

Why is this a change to the nuspec functionality?

dependencies are defined in nuspec. however there is no conditional logic around it. It is only package to package dependencies. foo.1.0 requires bar.2.0 or greater type stuff.

I would envision Chocolatey installing two empty packages when you install it.

this seems very hackish, to get at OS versions. This overcomes package to package dependencies with a fake OS package. But it only addresses OS dependency. What about other logical dependencies? For those am I just left with powershell?

Ideally, I would want some dependency capability to do stuff like:

<chooser>
  <when $os=6.1>
    <dependency 1/>
  </when>
  <when $os=6.2>
    <dependency 2/>
  </when>
 <else>
    <dependency 3/>
  </else>
</chooser>

right now this all needs to happen in chocolateyinstall via just another cinst within a conditonal

ferventcoder commented 10 years ago

I think while the two things being discussed are related, they are slightly different. The related part is surrounding OS and dependencies. The part that is different is that one decides whether the package should be installed or not and the other decides what specifically would be installed per OS.

Am I catching the differences appropriately?

rismoney commented 10 years ago

i think so. ;)

allensanborn commented 10 years ago

I think so too.

this seems very hackish

True but you say that like it is a bad thing :)

Is it up to Nuget or Chocolatey to say that Foo.1.0 exists? If we say that a Chocolatey package has a dependency on Windows.6.2, is that resolved by Nuget or Chocolatey?

I would think Chocolatey. If so, then couldn't Chocolatey understand that it is a logical package and not a physical package? I understand that it is a limited case and doesn't resolve the problem with OS features which may be implied by OS version but is useful when there is a minimum OS version.

In regards to Windows Features, would it be possible to look to the WebPI for inspiration or implementation? If I'm installing some plugin for IIS then we better have IIS installed but right now that is step that can't be resolved without additional coding which seems silly since WebPI can be used by Chocolatey (so happy that was added).

For example the URL Rewrite package doesn't specify that IIS is required. http://chocolatey.org/packages/UrlRewrite Clearly IIS is required but you wouldn't know that by looking at the nuspec file. If it were just a wrapper around the WebPI 'package' we would see that it has two dependencies listed and those dependencies will make sure that IIS is installed. Sample section listed below.

Of course this doesn't work for all Windows Features. I can't have a PowerShell script in a Chocolatey package and list Hyper-V as a dependency even if Hyper-V is a dependency. It seems like we'd be able to figure something out along those lines. It's more difficult though when it comes to things like Windows 8 being able to mount an ISO. That isn't a -windowsfeature option but it would be great to be able to use something like a virtual package to be able to say that I need to be able to mount an ISO, I don't care how, just do it. How would Chocolatey know that it doesn't need to cinst virtualclonedrive but can just instead use posh mount-diskimage if it doesn't have some knowledge about the features of the OS that it is running on?

https://www.microsoft.com/web/webpi/4.6/webproductlist.xml

<dependency>
    <and>
        <dependency>
            <productid>StaticContent</productid>
        </dependency>
        <dependency>
            <productid>IISManagementConsole</productid>
        </dependency>
    </and>
</dependency>
<!--  Win7 / R2, x64  -->
<!--  x64 English  -->
<installer>
<id>40</id>
<languageid>en</languageid>
<architectures>
    <x64 />
</architectures>
<oslist>
    <os>
        <minimumversion>
            <osmajorversion>6</osmajorversion>
            <osminorversion>1</osminorversion>
        </minimumversion>
        <ostypes>
            <server />
            <homepremium />
            <ultimate />
            <enterprise />
            <business />
        </ostypes>
    </os>
</oslist>
<eulaurl>...</eulaurl>
<installerfile>
    <filesize>6242</filesize>
    <installerurl>
http://download.microsoft.com/download/6/7/D/67D80164-7DD0-48AF-86E3-DE7A182D6815/rewrite_amd64_en-US.msi
    </installerurl>
    <trackingurl>...</trackingurl>
    <sha1>CBB23944AF77F69E9B31357B114ADEBE12B3B1CE</sha1>
</installerfile>
<installcommands>
    <cmdline>
        <exe>%SystemRoot%\System32\net.exe</exe>
        <commandlinearguments>stop was /y</commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
    <cmdline>
        <exe>%SystemRoot%\System32\net.exe</exe>
        <commandlinearguments>stop wmsvc</commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
    <cmdline>
        <exe>%SystemRoot%\System32\cmd.exe</exe>
        <commandlinearguments>
/C reg.exe save "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" "%TEMP%\__rewrite_netfx35_sp_level.txt" /y
        </commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
    <cmdline>
        <exe>%SystemRoot%\System32\cmd.exe</exe>
        <commandlinearguments>
/C reg.exe add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" /v SP /t REG_DWORD /d 0 /f
        </commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
    <msiinstall>
        <msi>%InstallerFile%</msi>
    </msiinstall>
    <cmdline>
        <exe>%SystemRoot%\System32\cmd.exe</exe>
        <commandlinearguments>
/C reg.exe restore "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5" "%TEMP%\__rewrite_netfx35_sp_level.txt" & del "%TEMP%\__rewrite_netfx35_sp_level.txt"
        </commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
    <cmdline>
        <exe>%SystemRoot%\System32\net.exe</exe>
        <commandlinearguments>start w3svc</commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
    <cmdline>
        <exe>%SystemRoot%\System32\net.exe</exe>
        <commandlinearguments>start wmsvc</commandlinearguments>
        <ignoreexitcode>true</ignoreexitcode>
    </cmdline>
</installcommands>
</installer>
allensanborn commented 10 years ago

Another example would be in mwrock's package for Fiddler, he's manually checking to make sure that the correct version of .Net is installed and is installing it if it isn't. It isn't extremely difficult code to write but it gets a bit ugly without a fair bit of knowledge around how to manually check for dependencies and how to install windows features using DISM and might have bugs (not saying it does...).

I'm not sure why he isn't using Chocolatey's 'windowsfeature' source or 'webpi' source but that would be besides the point. If we had packages (physical, logical, or otherwise) that would allow us to specify all of the applications dependencies we wouldn't need to worry about how they were resolved as long as Chocolatey had the means to resolve it. As a bonus for creators of packages they wouldn't have to duplicate efforts or potentially introduce bugs in their installation or uninstallation process due to the oddities around what's available in which version (OS, architecture, language) of Windows they are being installed on.

https://github.com/mwrock/Chocolatey-Packages/blob/master/fiddler/tools/chocolateyInstall.ps1

$tools = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"

function Is64Bit {  [IntPtr]::Size -eq 8  }

if(Is64Bit) {$fx="framework64"} else {$fx="framework"}
if(!(test-path "$env:windir\Microsoft.Net\$fx\v2.0.50727")) {
  $packageArgs = "/c DISM /Online /NoRestart /Enable-Feature /FeatureName:NetFx3"
  $statements = "cmd.exe $packageArgs"
  Start-ChocolateyProcessAsAdmin "$statements" -minimized -nosleep -validExitCodes @(0,1)
}

Install-ChocolateyPackage 'fiddler' 'exe' '/S' 'http://www.getfiddler.com/dl/Fiddler2Setup.exe'
rismoney commented 10 years ago

I thought I wrote another reply to this- but I guess I didn't click comment...

An idea on this topic is to make the nuspec dependency element a parseable item around things like os, features, architecture and then have run-nuget or it's caller like install-chocolateypackage use a set of dependency helpers to do the needful...

<dependency id="|os|" version="6.2" />

and we use dependency helpers based on the between the pipes or other delimiter.

ferventcoder commented 10 years ago

The check that @mwrock does for the existence of the framework should be done in a separate package named solely for .net framework 3.5. I think we can agree on that.

We can either go - "Packages - its packages all the way down." or build in dependency types that are not necessarily package related.

allensanborn commented 10 years ago

Would it be appropriate to create or generate packages that wrap what is available in the windowsfeatures and webpi sources?

Where there is an intersection we'd probably want to go with webpi since it would cover cases like NetFx3 not being present on WinXp and it needing to be downloaded as opposed to it being a windowsfeature in Win8.

I think it could be automated relatively easily since the webpi feed is extremely well structured and covers OS/arch/lang variations. There would of course be gaps that windowsfeature would need to fill for Hyper-V, MSMQ and so on.

I think there might be some merit to the generation of these packages since if nothing else it would help to simplify the install scripts and not require people to become familiar with what is available from the other sources. The install scripts would be simplified since there wouldn't be any additional dependencies to install in the script since the dependency would be fulfilled by Chocolatey. It would also be forward compatible if the nuspec parsing option was pursued.

Thanks for your responses I'm definitely becoming more familiar with the tooling and problems around dependency management thanks to this thread.

allensanborn commented 10 years ago

I have some free time this week and I've been meaning to dig into the WebPI APIs a bit so hopefully I'll be able to figure out some sane solution to generating some packages directly from the WebPI feed and which get installed using WebPI in their install script. http://blogs.iis.net/kateroh/archive/2010/02/11/webpi-apis-install-a-product-from-a-custom-feed.aspx http://blogs.iis.net/kateroh/archive/2010/02/27/webpi-api-load-balance-to-set-up-backend-servers-with-latest-microsoft-web-stack.aspx http://blogs.iis.net/kateroh/archive/2010/03/20/web-pi-apis-visualize-available-products-hierarchy-with-dgml.aspx

mwrock commented 10 years ago

Agree with Rob that the fx3.5 check would be better placed in its own package. I did this for 4.5 and 4.5.1. Not sure why I did not use the WindowsFeature (especially since win features was my contribution). Maybe this package predates that.

One small caution on webpi: there are times when webPI does more than simply install what it is advertising and the simpler approach might be to simply install an MSI. I have recently discovered the .net4.0 install to be an example. Simply installing the MSI is faster and simpler and often meets your requirements while webpi makes several DISM calls and does some additional asp.net configuration. This might be what you want but not necessarily if you just need the basic framework BCL.

I was having alot of issues in Boxstarter where the webpi was failing if I disabled windows update first and if I kept it enabled, webpi turns it back on and potentially opens the flood gates of updates that then launch their own MSIEXEC processes that will cause the ,net4.0 msi in webpi to either block or sometimes fail. So the next boxstarter release will simply install the .net4.5 MSI and not use webpi which I have found to be far more reliable. Of course this is an edge case affecting new installs primarily on win7 and intermittently occurring. Each webpi package should be considered on a package by package basis.

ferventcoder commented 9 years ago

This seems to duplicate #172

grv87 commented 9 years ago

Shouldn't it be handled by higher-level instruments like Chef or Puppet?

ferventcoder commented 9 years ago

@grv87 if you are using configuration managers sure. :)