RamblingCookieMonster / PSDepend

PowerShell Dependency Handler
MIT License
277 stars 75 forks source link

Installing the .NET SDK with PSDepend #90

Closed TylerLeonhardt closed 5 years ago

TylerLeonhardt commented 6 years ago

This module is awesome!

I'm wondering if there's a way to specify a dependency on the .NET SDK and have PSDepend install it if it's available.

This would be super helpful for projects that use a mix of binary modules (that need the SDK) and script modules

gaelcolas commented 6 years ago

That can be done with the Package action and the ChocolateyGet provider, or we could just create a Chocolatey PSDepend script to bypass PackageManagement altogether...

gaelcolas commented 6 years ago

I assumed Windows OS though (for Choco or ChocolateyGet). Otherwise you'd need to find a Provider that can install the SDK in any platform, or change behaviour per OS.

@tylerl0706 : can you detail the use case you have in mind?

SeeminglyScience commented 6 years ago

This is something I've been meaning to look into for awhile as well.

@gaelcolas Assuming @tylerl0706 and I have the same thing in mind, the use case would be for a build script. Right now a lot of projects have their own scripts (often half broken, including mine) to install the required SDK version before trying to build a project. Ideally it would do the following

  1. Be cross platform
  2. Allow specifying a minimum/maximum version
  3. Install to a user writable path if not installed
  4. If the SDK is already installed but is an incompatible version, install to the project directory

Here's the script I use GetDotNet.ps1. Though it only checks for a minimum version, and only installs to the project folder which is not ideal.

gaelcolas commented 6 years ago

cross platform is not available yet for this kind of packages (installer), simply because there's no meta-package management provider that enable cross platform software management abstraction. And for Windows Software, it's still Chocolatey that does this best...

Yes, a xplat Package Management provider would be nice, but it's not in the scope of PSDepend. And I'm not even sure the app name would be the same (although for dotnet it probably is).

What we'd still need anyway, is a way to specify a Package Provider based on the OS: if Windows --> Use ChocolateyGet, if Debian/Ubuntu --> use APTGetProvider, and so on... But it may not be worth working on this yet.

TylerLeonhardt commented 6 years ago

@SeeminglyScience are on the same page :)

And instead of Chocolatey and such... Why not we just use the scripts that .NET supplies https://github.com/dotnet/docs/blob/master/docs/core/tools/dotnet-install-script.md

The use case I'm looking at is for binary modules or projects that also leverage PowerShell modules.

If PSDepend supported this, a build script could be basically 2 lines:

Invoke-PSDepend
dotnet build

Today, I have to invoke the install-dotnet.ps1 as a part of that which is fine... But it's a dependency that could be handled in PSDepend.

SeeminglyScience commented 6 years ago

@gaelcolas Yeah I didn't think it would be something handled by an existing option. I think it should be it's own dependency type. I get that that would typically be a big ask for a single application, but to be fair pretty much every binary module is going to need the Core SDK.

@tylerl0706 We could write our own, but it would be nice if we didn't need to include the dependency type in every project.

RamblingCookieMonster commented 6 years ago

Oh! completely missed this thread.

I could see adding a new DependencyType to PSDepend that included a cross platform way to test/install the .NET SDK - but like others mentioned, theres no cross platform package manager we could wrap to handle that, would need all the logic right in the dependency type.

Up to you all! If you want to write something like this, I wouldn't be against including it, just not something I'd be able to tackle myself.

Cheers!

TylerLeonhardt commented 6 years ago

How do we think this should look?

I'm thinking it can have Test, Install, and Import.

Test would test that it exists in $Home/Microsoft/dotnet (which I believe is the cross-plat location). Install would run the .ps1 on Windows and .sh on everything else (because the ps1 isn't cross-plat). Install & Import would add it to the PATH.

We can offer all of the dotnet-install.ps1 parameters as parameters in the DependencyType... the exception for Version and InstallDir which will use Dependency.Version and Dependency.Target.

The weird experience to me will be the DepedencyName.

Ideally we'd want to be able to do:

DotnetSdk = 'latest' and PSDepend figures it out but I think it will have to look like:

DotnetSdk = @{
    DependencyType = 'DotnetSdk'
    ....
}

Thoughts on this?

RamblingCookieMonster commented 6 years ago

Adding the dependency would just be a psdependscripts/dotnetsdk.ps1 file and an update to psdependmap.psd1. The script itself would just need to test/install/import depending on psdependaction (this would benefit from classes, but... didn't go that route). There's a brief example here

As for users - this is a bit odd - there's no named packages to consume, just the provider and version. So... for example, could have the simplified syntax 'GitHub::RamblingCookieMonster/PSNeo4j' = 'master' - in this case, it might just be 'dotnetsdk::' = 'master'? Alternatively, if there's no chance dotnetsdk would ever make it into the powershell gallery, could just have a hard coded exception for dotnetsdk = 'latest' (would be a bit less ugly vs. dotnetsdk:: or requiring the full Dotnetsdk = @{} syntax)?

TylerLeonhardt commented 6 years ago

I like that - we could possibly have the Channel after the dotnet::

Ex. dotnet::LTS = 'latest'

Here's the full comment based help (look for my ####### comments):

<#
.SYNOPSIS
    Installs dotnet cli
.DESCRIPTION
    Installs dotnet cli. If dotnet installation already exists in the given directory
    it will update it only if the requested version differs from the one already installed.

.PARAMETER Channel
    Default: LTS
    Download from the Channel specified. Possible values:
    - Current - most current release
    - LTS - most current supported release
    - 2-part version in a format A.B - represents a specific release
          examples: 2.0; 1.0
    - Branch name
          examples: release/2.0.0; Master

###### NOT TO BE CONFUSED WITH CHANNEL.... #########

.PARAMETER Version
    Default: latest
    Represents a build version on specific channel. Possible values:
    - latest - most latest build on specific channel
    - coherent - most latest coherent build on specific channel
          coherent applies only to SDK downloads
    - 3-part version in a format A.B.C - represents specific version of build
          examples: 2.0.0-preview2-006120; 1.1.0

####### AKA TARGET ########
.PARAMETER InstallDir
    Default: %LocalAppData%\Microsoft\dotnet
    Path to where to install dotnet. Note that binaries will be placed directly in a given directory.

####### THE REST THAT WOULD GO IN PARAMETERS ########

.PARAMETER Architecture
    Default: <auto> - this value represents currently running OS architecture
    Architecture of dotnet binaries to be installed.
    Possible values are: <auto>, x64 and x86
.PARAMETER SharedRuntime
    This parameter is obsolete and may be removed in a future version of this script.
    The recommended alternative is '-Runtime dotnet'.

    Default: false
    Installs just the shared runtime bits, not the entire SDK.
    This is equivalent to specifying `-Runtime dotnet`.
.PARAMETER Runtime
    Installs just a shared runtime, not the entire SDK.
    Possible values:
        - dotnet     - the Microsoft.NETCore.App shared runtime
        - aspnetcore - the Microsoft.AspNetCore.App shared runtime
.PARAMETER DryRun
    If set it will not perform installation but instead display what command line to use to consistently install
    currently requested version of dotnet cli. In example if you specify version 'latest' it will display a link
    with specific version so that this command can be used deterministicly in a build script.
    It also displays binaries location if you prefer to install or download it yourself.
.PARAMETER NoPath
    By default this script will set environment variable PATH for the current process to the binaries folder inside installation folder.
    If set it will display binaries location but not set any environment variable.
.PARAMETER Verbose
    Displays diagnostics information.
.PARAMETER AzureFeed
    Default: https://dotnetcli.azureedge.net/dotnet
    This parameter typically is not changed by the user.
    It allows changing the URL for the Azure feed used by this installer.
.PARAMETER UncachedFeed
    This parameter typically is not changed by the user.
    It allows changing the URL for the Uncached feed used by this installer.
.PARAMETER FeedCredential
    Used as a query string to append to the Azure feed.
    It allows changing the URL to use non-public blob storage accounts.
.PARAMETER ProxyAddress
    If set, the installer will use the proxy when making web requests
.PARAMETER ProxyUseDefaultCredentials
    Default: false
    Use default credentials, when using proxy address.
.PARAMETER SkipNonVersionedFiles
    Default: false
    Skips installing non-versioned files if they already exist, such as dotnet.exe.
.PARAMETER NoCdn
    Disable downloading from the Azure CDN, and use the uncached feed directly.
#>
TylerLeonhardt commented 6 years ago

@RamblingCookieMonster does whatever comes after the :: get parsed somewhere? How does that get handled?

RamblingCookieMonster commented 6 years ago

It gets parsed as the DependencyName (among other heinous logic here). It's not passed as an explicit parameter to a dependency script, it's assumed** to be a property included in the incoming Dependency parameter - e.g. here's PSGalleryModule handling it

**: The logic mentioned above in Get-Dependency tends to avoid cases where no DependencyName is provided - e.g. if using simple::syntax it only parses if splitting the string gives two items - allowing dotnetsdk:: on its own would require adding a hard coded exception to that logic

TylerLeonhardt commented 6 years ago

I see. So when we do simple::syntax

You parse that as:

DependencyType = simple so we'd process the item as a simple.ps1 dependency type thanks to the psdependmap DependencyName = syntax

Both of which are on the Dependency object

TylerLeonhardt commented 6 years ago

FYI I have a WIP PR here: https://github.com/RamblingCookieMonster/PSDepend/pull/92