diff --git a/.gitignore b/.gitignore index aa4c089..a1db876 100644 --- a/.gitignore +++ b/.gitignore @@ -98,3 +98,6 @@ policheck* *.orig.sln *pingme* *.GhostDoc.xml +**/.vs/ChocolateyProvider +/paket-files/ +/.paket/ diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config deleted file mode 100644 index 67f8ea0..0000000 --- a/.nuget/NuGet.Config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe deleted file mode 100644 index c296edf..0000000 Binary files a/.nuget/NuGet.exe and /dev/null differ diff --git a/.nuget/NuGet.targets b/.nuget/NuGet.targets deleted file mode 100644 index 3f8c37b..0000000 --- a/.nuget/NuGet.targets +++ /dev/null @@ -1,144 +0,0 @@ - - - - $(MSBuildProjectDirectory)\..\ - - - false - - - false - - - true - - - false - - - - - - - - - - - $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) - - - - - $(SolutionDir).nuget - - - - $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config - $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config - - - - $(MSBuildProjectDirectory)\packages.config - $(PackagesProjectConfig) - - - - - $(NuGetToolsPath)\NuGet.exe - @(PackageSource) - - "$(NuGetExePath)" - mono --runtime=v4.0.30319 "$(NuGetExePath)" - - $(TargetDir.Trim('\\')) - - -RequireConsent - -NonInteractive - - "$(SolutionDir) " - "$(SolutionDir)" - - - $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) - $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols - - - - RestorePackages; - $(BuildDependsOn); - - - - - $(BuildDependsOn); - BuildPackage; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6c9fae7 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "PowerShell", + "request": "launch", + "name": "Build", + "script": "Invoke-Psake", + "args": ["Build"], + "cwd": "${workspaceRoot}\\Build" + }, + { + "type": "PowerShell", + "request": "launch", + "name": "Build and Test", + "script": "Invoke-Psake", + "args": [], + "cwd": "${workspaceRoot}\\Build" + }, + { + "type": "PowerShell", + "request": "launch", + "name": "Test", + "script": "Invoke-Psake", + "args": ["Test"], + "cwd": "${workspaceRoot}\\Build" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a0672fb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "powershell.scriptAnalysis.settingsPath": "PSScriptAnalyzerSettings.psd1" +} \ No newline at end of file diff --git a/Build/build.ps1 b/Build/build.ps1 new file mode 100644 index 0000000..66bdf43 Binary files /dev/null and b/Build/build.ps1 differ diff --git a/Build/prepareEnvironment.ps1 b/Build/prepareEnvironment.ps1 new file mode 100644 index 0000000..bf1e921 --- /dev/null +++ b/Build/prepareEnvironment.ps1 @@ -0,0 +1,13 @@ +$InstallDir='C:\ProgramData\chocoportable' +$env:ChocolateyInstall="$InstallDir" + +Set-ExecutionPolicy Bypass -Scope Process +Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + +# Testing framework +Install-Module -Name Pester -Force -SkipPublisherCheck -Scope "CurrentUser" -RequiredVersion 4.3.1 +Import-Module -Name Pester +Install-Module -Name psake -Force -Scope "CurrentUser" -RequiredVersion 4.7.0 +Import-Module -Name psake + +choco install paket -y -version 5.133.0 \ No newline at end of file diff --git a/Build/psakefile.ps1 b/Build/psakefile.ps1 new file mode 100644 index 0000000..35c2dbf --- /dev/null +++ b/Build/psakefile.ps1 @@ -0,0 +1,106 @@ +$targetFolder = Join-Path $PSScriptRoot "Output" +$moduleName = "Chocolatey-OneGet" +$moduleFolder = Join-Path $targetFolder $moduleName +$outputRepository = "$moduleName-OutputRepository" +$installedModule = "$home\Documents\WindowsPowerShell\Modules\$moduleName" +$moduleVersion = "0.10.9" +$testsFilter = "*" # all by default +#$testsFilter = "Uninstall package" + +Task Default -Depends ` + Build,` + Test + +Task Build -Depends ` + Clean-OutputRepository,` + Clean,` + Restore-Packages,` + Register-OutputRepository, ` + Compile, ` + PublishTo-OutputRepository, ` + Compile-TestPackage + +Task Restore-Packages { + Exec { + paket restore + } +} + +Task Clean { + Remove-Item $targetFolder -Force -Recurse -ErrorAction SilentlyContinue + # This needs to kill the Visual Studio code powershell instance, otherwise the chocolatey.dll is locked. + Remove-Item $installedModule -Force -Recurse -ErrorAction SilentlyContinue +} + +Task Compile { + Copy-ToTargetFolder $moduleFolder +} + +Task Clean-OutputRepository { + Unregister-PSRepository $outputRepository -ErrorAction SilentlyContinue +} + +Task Register-OutputRepository { + mkdir "$targetFolder\$moduleName" | Out-Null + + if((Get-PSRepository | Where-Object { $_.Name -eq $outputRepository}) -eq $null){ + Register-PSRepository -Name $outputRepository -SourceLocation $targetFolder -PublishLocation $targetFolder -InstallationPolicy Trusted | Out-Null + } +} + +Task Compile-TestPackage { + $testPackages = Join-Path $targetFolder "TestPackages" + + if(-Not (Test-Path $testPackages)){ + mkdir $testPackages | Out-Null + } + + Exec { + choco pack ..\TestPackage\TestPackage.nuspec --outputdirectory $testPackages --version=1.0.1 + choco pack ..\TestPackage\TestPackage.nuspec --outputdirectory $testPackages --version=1.0.2 + choco pack ..\TestPackage\TestPackage.nuspec --outputdirectory $testPackages --version=1.0.3 + choco pack ..\TestPackage\TestPackage.nuspec --outputdirectory $testPackages --version=1.1.0-beta1 + } +} + +Task Import-CompiledModule { + if((Get-Module -Name $moduleName) -eq $null){ + # equivalent to: Install-Module $moduleName -Repository $outputRepository -Force -AllowClobber -Scope "CurrentUser" + $targetFolder = Join-Path $installedModule $moduleVersion + Copy-ToTargetFolder $targetFolder + + Import-Module $moduleName -Force -Scope Local + } +} + +Task Test -Depends Import-CompiledModule { + # Run Pester tests + $testResults = Invoke-Pester ../Tests/* -PassThru -TestName $testsFilter + + if ($testResults.FailedCount -gt 0) { + Write-Error -Message 'One or more Pester tests failed!' + } +} + +Task PublishTo-OutputRepository { + Publish-Module -Path $moduleFolder -Repository $outputRepository -Force +} + +Task Publish { + # nugetApi key needs to be provided by chocolatey owners + Publish-Module -Path $moduleFolder -NuGetApiKey "" +} + +function Copy-ToTargetFolder(){ + param([String]$targetFolder) + + if(-Not (Test-Path $targetFolder)){ + mkdir $targetFolder | Out-Null + } + + Copy-Item -Path "..\$moduleName.psd1" -Destination "$targetFolder\$moduleName.psd1" -Force + Copy-Item -Path "..\$moduleName.psm1" -Destination "$targetFolder\$moduleName.psm1" -Force + Copy-Item -Path "..\Chocolatey-Helpers.psm1" -Destination "$targetFolder\Chocolatey-Helpers.psm1" -Force + Copy-Item -Path "..\packages\chocolatey.lib\lib\chocolatey.dll" -Destination "$targetFolder\chocolatey.dll" -Force + Copy-Item -Path "..\packages\log4net\lib\net40-client\log4net.dll" -Destination "$targetFolder\log4net.dll" -Force +} \ No newline at end of file diff --git a/Chocolatey-Helpers.psm1 b/Chocolatey-Helpers.psm1 new file mode 100644 index 0000000..c3ad23c --- /dev/null +++ b/Chocolatey-Helpers.psm1 @@ -0,0 +1,19 @@ +function IsChocolateyInstalled() { + $script:chocolateyDir = $null + if ($null -ne $env:ChocolateyInstall) { + $script:chocolateyDir = $env:ChocolateyInstall; + } + elseif (Test-Path (Join-Path $env:SYSTEMDRIVE Chocolatey)) { + $script:chocolateyDir = Join-Path $env:SYSTEMDRIVE Chocolatey; + } + elseif (Test-Path (Join-Path ([Environment]::GetFolderPath("CommonApplicationData")) Chocolatey)) { + $script:chocolateyDir = Join-Path ([Environment]::GetFolderPath("CommonApplicationData")) Chocolatey; + } + + Test-Path -Path $script:chocolateyDir; +} + +function Register-ChocoDefaultSource(){ + # choco source add -n=choco -s=https://chocolatey.org/api/v2/ + Register-PackageSource -ProviderName chocolatey-oneget -Name choco -Location https://chocolatey.org/api/v2/ +} \ No newline at end of file diff --git a/Chocolatey-OneGet.psd1 b/Chocolatey-OneGet.psd1 new file mode 100644 index 0000000..8885c5f Binary files /dev/null and b/Chocolatey-OneGet.psd1 differ diff --git a/Chocolatey-OneGet.psm1 b/Chocolatey-OneGet.psm1 new file mode 100644 index 0000000..08e1ae6 --- /dev/null +++ b/Chocolatey-OneGet.psm1 @@ -0,0 +1,573 @@ +$sourceCommandName = "source" +$optionPriority = "Priority" +$optionBypassProxy = "BypassProxy" +$optionAllowSelfService = "AllowSelfService" +$optionVisibleToAdminsOnly = "VisibleToAdminsOnly" +$optionCertificate = "Certificate" +$optionCertificatePassword = "CertificatePassword" +$optionTags = "Tag" +$optionAllVersions = "AllVersions" +$optionPreRelease = "PrereleaseVersions" +$optionAllowMultiple = "AllowMultipleVersions" +$optionForceDependencies = "ForceDependencies" +$optionPackageParameters = "PackageParameters" +$optionUpgrade = "Upgrade" + +$script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor ` + [System.Management.Automation.WildcardOptions]::IgnoreCase + +function Get-PackageProviderName { + return "Chocolatey-OneGet" +} + +function Initialize-Provider { + $chocoBinary = Join-Path $PSScriptRoot "\\chocolatey.dll" + Add-Type -Path $chocoBinary +} + +function Get-Feature { + # New-Feature commes from PackageProvider functions + Write-Output -InputObject (New-Feature -name "file-extensions" -values @(".nupkg")) + Write-Output -InputObject (New-Feature -name "uri-schemes" -values @("http", "https", "file")) +} + +function Get-DynamicOptions{ + param( + [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] + $category + ) + + Write-Debug ("Get-DynamicOptions") + switch($category){ + Source { + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionPriority -ExpectedType int -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionBypassProxy -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionAllowSelfService -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionVisibleToAdminsOnly -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionCertificate -ExpectedType string -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionCertificatePassword -ExpectedType string -IsRequired $false) + } + + Package { + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionTags -ExpectedType StringArray -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionAllVersions -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionPreRelease -ExpectedType switch -IsRequired $false) + } + + Install { + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionAllowMultiple -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionForceDependencies -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionPreRelease -ExpectedType switch -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionPackageParameters -ExpectedType string -IsRequired $false) + Write-Output -InputObject (New-DynamicOption -Category $category -Name $optionUpgrade -ExpectedType switch -IsRequired $false) + } + } +} + +function Resolve-PackageSource { + $SourceNames = $request.PackageSources + + if($SourceNames.Count -eq 0) { + $SourceNames += "*" + } + + $choco = Get-Chocolatey + # fluent API of Set method returns it self, + # without assignment it is written as output object and break Find-Package + $choco = $choco.Set({ + param($config) + + $config.CommandName = $sourceCommandName + $config.SourceCommand.Command = [chocolatey.infrastructure.app.domain.SourceCommandType]::list + $config.QuietOutput = $True + }); + + $method = $choco.GetType().GetMethod("List") + $gMethod = $method.MakeGenericMethod([chocolatey.infrastructure.app.configuration.ChocolateySource]) + $registered = $gMethod.Invoke($choco, $Null) + + foreach($pattern in $SourceNames){ + if($request.IsCanceled) { + return; + } + + $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $pattern, $script:wildcardOptions + $filtered = $registered | Where-Object { $wildcardPattern.IsMatch($_.Id) -or $wildcardPattern.IsMatch($_.Value) } + + forEach($source in $filtered){ + $packageSource = New-PackageSource -Name $source.Id -Location $source.Value -Trusted $False -Registered $True + Write-Output -InputObject $packageSource + } + + if($iltered.Count -eq 0) { + # if the path is valid isnt really not our responsibility, only for Url values + $parsedUri = $null + + if([System.Uri]::TryCreate($pattern, [System.UriKind]::Absolute, [ref]$parsedUri)){ + $packageSource = New-PackageSource -Name $pattern -Location $pattern -Trusted $False -Registered $False + Write-Output -InputObject $packageSource + } + } + } +} + +function Add-PackageSource { + [CmdletBinding()] + param( + [string] + $Name, + + [string] + $Location, + + [bool] + $Trusted + ) + + if([string]::IsNullOrEmpty($Name)) { + ThrowError "System.ArgumentException" "Source Name is required" + return + } + + if([string]::IsNullOrEmpty($Location)) { + ThrowError "System.ArgumentException" "Source Location is required" + return + } + + $priority = ParseDynamicOption $optionPriority 0 + $bypassProxy = ParseDynamicOption $optionBypassProxy $False + $allowSelfService = ParseDynamicOption $optionAllowSelfService $False + $visibleToAdminsOnly = ParseDynamicOption $optionVisibleToAdminsOnly $False + $certificate = ParseDynamicOption $optionCertificate "" + $certificatePassword = ParseDynamicOption $optionCertificatePassword "" + + $choco = Get-Chocolatey + $choco = $choco.Set({ + param($config) + + $config.CommandName = $sourceCommandName + $config.SourceCommand.Command = [chocolatey.infrastructure.app.domain.SourceCommandType]::add + $config.SourceCommand.Name = $Name + $config.Sources = $Location + $config.SourceCommand.Priority = $priority + $config.SourceCommand.BypassProxy = $bypassProxy + $config.SourceCommand.AllowSelfService = $allowSelfService + $config.SourceCommand.VisibleToAdminsOnly = $visibleToAdminsOnly + $config.SourceCommand.Certificate = $certificate + $config.SourceCommand.CertificatePassword = $certificatePassword + + $credential = $request.Credential + + if ($Null -ne $credential){ + $config.SourceCommand.Username = $credential.UserName + $config.SourceCommand.Password = $credential.GetNetworkCredential().Password + } + }) + + $choco.Run() + + $created = New-Object PSCustomObject -Property (@{ + Name = $Name + Location = $Location + Trusted = $False + Registered = $True + }) + + $created = New-PackageSource -Name $Name -Location $Location -Trusted $False -Registered $True + Write-Output -InputObject $created +} + +function Remove-PackageSource { + [CmdletBinding()] + param + ( + [string] + $Name + ) + + if([string]::IsNullOrEmpty($Name)) { + ThrowError "System.ArgumentException" "Source Name is required" + return + } + + $choco = Get-Chocolatey + $choco = $choco.Set({ + param($config) + + $config.CommandName = $sourceCommandName + $config.SourceCommand.Command = [chocolatey.infrastructure.app.domain.SourceCommandType]::remove + $config.SourceCommand.Name = $Name + }); + + $choco.Run() +} + +function Find-Package { + [CmdletBinding()] + param( + [string] + $Name, + + [string] + $RequiredVersion, + + [string] + $MinimumVersion, + + [string] + $MaximumVersion + ) + + Find-ChocoPackage $Name $RequiredVersion $MinimumVersion $MaximumVersion | Write-Output +} +function Find-ChocoPackage { + [CmdletBinding()] + param( + [string] + $Name, + + [string] + $RequiredVersion, + + [string] + $MinimumVersion, + + [string] + $MaximumVersion, + + [switch] + $localScope + ) + + $sourceNames = $Request.PackageSources + $tags = ParseDynamicOption $optionTags @() + $allVersions = ParseDynamicOption $optionAllVersions $false + $preRelease = ParseDynamicOption $optionPreRelease $false + $queryVersions = Parse-Version $RequiredVersion $MinimumVersion $MaximumVersion + $allVersions = ($allVersions -or $queryVersions.defined) + $byIdOnly = -not [string]::IsNullOrEmpty($Name) -or $queryVersions.defined + + if($sourceNames.Count -eq 0){ + Resolve-PackageSource | ForEach-Object{ + $sourceNames += $_.Name + } + } + + $source = [String]::Join(";", $sourceNames) + + $choco = Get-Chocolatey + $choco = $choco.Set({ + param($config) + + $config.CommandName = [chocolatey.infrastructure.app.domain.CommandNameType]::list + + $config.Input = $Name + $config.Sources = $source + $config.ListCommand.ByIdOnly = $byIdOnly + $config.ListCommand.LocalOnly = $localScope + + if($queryVersions.min -eq $queryVersions.max){ + $config.Version = $RequiredVersion + } + + $config.AllVersions = $allVersions + $config.Prerelease = $preRelease + }) + + $method = $choco.GetType().GetMethod("List") + $gMethod = $method.MakeGenericMethod([chocolatey.infrastructure.results.PackageResult]) + $packages = $gMethod.Invoke($choco, $Null) + + foreach($found in $packages){ + if($request.IsCanceled) { + return + } + + # Choco has different usage for the tag filtering option + $package = $found.Package + $packageTags = $package.Tags + $tagFound = $tags.Count -eq 0 + + foreach($tag in $tags){ + $tagFound = $tagFound -or $packageTags.Contains($tag) + } + + if(-Not $tagFound){ + continue + } + + [NuGet.SemanticVersion]$actual = $null; + if ([NuGet.SemanticVersion]::TryParse($package.Version,[ref] $actual) ` + -and ($actual -lt $queryVersions.min -or $actual -gt $queryVersions.max)){ + continue + } + + $packageName = $found.Name + $packageVersion = $found.Version + $fileName = "$packageName.$packageVersion.nupkg" + $packageReference = Build-FastPackageReference $found + + # web server sends Uri, but local and Unc paths fill only source with full directory path + $fullPath = $found.SourceUri + if($Null -eq $fullPath) { + $parsedUri = $null + + if([System.Uri]::TryCreate($found.Source, [System.UriKind]::Absolute, [ref]$parsedUri) -and $parsedUri.IsFile) { + $fullPath = Join-Path $parsedUri.AbsolutePath $fileName + } else { + ThrowError "System.FormatException" "Unable to parse local file path from '$fullPath'" + } + } + + $identity = New-SoftwareIdentity $packageReference $packageName $packageVersion "semver" ` + $source $found.Description $Name $fullPath $fileName + Write-Output $identity + } +} + +function Get-InstalledPackage { + [CmdletBinding()] + param( + [Parameter()] + [string] + $Name, + + [Parameter()] + [string] + $RequiredVersion, + + [Parameter()] + [string] + $MinimumVersion, + + [Parameter()] + [string] + $MaximumVersion + ) + + Find-ChocoPackage $Name $RequiredVersion $MinimumVersion $MaximumVersion -localScope | Write-Output +} + +function Install-Package { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference + ) + + $packageReference = Parse-FastPackageReference $FastPackageReference + $multipleVersions = ParseDynamicOption $optionAllowMultiple $false + $packageArgs = ParseDynamicOption $optionPackageParameters "" + $upgrade = ParseDynamicOption $optionUpgrade $false + $installCommand = [chocolatey.infrastructure.app.domain.CommandNameType]::install + + if ($upgrade) { + $installCommand = [chocolatey.infrastructure.app.domain.CommandNameType]::upgrade + } + + #TODO needs to solve the source as trusted, otherwise automatic test is not able to execute + + $choco = Get-Chocolatey + $choco = $choco.Set({ + param($config) + + $config.CommandName = $installCommand + $config.PackageNames = $packageReference.Name + $config.Version = $packageReference.Version + $config.Sources = $packageReference.Source + $config.PromptForConfirmation = $False + $config.AllowMultipleVersions = $multipleVersions + $config.PackageParameters = $packageArgs + $config.Features.UsePackageExitCodes = $false + }); + + $choco.Run() + + $identity = New-SoftwareIdentity $FastPackageReference $packageReference.Name ` + $packageReference.Version "semver" $packageReference.source + Write-Output $identity + } + +function UnInstall-Package { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference + ) + + $packageReference = Parse-FastPackageReference $FastPackageReference + + $choco = Get-Chocolatey + $choco = $choco.Set({ + param($config) + + $config.CommandName = [chocolatey.infrastructure.app.domain.CommandNameType]::uninstall + $config.PackageNames = $packageReference.Name + $config.Features.UsePackageExitCodes = $false + $config.Version = $packageReference.Version + }); + + $choco.Run() + + $identity = New-SoftwareIdentity $FastPackageReference $packageReference.Name ` + $packageReference.Version "semver" $packageReference.source + Write-Output $identity +} + +function Download-Package { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $FastPackageReference, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $Location + ) + + if(-not $Location -or -not (Test-Path $Location)){ + ThrowError "System.ArgumentException" "Target location is required" + } + + $force = ParseDynamicOption "Force" $false + $packageReference = Parse-FastPackageReference $FastPackageReference + $found = Find-ChocoPackage $packageReference.Name $packageReference.Version + $downloadUrl = $found.FullPath + $fileName = $found.PackageFilename + $output = Join-Path $outputDirectory $fileName + + if (!(Test-Path $outputDirectory)) { + New-Item -ItemType Directory $outputDirectory + } + + $parsedUri = $null + + if([System.Uri]::TryCreate($downloadUrl, [System.UriKind]::Absolute, [ref]$parsedUri)) { + if($parsedUri.IsFile){ + Copy-Item -Path $parsedUri.AbsolutePath -Destination $output -Force:$force + } else { + Invoke-WebRequest -Uri $downloadUrl -OutFile $output + } + } else { + ThrowError "System.FormatException" "Unable to parse download address from '$downloadUrl'" + } +} + +#region Helper functions + +function Get-Chocolatey{ + $choco = [chocolatey.Lets]::GetChocolatey() + return $choco +} + +function ParseDynamicOption() { + param( + [string] + $optionName, + + $defaultValue + ) + + $options = $request.Options + + if($options.ContainsKey($optionName)){ + return $options[$optionName] + } + + return $defaultValue +} + +function ThrowError(){ + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $exceptionType, + + [Parameter(Mandatory=$true)] + [ValidateNotNullOrEmpty()] + [string] + $exceptionMessage + ) + + $exception = New-Object $exceptionType $exceptionMessage + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidOperation + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, "Chocolatey", $errorCategory, $Null + $PSCmdlet.ThrowTerminatingError($errorRecord) +} + +function Parse-Version(){ + param([string]$requiredVersion, + [string]$minimumVersion, + [string]$maximumVersion + ) + + [NuGet.SemanticVersion]$min = $null + [NuGet.SemanticVersion]$max = $null + [NuGet.SemanticVersion]$actual = $null + $defined = $false + + if (-Not [string]::IsNullOrEmpty($requiredVersion) -and [NuGet.SemanticVersion]::TryParse($requiredVersion, [ref] $actual)){ + $min = $max = $actual + $defined = $true + } else { + if ([string]::IsNullOrEmpty($minimumVersion) -or -not [NuGet.SemanticVersion]::TryParse($minimumVersion, [ref] $min)){ + $version = New-Object Version + $min = New-Object "NuGet.SemanticVersion" $version + } else { + $defined = $true + } + + if ([string]::IsNullOrEmpty($maximumVersion) -or -not [NuGet.SemanticVersion]::TryParse($maximumVersion, [ref] $max)){ + $max = New-Object "NuGet.SemanticVersion" @([int32]::MaxValue, [int32]::MaxValue, [int32]::MaxValue, [int32]::MaxValue) + } else { + $defined = $true + } + } + + return @{ "min" = $min + "max" = $max + "defined" = $defined + } +} + +function Build-FastPackageReference($package){ + $name = $package.Name + $version = $package.Version + $source = $package.Source + $parsedUri = $null + + if([System.Uri]::TryCreate($package.Source, [System.UriKind]::Absolute, [ref]$parsedUri) -and $parsedUri.IsFile){ + $source = $parsedUri.AbsolutePath + } + + return "$name|#|$version|#|$source" +} + +function Parse-FastPackageReference($fastPackageReference){ + $pattern = "(?.*)\|#\|(?.*)\|#\|(?.*)" + $regEx = [regex]::new($pattern, $wildcardOptions) + $parsed = $regEx.Match($fastPackageReference) + + if($parsed.Success){ + $result = @{ + Name = $parsed.Groups["Name"].Value + Version = $parsed.Groups["Version"].Value + Source = $parsed.Groups["Source"].Value + } + + return $result + } + + return $null +} + +#endregion \ No newline at end of file diff --git a/ChocolateyPackageProvider.cs b/ChocolateyPackageProvider.cs deleted file mode 100644 index d54fccb..0000000 --- a/ChocolateyPackageProvider.cs +++ /dev/null @@ -1,535 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace PackageManagement -{ - using chocolatey; - using chocolatey.infrastructure.app.configuration; - using chocolatey.infrastructure.app.domain; - using chocolatey.infrastructure.results; - using NuGet; - using Sdk; - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using Constants = Sdk.Constants; - - /// - /// A Package provider for OneGet. - /// - /// Important notes: - /// - Required Methods: Not all methods are required; some package providers do not support some features. If the methods isn't used or implemented it should be removed (or commented out) - /// - Error Handling: Avoid throwing exceptions from these methods. To properly return errors to the user, use the request.Error(...) method to notify the user of an error condition and then return. - /// - public class ChocolateyPackageProvider - { - /// - /// The features that this package supports. - /// TODO: fill in the feature strings for this provider - /// - protected static Dictionary Features = new Dictionary { - - // specify the extensions that your provider uses for its package files (if you have any) - { Constants.Features.SupportedExtensions, new[]{"nupkg"}}, - - // you can list the URL schemes that you support searching for packages with - { Constants.Features.SupportedSchemes, new [] {"http", "https", "file"}}, - -#if FOR_EXAMPLE - // add this if you want to 'hide' your provider by default. - { Constants.Features.AutomationOnly, Constants.FeaturePresent }, -#endif - // you can list the magic signatures (bytes at the beginning of a file) that we can use - - // to peek and see if a given file is yours. - { Constants.Features.MagicSignatures, Constants.Signatures.ZipVariants}, - }; - - private GetChocolatey _chocolatey; - - /// - /// Returns the name of the Provider. - /// TODO: Test and verify that we want "choco" vs "chocolatey" - /// TODO: let's keep it as 'choco' until we are ready to punt the prototype provider - /// - /// The name of this provider - public string PackageProviderName - { - get { return "Choco"; } - } - - /// - /// Returns the version of the Provider. - /// - /// The version of this provider - public string ProviderVersion - { - get - { - return "3.0.0.0"; - } - } - - /// - /// This is just here as to give us some possibility of knowing when an unexception happens... - /// At the very least, we'll write it to the system debug channel, so a developer can find it if they are looking for it. - /// - public void OnUnhandledException(string methodName, Exception exception) - { - Debug.WriteLine("Unexpected Exception thrown in '{0}::{1}' -- {2}\\{3}\r\n{4}", PackageProviderName, methodName, exception.GetType().Name, exception.Message, exception.StackTrace); - } - - /// - /// Performs one-time initialization of the $provider. - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void InitializeProvider(Request request) - { - request.Debug("Entering '{0}::InitializeProvider' to set up a chocolatey with custom logging", PackageProviderName); - _chocolatey = Lets.GetChocolatey().SetCustomLogging(new RequestLogger(request)); - } - - /// - /// Returns dynamic option definitions to the HOST - /// - /// example response: - /// request.YieldDynamicOption( "MySwitch", OptionType.String.ToString(), false); - /// - /// - /// The category of dynamic options that the HOST is interested in - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void GetDynamicOptions(string category, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::GetDynamicOptions' {1}", PackageProviderName, category); - - switch ((category ?? string.Empty).ToLowerInvariant()) - { - case "install": - // TODO: put the options supported for install/uninstall/getinstalledpackages - - break; - - case "provider": - // TODO: put the options used with this provider (so far, not used by OneGet?). - - break; - - case "source": - // TODO: put any options for package sources - - break; - - case "package": - // TODO: put any options used when searching for packages - - break; - default: - request.Debug("Unknown category for '{0}::GetDynamicOptions': {1}", PackageProviderName, category); - break; - } - } - - /// - /// Returns a collection of strings to the client advertizing features this provider supports. - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void GetFeatures(Request request) - { - request.Debug("Entering '{0}::GetFeatures' ", PackageProviderName); - - foreach (var feature in Features) - { - request.Yield(feature); - } - } - - #region Sources - /// - /// Resolves and returns Package Sources to the client. - /// - /// Specified sources are passed in via the request object (request.GetSources()). - /// - /// Sources are returned using request.YieldPackageSource(...) - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void ResolvePackageSources(Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::ResolvePackageSources'", PackageProviderName); - - foreach (var source in GetSource(request.Sources.ToArray())) - { - request.YieldPackageSource(source.Id, source.Value, false, source.Authenticated, false); - } - } - #endregion - - /// - /// This is called when the user is adding (or updating) a package source - /// - /// The name of the package source. If this parameter is null or empty the PROVIDER should use the location as the name (if the PROVIDER actually stores names of package sources) - /// The location (ie, directory, URL, etc) of the package source. If this is null or empty, the PROVIDER should use the name as the location (if valid) - /// A boolean indicating that the user trusts this package source. Packages returned from this source should be marked as 'trusted' - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void AddPackageSource(string name, string location, bool trusted, Request request) - { - // TODO: Make chocolatey store "trusted" property on the sources - request.Debug("Entering {0} source add -n={1} -s'{2}' (we don't support trusted = '{3}')", PackageProviderName, name, - location, trusted); - - _chocolatey.Set(conf => - { - conf.CommandName = "Source"; - conf.SourceCommand.Command = SourceCommandType.add; - conf.SourceCommand.Name = name; - conf.Sources = location; - conf.AllowUnofficialBuild = true; - }).Run(); - } - - /// - /// Removes/Unregisters a package source - /// - /// The name or location of a package source to remove. - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void RemovePackageSource(string name, Request request) - { - request.Debug("Entering {0} source remove -n={1})", PackageProviderName, name); - - _chocolatey.Set(conf => - { - conf.CommandName = "Source"; - conf.SourceCommand.Command = SourceCommandType.remove; - conf.SourceCommand.Name = name; - conf.AllowUnofficialBuild = true; - }).Run(); - // TODO: support user-defined package sources OR remove this method - } - - #endregion - - /// - /// Searches package sources given name and version information - /// - /// Package information must be returned using request.YieldPackage(...) function. - /// - /// a name or partial name of the package(s) requested - /// A specific version of the package. Null or empty if the user did not specify - /// A minimum version of the package. Null or empty if the user did not specify - /// A maximum version of the package. Null or empty if the user did not specify - /// if this is greater than zero (and the number should have been generated using StartFind(...), the core is calling this multiple times to do a batch search request. The operation can be delayed until CompleteFind(...) is called - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void FindPackage(string name, string requiredVersion, string minimumVersion, string maximumVersion, int id, Request request) - { - request.Debug("Entering '{0}::FindPackage' '{1}','{2}','{3}','{4}', '{5}'", PackageProviderName, name, requiredVersion, minimumVersion, maximumVersion, id); - request.Debug("FindPackage:: " + request.PackageSources.@join("|")); - var versions = ParseVersion(requiredVersion, minimumVersion, maximumVersion); - - var sources = GetSource(request.PackageSources.ToArray()); - // TODO: need to support URLs for sources ... - foreach(var package in _chocolatey.Set(conf => - { - conf.CommandName = "List"; - conf.Input = name; - conf.Sources = sources.Select(cs => cs.Value).@join(";"); - conf.Version = requiredVersion; - conf.AllowUnofficialBuild = true; - }).List()) - { - SemanticVersion actual; - if (SemanticVersion.TryParse(package.Version, out actual) && (actual < versions.Item1 || actual > versions.Item2)) - { - continue; - } - request.YieldSoftwareIdentity(package); - } - } - - private static Tuple ParseVersion(string requiredVersion, string minimumVersion, string maximumVersion) - { - SemanticVersion min, max, actual; - - if (!string.IsNullOrEmpty(requiredVersion) && SemanticVersion.TryParse(requiredVersion, out actual)) - { - min = max = actual; - } - else - { - if (string.IsNullOrEmpty(minimumVersion) || !SemanticVersion.TryParse(minimumVersion, out min)) - { - min = new SemanticVersion(new Version()); - } - if (string.IsNullOrEmpty(maximumVersion) || !SemanticVersion.TryParse(maximumVersion, out max)) - { - max = new SemanticVersion(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue); - } - } - return new Tuple(min, max); - } - - - private IEnumerable GetSource(params string[] names) - { - IEnumerable sources; - if (names.Any()) - { - var all = new List(); - // the system is requesting sources that match the values passed. - // if the value passed can be a legitimate source, but is not registered, return a package source marked unregistered. - - all.AddRange( _chocolatey.Set(conf => - { - conf.CommandName = "Source"; - conf.SourceCommand.Command = SourceCommandType.list; - conf.Sources = names.@join(";"); - conf.AllowUnofficialBuild = true; - }).List().Where(source => names.Any(name => name == source.Id || name == source.Value))); - - if (!all.Any()) - { - foreach (var n in names) - { - string name = n; - var s = _chocolatey.Set(conf => - { - conf.CommandName = "Source"; - conf.SourceCommand.Command = SourceCommandType.list; - conf.Sources = name; - conf.AllowUnofficialBuild = true; - }).List().Where(source => name == source.Id || name == source.Value).ToList(); - if (!s.Any()) - { - all.Add(new ChocolateySource {Id = name, Value = name}); - } - else - { - all.AddRange(s); - } - } - } - sources = all; - } - else - { - // the system is requesting all the registered sources - sources = _chocolatey.Set(conf => - { - conf.CommandName = "Source"; - conf.SourceCommand.Command = SourceCommandType.list; - conf.AllowUnofficialBuild = true; - }).List(); - } - return sources; - } - -/* - /// - /// Finds packages given a locally-accessible filename - /// - /// Package information must be returned using request.YieldPackage(...) function. - /// - /// the full path to the file to determine if it is a package - /// if this is greater than zero (and the number should have been generated using StartFind(...), the core is calling this multiple times to do a batch search request. The operation can be delayed until CompleteFind(...) is called - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void FindPackageByFile(string file, int id, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::FindPackageByFile' '{1}','{2}'", PackageProviderName, file, id); - - // TODO: implement searching for a package by analyzing the package file, or remove this method - } - - /// - /// Finds packages given a URI. - /// - /// The function is responsible for downloading any content required to make this work - /// - /// Package information must be returned using request.YieldPackage(...) function. - /// - /// the URI the client requesting a package for. - /// if this is greater than zero (and the number should have been generated using StartFind(...), the core is calling this multiple times to do a batch search request. The operation can be delayed until CompleteFind(...) is called - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void FindPackageByUri(Uri uri, int id, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::FindPackageByUri' '{1}','{2}'", PackageProviderName, uri, id); - - // TODO: implement searching for a package by it's unique uri (or remove this method) - } - - /// - /// Downloads a remote package file to a local location. - /// - /// - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void DownloadPackage(string fastPackageReference, string location, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::DownloadPackage' '{1}','{2}'", PackageProviderName, fastPackageReference, location); - - // TODO: actually download the package ... - - } - - /// - /// Returns package references for all the dependent packages - /// - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void GetPackageDependencies(string fastPackageReference, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::GetPackageDependencies' '{1}'", PackageProviderName, fastPackageReference); - - // TODO: check dependencies - - } - -*/ - - /// - /// Installs a given package. - /// - /// A provider supplied identifier that specifies an exact package - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void InstallPackage(string fastPackageReference, Request request) - { - request.Debug("Entering '{0}::InstallPackage' '{1}'", PackageProviderName, fastPackageReference); - var parts = fastPackageReference.Split(RequestHelper.NullChar); - var force = false; - - var forceStr = request.GetOptionValue("Force"); - if (!string.IsNullOrEmpty(forceStr)) - { - bool.TryParse(forceStr, out force); - } - - foreach (var package in _chocolatey.Set(conf => - { - conf.CommandName = "Install"; - conf.Sources = GetSource(parts[0]).Select(cs => cs.Value).@join(";"); - conf.PackageNames = parts[1]; - conf.Version = parts[2]; - conf.AllowUnofficialBuild = true; - conf.Force = force; - }).List()) - { - request.YieldSoftwareIdentity(package); - } - } - - /// - /// Uninstalls a package - /// - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void UninstallPackage(string fastPackageReference, Request request) - { - // TODO: improve this debug message that tells us what's going on (what about the dynamic parameters) - var parts = fastPackageReference.Split(RequestHelper.NullChar); - request.Debug("Entering '{0}::UninstallPackage' '{1}'", PackageProviderName, parts.@join("' '")); - - // TODO: add dynamic parameters for AllVersions and ForceDependencies - foreach (var package in _chocolatey.Set(conf => - { - conf.CommandName = "Uninstall"; - //conf.Sources = parts[0]; - conf.PackageNames = parts[1]; - conf.Version = parts[2]; - }).List()) - { - request.YieldSoftwareIdentity(package); - } - } - - /// - /// Returns the packages that are installed - /// - /// the package name to match. Empty or null means match everything - /// the specific version asked for. If this parameter is specified (ie, not null or empty string) then the minimum and maximum values are ignored - /// the minimum version of packages to return . If the requiredVersion parameter is specified (ie, not null or empty string) this should be ignored - /// the maximum version of packages to return . If the requiredVersion parameter is specified (ie, not null or empty string) this should be ignored - /// - /// An object passed in from the CORE that contains functions that can be used to interact with - /// the CORE and HOST - /// - public void GetInstalledPackages(string name, string requiredVersion, string minimumVersion, string maximumVersion, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::GetInstalledPackages' '{1}' '{2}' '{3}' '{4}'", PackageProviderName, name, requiredVersion, minimumVersion, maximumVersion); - var versions = ParseVersion(requiredVersion, minimumVersion, maximumVersion); - - foreach (var package in _chocolatey.Set(conf => - { - conf.CommandName = "List"; - conf.Input = name; - conf.ListCommand.LocalOnly = true; - conf.AllowUnofficialBuild = true; - }).List()) - { - SemanticVersion actual; - if (SemanticVersion.TryParse(package.Version, out actual) && (actual < versions.Item1 || actual > versions.Item2)) - { - continue; - } - request.YieldSoftwareIdentity(package); - } - } - -/* - /// - /// - /// - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - public void GetPackageDetails(string fastPackageReference, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::GetPackageDetails' '{1}'", PackageProviderName, fastPackageReference); - - // TODO: This method is for fetching details that are more expensive than FindPackage* (if you don't need that, remove this method) - } - - /// - /// Initializes a batch search request. - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - /// - public int StartFind(Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::StartFind'", PackageProviderName); - - // TODO: batch search implementation - return default(int); - } - - /// - /// Finalizes a batch search request. - /// - /// - /// An object passed in from the CORE that contains functions that can be used to interact with the CORE and HOST - /// - public void CompleteFind(int id, Request request) - { - // TODO: improve this debug message that tells us what's going on. - request.Debug("Entering '{0}::CompleteFind' '{1}'", PackageProviderName, id); - // TODO: batch search implementation - } -*/ - } -} diff --git a/ChocolateyProvider.csproj b/ChocolateyProvider.csproj deleted file mode 100644 index 1b655c1..0000000 --- a/ChocolateyProvider.csproj +++ /dev/null @@ -1,104 +0,0 @@ - - - - - Debug - AnyCPU - {12BC926F-9911-47DB-A490-21E8686514F6} - Library - Properties - PackageManagement - ChocolateyProvider - 512 - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), solution.props))\solution.props - - - - - $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), PackageProvider.sln))\ - $(SolutionDir) - - v4.0 - v4.0 - $(SolutionRootDir)output\$(TargetFrameworkVersion.Replace(".",""))\$(Configuration)\bin\ - $(SolutionRootDir)intermediate\$(TargetFrameworkVersion.Replace(".",""))\$(Configuration)\$(AssemblyName)\ - $(BaseIntermediateOutputPath) - $(OutputPath)$(AssemblyName).XML - 1591 - true - FRAMEWORK$(TargetFrameworkVersion.Replace(".","")) - output\$(TargetFrameworkVersion.Replace(".",""))\$(Configuration)\bin\ - - - true - full - false - $(DefineConstants);DEBUG;TRACE - prompt - 4 - output\v40\Debug\bin\ChocolateyProvider.xml - - - pdbonly - true - TRACE - prompt - 4 - output\v40\Release\bin\ChocolateyProvider.xml - - - - - - - - - - True - True - Messages.resx - - - - - - ResXFileCodeGenerator - Messages.Designer.cs - - - - - packages\chocolatey.lib.0.9.10.3\lib\chocolatey.dll - True - - - packages\log4net.2.0.3\lib\net40-full\log4net.dll - True - - - - - - - - - - - - - - :Locate MT.EXE Tool: -for /f "delims=" %25%25a in ('powershell "$p = ((Get-ItemProperty -Path HKCU:\Software\PackageManagement\Tools\MT.EXE -Name Path -ea 0).Path) ; if( -not $p ) { $p = ((dir ${env:ProgramFiles(x86)} -recurse -ea 0| where -property name -eq mt.exe | select -first 1 ).FullName) ; $null = mkdir -Path HKCU:\Software\PackageManagement\Tools\MT.EXE -Force ; $null = New-ItemProperty -Path HKCU:\Software\PackageManagement\Tools\MT.EXE -Name Path -Value $p -force } ; $p"') do @set MTEXE=%25%25a - -:Run the tool to add the manifest to the binary. -"%25MTEXE%25" -manifest $(ProjectDir)provider.manifest -outputresource:$(TargetPath);#101 - - - - diff --git a/ChocolateyProvider.sln b/ChocolateyProvider.sln deleted file mode 100644 index ddf392f..0000000 --- a/ChocolateyProvider.sln +++ /dev/null @@ -1,29 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChocolateyProvider", "ChocolateyProvider.csproj", "{12BC926F-9911-47DB-A490-21E8686514F6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D4933EC0-5563-4BE5-88D3-FA1ADC0BE218}" - ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {12BC926F-9911-47DB-A490-21E8686514F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {12BC926F-9911-47DB-A490-21E8686514F6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12BC926F-9911-47DB-A490-21E8686514F6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {12BC926F-9911-47DB-A490-21E8686514F6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/PSScriptAnalyzerSettings.psd1 b/PSScriptAnalyzerSettings.psd1 new file mode 100644 index 0000000..3be9451 --- /dev/null +++ b/PSScriptAnalyzerSettings.psd1 @@ -0,0 +1,23 @@ +@{ + IncludeRules = @('PSAvoidAssignmentToAutomaticVariable', + 'PSAvoidDefaultValueSwitchParameter', + 'PSAvoidGlobalAliases', + 'PSAvoidGlobalFunctions', + 'PSAvoidGlobalVars', + 'PSAvoidTrailingWhitespace', + 'PSAvoidUsingCmdletAliases', + 'PSAvoidUsingEmptyCatchBlock', + 'PSMisleadingBacktick', + 'PSMissingModuleManifestField', + 'PSPossibleIncorrectComparisonWithNull', + 'PSPossibleIncorrectUsageOfAssignmentOperator', + 'PSPossibleIncorrectUsageOfRedirectionOperator', + 'PSReservedCmdletChar', + 'PSReservedParams', + 'PSReservedParams', + 'PSShouldProcess', + 'PSUseApprovedVerbs', + 'PSUseDeclaredVarsMoreThanAssignments', + 'PSUseLiteralInitializerForHashtable' + ) +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs deleted file mode 100644 index a5cb412..0000000 --- a/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly: AssemblyTitle("Chocolatey.PackageManagement")] -[assembly: AssemblyDescription("PackageManagement package provider: Chocolatey")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Chocolatey")] -[assembly: AssemblyProduct("Chocolatey Provider for PackageManagement")] -[assembly: AssemblyCopyright("Copyright Chocolatey © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly: Guid("bff90b5a-cb46-49b3-a3d5-5df99bf23017")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] - -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/README.md b/README.md index eaab1f7..7d17ee3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,48 @@ -**NOTE:** Seeking maintainers to help finish this Provider. Please inquire on the issues list or on Gitter (see the chat room below). Thanks! +# Chocolatey Provider for PowerShell PackageManagement -**NOTE:** For now, you may be more interested in using the ChocolateyGet provider as a stop gap solution until this provider is ready. See https://github.com/jianyunt/ChocolateyGet for details +This is the official Chocolatey provider for PackageManagement (aka OneGet). -# Chocolatey Provider for PowerShell PackageManagement (aka OneGet) (C#) -This will be the official Chocolatey provider for PackageManagement. +## Features -## Development Requires: - - Visual Studio 2013+ - - Any official PackageManagement build from February 2015 or later. +* search/find installed/install/uninstall packages +* upgrade packages +* download package +* manage package sources +* online/offline installation -## Chat Room +## [How to use it](/docs/howto.md) -Come join in the conversation about Chocolatey in our Gitter Chat Room +## [License](LICENSE) + +# [Development](/docs/contributing.md) + +## Progress + +* [x] Implement metadata +* [x] Implement install able skeleton +* [x] Prepare build and test infrastructure +* API: + * [x] Get-ProviderName + * [x] Initialize-Provider + * [x] Resolve-PackageSource + * [x] Add-PackageSource + * [x] Remove-PackageSource + * [x] Find-Package + * [x] Install-Package + * [x] Get-InstalledPackage + * [x] UnInstall-Package + * [ ] Download-Package - IN PROGRESS + +## Not implemented +* Trusted package sources +* Disable package source +* Custom credentials in Find-Package +* Advanced chocolatey switches + +## Contribution + +> **NOTE:** Seeking maintainers to help finish this Provider. Please inquire on the issues list or on Gitter (see the chat room below). Thanks! + +Come join in the conversation about Chocolatey in our Gitter Chat Room. [![Join the chat at https://gitter.im/chocolatey/chocolatey-oneget](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/chocolatey/chocolatey-oneget?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/RequestHelper.cs b/RequestHelper.cs deleted file mode 100644 index 0fc7040..0000000 --- a/RequestHelper.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace PackageManagement -{ - using chocolatey.infrastructure.results; - using Sdk; - - public static class RequestHelper - { - public static readonly char NullChar = Convert.ToChar(0x0); - public static readonly string NullString = new string(NullChar, 1); - - public static string YieldSoftwareIdentity(this Request request, PackageResult package) - { - var fastPath = string.Join(NullString, package.Source, package.Package.Id, package.Version); - var fileName = string.Format("{0}.{1}.nupkg", package.Package.Id, package.Version); - var uri = package.SourceUri ?? (package.Package.ProjectUrl == null ? "" : package.Package.ProjectUrl.AbsoluteUri); - return request.YieldSoftwareIdentity( - fastPath, // this should be what we need to figure out how to find the package again - package.Package.Id, // this is the friendly name of the package - package.Version, "semver", // the version and version scheme - package.Package.Summary ?? package.Package.Description, // the summary (sometimes NuGet puts it in Description?) - package.Source, // the package SOURCE name - package.Name, // the search that returned this package - uri, // should be the full path to the file (I pass a project URL otherwise?) - package.InstallLocation ?? fileName); // a file name in case they want to download it... - } - } -} diff --git a/RequestLogger.cs b/RequestLogger.cs deleted file mode 100644 index 94c10fc..0000000 --- a/RequestLogger.cs +++ /dev/null @@ -1,82 +0,0 @@ -namespace PackageManagement -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using chocolatey.infrastructure.logging; - using PackageManagement.Sdk; - - public class RequestLogger : ILog - { - private readonly Request _request; - - public RequestLogger(Request request) - { - _request = request; - } - - public void InitializeFor(string loggerName) - { - // TODO: I don't think I'm allowed to do this - } - - public void Debug(string message, params object[] formatting) - { - _request.Debug(message, formatting); - } - - public void Debug(Func message) - { - _request.Debug(message.Invoke()); - } - - public void Info(string message, params object[] formatting) - { - _request.Verbose(message, formatting); - } - - public void Info(Func message) - { - _request.Verbose(message.Invoke()); - } - - public void Warn(string message, params object[] formatting) - { - _request.Warning(message, formatting); - } - - public void Warn(Func message) - { - _request.Warning(message.Invoke()); - } - public void Error(string id, string category, string targetObject, string message) - { - _request.Error(id, category, targetObject, message); - } - public void Error(ErrorCategory category, string targetObject, string message, params object[] formatting) - { - _request.Error(category, targetObject, message, formatting); - } - - public void Error(string message, params object[] formatting) - { - _request.Error(ErrorCategory.NotSpecified, "", message, formatting); - } - - public void Error(Func message) - { - _request.Error(ErrorCategory.NotSpecified, "", message.Invoke()); - } - - public void Fatal(string message, params object[] formatting) - { - _request.Error(ErrorCategory.NotSpecified, "FATAL", message, formatting); - } - - public void Fatal(Func message) - { - _request.Error(ErrorCategory.NotSpecified, "FATAL", message.Invoke()); - } - } -} diff --git a/Resources/Messages.Designer.cs b/Resources/Messages.Designer.cs deleted file mode 100644 index 2f03c62..0000000 --- a/Resources/Messages.Designer.cs +++ /dev/null @@ -1,73 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace PackageManagement.Resources -{ - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Messages - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Messages() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if (object.ReferenceEquals(resourceMan, null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PackageManagement.Resources.Messages", typeof(Messages).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - } -} - diff --git a/Resources/Messages.resx b/Resources/Messages.resx deleted file mode 100644 index 78916d2..0000000 --- a/Resources/Messages.resx +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - diff --git a/Sdk/Constants.cs b/Sdk/Constants.cs deleted file mode 100644 index eb3ec11..0000000 --- a/Sdk/Constants.cs +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace PackageManagement.Sdk -{ - public static partial class Constants - { - #region copy common-constants-implementation /internal/public - - public const string MinVersion = "0.0.0.1"; - public const string MSGPrefix = "MSG:"; - public static string[] FeaturePresent = new string[0]; - public static string[] Empty = new string[0]; - - public static partial class Features - { - public const string AutomationOnly = "automation-only"; - public const string MagicSignatures = "magic-signatures"; - public const string SupportedExtensions = "file-extensions"; - public const string SupportedSchemes = "uri-schemes"; - public const string SupportsPowerShellModules = "supports-powershell-modules"; - public const string SupportsRegexSearch = "supports-regex-search"; - public const string SupportsSubstringSearch = "supports-substring-search"; - public const string SupportsWildcardSearch = "supports-wildcard-search"; - } - - public static partial class Messages - { - public const string CreatefolderFailed = "MSG:CreatefolderFailed"; - public const string DependencyResolutionError = "MSG:UnableToResolveDependency_dependencyPackage"; - public const string DependentPackageFailedInstall = "MSG:DependentPackageFailedInstall_dependency"; - public const string DestinationPathNotSet = "MSG:DestinationPathNotSet"; - public const string FailedProviderBootstrap = "MSG:FailedProviderBootstrap"; - public const string FileFailedVerification = "MSG:FileFailedVerification"; - public const string InvalidFilename = "MSG:InvalidFilename"; - public const string MissingRequiredParameter = "MSG:MissingRequiredParameter"; - public const string PackageFailedInstall = "MSG:UnableToInstallPackage_package_reason"; - public const string PackageSourceExists = "MSG:PackageSourceExists"; - public const string ProtocolNotSupported = "MSG:ProtocolNotSupported"; - public const string ProviderPluginLoadFailure = "MSG:ProviderPluginLoadFailure"; - public const string ProviderSwidtagUnavailable = "MSG:ProviderSwidtagUnavailable"; - public const string RemoveEnvironmentVariableRequiresElevation = "MSG:RemoveEnvironmentVariableRequiresElevation"; - public const string SchemeNotSupported = "MSG:SchemeNotSupported"; - public const string SourceLocationNotValid = "MSG:SourceLocationNotValid_Location"; - public const string UnableToCopyFileTo = "MSG:UnableToCopyFileTo"; - public const string UnableToCreateShortcutTargetDoesNotExist = "MSG:UnableToCreateShortcutTargetDoesNotExist"; - public const string UnableToDownload = "MSG:UnableToDownload"; - public const string UnableToOverwriteExistingFile = "MSG:UnableToOverwriteExistingFile"; - public const string UnableToRemoveFile = "MSG:UnableToRemoveFile"; - public const string UnableToResolvePackage = "MSG:UnableToResolvePackage"; - public const string UnableToResolveSource = "MSG:UnableToResolveSource_NameOrLocation"; - public const string UnableToUninstallPackage = "MSG:UnableToUninstallPackage"; - public const string UnknownFolderId = "MSG:UnknownFolderId"; - public const string UnknownProvider = "MSG:UnknownProvider"; - public const string UnsupportedArchive = "MSG:UnsupportedArchive"; - public const string UnsupportedProviderType = "MSG:UnsupportedProviderType"; - public const string UriSchemeNotSupported = "MSG:UriSchemeNotSupported_Scheme"; - public const string UserDeclinedUntrustedPackageInstall = "MSG:UserDeclinedUntrustedPackageInstall"; - } - - public static partial class OptionType - { - public const string String = "String"; - public const string StringArray = "StringArray"; - public const string Int = "Int"; - public const string Switch = "Switch"; - public const string Folder = "Folder"; - public const string File = "File"; - public const string Path = "Path"; - public const string Uri = "Uri"; - public const string SecureString = "SecureString"; - } - - public static partial class PackageStatus - { - public const string Available = "Available"; - public const string Dependency = "Dependency"; - public const string Installed = "Installed"; - public const string Uninstalled = "Uninstalled"; - } - - public static partial class Parameters - { - public const string IsUpdate = "IsUpdatePackageSource"; - public const string Name = "Name"; - public const string Location = "Location"; - } - - public static partial class Signatures - { - public const string Cab = "4D534346"; - public const string OleCompoundDocument = "D0CF11E0A1B11AE1"; - public const string Zip = "504b0304"; - public static string[] ZipVariants = new[] { Zip, /* should have EXEs? */}; - } - - public static partial class SwidTag - { - public const string SoftwareIdentity = "SoftwareIdentity"; - } - - #endregion - } -} - diff --git a/Sdk/ErrorCategory.cs b/Sdk/ErrorCategory.cs deleted file mode 100644 index 46c7b46..0000000 --- a/Sdk/ErrorCategory.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace PackageManagement.Sdk -{ - public enum ErrorCategory - { - NotSpecified, - OpenError, - CloseError, - DeviceError, - DeadlockDetected, - InvalidArgument, - InvalidData, - InvalidOperation, - InvalidResult, - InvalidType, - MetadataError, - NotImplemented, - NotInstalled, - ObjectNotFound, - OperationStopped, - OperationTimeout, - SyntaxError, - ParserError, - PermissionDenied, - ResourceBusy, - ResourceExists, - ResourceUnavailable, - ReadError, - WriteError, - FromStdErr, - SecurityError, - ProtocolError, - ConnectionError, - AuthenticationError, - LimitsExceeded, - QuotaExceeded, - NotEnabled, - } -} - diff --git a/Sdk/Request.cs b/Sdk/Request.cs deleted file mode 100644 index 1e6db33..0000000 --- a/Sdk/Request.cs +++ /dev/null @@ -1,340 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -namespace PackageManagement.Sdk -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Security; - using Resources; - - public abstract class Request - { - private Dictionary _options; - private string[] _packageSources; - - #region PackageMangaement Interfaces - public interface IProviderServices - { - bool IsElevated { get; } - - IEnumerable FindPackageByCanonicalId(string canonicalId, Request requestObject); - - string GetCanonicalPackageId(string providerName, string packageName, string version, string source); - - string ParseProviderName(string canonicalPackageId); - - string ParsePackageName(string canonicalPackageId); - - string ParsePackageVersion(string canonicalPackageId); - - string ParsePackageSource(string canonicalPackageId); - - void DownloadFile(Uri remoteLocation, string localFilename, Request requestObject); - - bool IsSupportedArchive(string localFilename, Request requestObject); - - IEnumerable UnpackArchive(string localFilename, string destinationFolder, Request requestObject); - - bool Install(string fileName, string additionalArgs, Request requestObject); - - bool IsSignedAndTrusted(string filename, Request requestObject); - } - - public interface IPackageProvider - { - - } - - public interface IPackageManagementService - { - int Version { get; } - - IEnumerable ProviderNames { get; } - - IEnumerable AllProviderNames { get; } - - IEnumerable PackageProviders { get; } - - IEnumerable SelectProvidersWithFeature(string featureName); - - IEnumerable SelectProvidersWithFeature(string featureName, string value); - - IEnumerable SelectProviders(string providerName, Request requestObject); - - bool RequirePackageProvider(string requestor, string packageProviderName, string minimumVersion, Request requestObject); - } - #endregion - - #region core-apis - - public abstract dynamic PackageManagementService { get; } - - public abstract IProviderServices ProviderServices { get; } - - #endregion - - #region copy host-apis - - /* Synced/Generated code =================================================== */ - public abstract bool IsCanceled { get; } - - public abstract string GetMessageString(string messageText, string defaultText); - - public abstract bool Warning(string messageText); - - public abstract bool Error(string id, string category, string targetObjectValue, string messageText); - - public abstract bool Message(string messageText); - - public abstract bool Verbose(string messageText); - - public abstract bool Debug(string messageText); - - public abstract int StartProgress(int parentActivityId, string messageText); - - public abstract bool Progress(int activityId, int progressPercentage, string messageText); - - public abstract bool CompleteProgress(int activityId, bool isSuccessful); - - /// - /// Used by a provider to request what metadata keys were passed from the user - /// - /// - public abstract IEnumerable OptionKeys { get; } - - /// - /// - /// - /// - public abstract IEnumerable GetOptionValues(string key); - - public abstract IEnumerable Sources { get; } - - public abstract string CredentialUsername { get; } - - public abstract SecureString CredentialPassword { get; } - - public abstract bool ShouldBootstrapProvider(string requestor, string providerName, string providerVersion, string providerType, string location, string destination); - - public abstract bool ShouldContinueWithUntrustedPackageSource(string package, string packageSource); - - public abstract bool AskPermission(string permission); - - public abstract bool IsInteractive { get; } - - public abstract int CallCount { get; } - - #endregion - - #region copy response-apis - - /* Synced/Generated code =================================================== */ - - /// - /// Used by a provider to return fields for a SoftwareIdentity. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public abstract string YieldSoftwareIdentity(string fastPath, string name, string version, string versionScheme, string summary, string source, string searchKey, string fullPath, string packageFileName); - - public abstract string AddMetadata(string name, string value); - - public abstract string AddMetadata(string elementPath, string name, string value); - - public abstract string AddMetadata(string elementPath, Uri @namespace, string name, string value); - - public abstract string AddTagId(string tagId); - - public abstract string AddMeta(string elementPath); - - public abstract string AddEntity(string name, string regid, string role, string thumbprint); - - public abstract string AddLink(Uri referenceUri, string relationship, string mediaType, string ownership, string use, string appliesToMedia, string artifact); - - public abstract string AddDependency(string providerName, string packageName, string version, string source, string appliesTo); - - public abstract string AddPayload(); - - public abstract string AddEvidence(DateTime date, string deviceId); - - public abstract string AddDirectory(string elementPath, string directoryName, string location, string root, bool isKey); - - public abstract string AddFile(string elementPath, string fileName, string location, string root, bool isKey, long size, string version); - - public abstract string AddProcess(string elementPath, string processName, int pid); - - public abstract string AddResource(string elementPath, string type); - - /// - /// Used by a provider to return fields for a package source (repository) - /// - /// - /// - /// - /// - /// - /// - public abstract bool YieldPackageSource(string name, string location, bool isTrusted, bool isRegistered, bool isValidated); - - /// - /// Used by a provider to return the fields for a Metadata Definition - /// The cmdlets can use this to supply tab-completion for metadata to the user. - /// - /// the provider-defined name of the option - /// one of ['string','int','path','switch'] - /// if the parameter is mandatory - /// - public abstract bool YieldDynamicOption(string name, string expectedType, bool isRequired); - - public abstract bool YieldKeyValuePair(string key, string value); - - public abstract bool YieldValue(string value); - - #endregion - /// - /// Yield values in a dictionary as key/value pairs. (one pair for each value in each key) - /// - /// - /// - public bool Yield(Dictionary dictionary) - { - return dictionary.All(Yield); - } - - public bool Yield(KeyValuePair pair) - { - if (pair.Value.Length == 0) - { - return YieldKeyValuePair(pair.Key, null); - } - return pair.Value.All(each => YieldKeyValuePair(pair.Key, each)); - } - - public bool Error(ErrorCategory category, string targetObjectValue, string messageText, params object[] args) - { - return Error(messageText, category.ToString(), targetObjectValue, FormatMessageString(messageText, args)); - } - - public bool Warning(string messageText, params object[] args) - { - return Warning(FormatMessageString(messageText, args)); - } - - public bool Message(string messageText, params object[] args) - { - return Message(FormatMessageString(messageText, args)); - } - - public bool Verbose(string messageText, params object[] args) - { - return Verbose(FormatMessageString(messageText, args)); - } - - public bool Debug(string messageText, params object[] args) - { - return Debug(FormatMessageString(messageText, args)); - } - - public int StartProgress(int parentActivityId, string messageText, params object[] args) - { - return StartProgress(parentActivityId, FormatMessageString(messageText, args)); - } - - public bool Progress(int activityId, int progressPercentage, string messageText, params object[] args) - { - return Progress(activityId, progressPercentage, FormatMessageString(messageText, args)); - } - - public string GetOptionValue(string name) - { - // get the value from the request - return (GetOptionValues(name) ?? Enumerable.Empty()).LastOrDefault(); - } - - private static string FixMeFormat(string formatString, object[] args) - { - if (args == null || args.Length == 0) - { - // not really any args, and not really expectng any - return formatString.Replace('{', '\u00ab').Replace('}', '\u00bb'); - } - return args.Aggregate(formatString.Replace('{', '\u00ab').Replace('}', '\u00bb'), (current, arg) => current + string.Format(CultureInfo.CurrentCulture, " \u00ab{0}\u00bb", arg)); - } - - internal string GetMessageStringInternal(string messageText) - { - return Messages.ResourceManager.GetString(messageText); - } - - internal string FormatMessageString(string messageText, params object[] args) - { - if (string.IsNullOrEmpty(messageText)) - { - return string.Empty; - } - - if (args == null) - { - return messageText; - } - - if (messageText.StartsWith(Constants.MSGPrefix, true, CultureInfo.CurrentCulture)) - { - // check with the caller first, then with the local resources, and fall back to using the messageText itself. - messageText = GetMessageString(messageText.Substring(Constants.MSGPrefix.Length), GetMessageStringInternal(messageText) ?? messageText) ?? GetMessageStringInternal(messageText) ?? messageText; - } - - // if it doesn't look like we have the correct number of parameters - // let's return a fix-me-format string. - var c = messageText.ToCharArray().Where(each => each == '{').Count(); - if (c < args.Length) - { - return FixMeFormat(messageText, args); - } - return string.Format(CultureInfo.CurrentCulture, messageText, args); - } - - public bool YieldDynamicOption(string name, string expectedType, bool isRequired, IEnumerable permittedValues) - { - return YieldDynamicOption(name, expectedType, isRequired) && (permittedValues ?? Enumerable.Empty()).All(each => YieldKeyValuePair(name, each)); - } - - public Dictionary Options - { - get - { - return _options ?? (_options = OptionKeys.Where(each => !string.IsNullOrWhiteSpace(each)).ToDictionary(k => k, (k) => (GetOptionValues(k) ?? new string[0]).ToArray())); - } - } - - public IEnumerable PackageSources - { - get - { - return _packageSources ?? (_packageSources = (Sources ?? new string[0]).ToArray()); - } - } - } -} diff --git a/TestPackage/TestPackage.nuspec b/TestPackage/TestPackage.nuspec new file mode 100644 index 0000000..f393d5f --- /dev/null +++ b/TestPackage/TestPackage.nuspec @@ -0,0 +1,14 @@ + + + + TestPackage + 1.0.1 + TestPackage + TestPackage + TestPackage for Chocolatey oneget package provider + TagA TagB + + + + + diff --git a/TestPackage/tools/chocolateyinstall.ps1 b/TestPackage/tools/chocolateyinstall.ps1 new file mode 100644 index 0000000..72988de --- /dev/null +++ b/TestPackage/tools/chocolateyinstall.ps1 @@ -0,0 +1,6 @@ +# Only output the used package parameters to text file +$packageArgs = Get-PackageParameters +$toReportDir = "$env:ChocolateyInstall\lib\TestPackage" +New-Item -Type Directory $toReportDir -ErrorAction SilentlyContinue | Out-Null +$installLog = "$toReportDir\UsedParams.txt" +$packageArgs | ConvertTo-Json | Out-File $installLog \ No newline at end of file diff --git a/TestPackage/tools/chocolateyuninstall.ps1 b/TestPackage/tools/chocolateyuninstall.ps1 new file mode 100644 index 0000000..0b0c1fb --- /dev/null +++ b/TestPackage/tools/chocolateyuninstall.ps1 @@ -0,0 +1,2 @@ +$installLog = "$env:ChocolateyInstall\lib\TestPackage\UsedParams.txt" +Remove-Item $installLog -ErrorAction SilentlyContinue | Out-Null \ No newline at end of file diff --git a/Tests/Module.Tests.ps1 b/Tests/Module.Tests.ps1 new file mode 100644 index 0000000..edd8beb --- /dev/null +++ b/Tests/Module.Tests.ps1 @@ -0,0 +1,19 @@ +. $PSScriptRoot\TestHelpers.ps1 + +Describe "Imported module" { + $provider = Get-PackageProvider -Name $chocolateyOneGet + + It "is loaded as PackageProvider" { + $provider | Should -Not -be $null + } + + It "supports '.nupkg' file extension" { + $extensions = $provider.features["file-extensions"] + $extensions | Should -Contain ".nupkg" + } + + It "supports 'http', 'https' and 'file' repository location types" { + $extensions = $provider.features["uri-schemes"] + $extensions | Should -Be "http https file" + } +} diff --git a/Tests/Package.Tests.ps1 b/Tests/Package.Tests.ps1 new file mode 100644 index 0000000..b11cd86 --- /dev/null +++ b/Tests/Package.Tests.ps1 @@ -0,0 +1,234 @@ +. $PSScriptRoot\TestHelpers.ps1 + +Describe "Find package" { + BeforeAll { + Clean-Sources + Register-TestPackageSources + } + + AfterAll { + Clean-Sources + } + + It "finds package in Source" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Source $expectedSourceName + $packagesUri = (New-Object "System.Uri" $testPackagesPath).AbsolutePath + $found.FastPackageReference | Should -Be "TestPackage|#|1.0.3|#|$packagesUri" + } + + It "finds package from all sources" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet + $found.Count | Should -Be 1 + } + + It "finds package by tags" { + $found = Find-Package -ProviderName $chocolateyOneGet -Tag @("TagC", "TagA") + $found.Count | Should -Be 1 + } + + It "finds all package versions" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet -AllVersions + $found.Count | Should -Be 3 + } + + It "finds prerelease versions" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet -PrereleaseVersions + $found.Version | Should -Be $prereleaseVersion + } + + It "finds package by required version" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet -RequiredVersion $previousVersion + $found.Version | Should -Be $previousVersion + } + + It "finds package by min. version" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet -AllVersions -MinimumVersion $previousVersion + $resolvedVersion = $found[$found.length - 1].Version + $resolvedVersion | Should -Be $previousVersion + } + + It "finds package by max. version" { + $found = Find-Package -Name $testPackageName -ProviderName $chocolateyOneGet -MaximumVersion $previousVersion + $found.Version | Should -Be $previousVersion + } +} + +Describe "Install package" { + BeforeAll { + Clean-Sources + Register-TestPackageSources + } + + BeforeEach { + Uninstall-TestPackage + } + + AfterEach { + Uninstall-TestPackage + } + + AfterAll { + Clean-Sources + Uninstall-TestPackage + } + + $latest = Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force + $installedInChoco = Find-InstalledTestPackage + + It "installs latest version" { + $installedInChoco | Should -Be "TestPackage $latestVersion" + } + + It "reports installed package" { + $latest.Version | Should -Be $latestVersion + } + + It "installs correct version" { + Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -RequiredVersion $previousVersion + Find-InstalledTestPackage | Should -Be "TestPackage $previousVersion" + } + + It "installs from correct source" { + $installed = Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -Source $expectedSourceName + $installed.Source -replace '/',"\" | Should -Be $testPackagesPath + } + + It "installs prerelease version" { + $installed = Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -PrereleaseVersions + $installed.Version | Should -Be $prereleaseVersion + } + + It "installs multiple versions side by side" { + Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -RequiredVersion $previousVersion -AllowMultipleVersions + Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -AllowMultipleVersions + $installed = Find-InstalledTestPackage | Sort-Object + $installed | Should -Be @("TestPackage $previousVersion", "TestPackage $latestVersion") + } + + It "uses package custom arguments" { + Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -PackageParameters '/customA:""Path spaced"" /customB:""value""' + $installLog = "$env:ChocolateyInstall\lib\TestPackage\UsedParams.txt" + + $expected = ConvertFrom-Json '{ "customA": "\"Path spaced\"", "customB": "\"value\"" }' + $installed = ConvertFrom-Json (-Join (Get-Content $installLog)) + $resultsEqual = $expected.custom -eq $installed.custom -and $expected.other -eq $installed.other + $resultsEqual | Should -Be $true + } + + It "upgrades package" { + Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -RequiredVersion $previousVersion + Install-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force ` + -Upgrade + + Find-InstalledTestPackage | Should -Be "TestPackage $latestVersion" + } +} + +Describe "Get installed package" { + BeforeAll { + Clean-Sources + Register-TestPackageSources + Install-TestPackages + } + + AfterAll { + Uninstall-TestPackage + Clean-Sources + } + + It "finds all installed package versions" { + $found = Get-Package -Name $testPackageName -ProviderName $chocolateyOneGet -AllVersions -Force + $found.Count | Should -Be 3 + } + + It "finds installed package by name" { + $found = Get-Package -Name $testPackageName -ProviderName $chocolateyOneGet -Force + $found.Name | Should -Be $testPackageName + } + + It "finds required package version" { + $found = Get-Package -Name $testPackageName -ProviderName $chocolateyOneGet -RequiredVersion $previousVersion + $found.Version | Should -Be $previousVersion + } + + It "finds by minimum version number" { + # allversions switch cant be used here, so we test latest available + $found = Get-Package -Name $testPackageName -ProviderName $chocolateyOneGet -MinimumVersion $prereleaseVersion + $found.Version | Should -Be $prereleaseVersion + } + + It "finds by maximum version number" { + $found = Get-Package -Name $testPackageName -ProviderName $chocolateyOneGet -MaximumVersion $previousVersion + $found.Version | Should -Be $previousVersion + } +} + +Describe "Uninstall package" { + BeforeAll { + Clean-Sources + Register-TestPackageSources + Install-TestPackages + } + + AfterAll { + Uninstall-TestPackage + Clean-Sources + } + + $removed = Uninstall-Package -Name $testPackageName -ProviderName $chocolateyOneGet -RequiredVersion $latestVersion + + It "reports removed package name" { + $removed.Name | Should -Be $testPackageName + } + + It "reports removed package version" { + $removed.Version | Should -Be $latestVersion + } + + It "removes package from chocolatey" { + $installed = Find-InstalledTestPackage | Sort-Object + $installed | Should -Be @("TestPackage $previousVersion", "TestPackage $prereleaseVersion") + } + + It "removes all versions" { + Install-TestPackages + Uninstall-Package -Name $testPackageName -ProviderName $chocolateyOneGet -AllVersions + $installed = Find-InstalledTestPackage + $installed | Should -Be $null + } +} + + +Describe "Download package" { + $downLoadDirectory = "$PSScriptRoot\..\Build\Output\Downloaded\" + + BeforeEach { + Remove-Item $downLoadDirectory -Recurse -Force -ErrorAction Ignore + } + BeforeAll { + Clean-Sources + Register-TestPackageSources + } + + AfterAll { + Clean-Sources + } + + It "copies from local path" { + # Example paths: + # web: "https://chocolatey.org/api/v2/package/chocolatey/0.10.11" + # local "c:\Workspace\Build\Output\TestPackages\TestPackage.1.0.1.nupkg" + # unc "\\localhost\c$\Workspaces\Chocolatey-OneGet_GitHub\Build\Output\TestPackages\TestPackage.1.0.1.nupkg" + + Save-Package -ProviderName $chocolateyOneGet -Name $testPackageName -Path $downLoadDirectory -Force + $outputFile = Join-Path $downLoadDirectory "testPackage.1.0.3.nupkg" + $outputFile | Should -Exist + } +} \ No newline at end of file diff --git a/Tests/Source.Tests.ps1 b/Tests/Source.Tests.ps1 new file mode 100644 index 0000000..822bf8f --- /dev/null +++ b/Tests/Source.Tests.ps1 @@ -0,0 +1,107 @@ +. $PSScriptRoot\TestHelpers.ps1 + +Describe "Add packages source" { + BeforeAll { + Clean-Sources + } + + AfterAll { + Clean-Sources + } + + Register-TestPackageSources + + $registeredSource = Get-ChocolateySource + + It "is saved in choco" { + $registeredSource | Should -Not -Be $Null + } + + It "saves Priority" { + $registeredSource | Should -Match "Priority 10" + } + + It "saves BypassProxy" { + $registeredSource | Should -Match "Bypass Proxy - True" + } + + It "saves AllowSelfService" { + $registeredSource | Should -Match "Self-Service - True" + } + + # Requires business edition + It "saves VisibleToAdminsOnly" -Skip { + $registeredSource | Should -Match "Admin Only - True" + } + + # Not possible to test user name value was set propertly this way + It "saves user credential properties" { + $registeredSource | Should -Match "(Authenticated)" + } + + It "saves user certificate properties" { + $certificateSource = choco source list | Where-Object { $_.Contains($expectedCertificateSource)} + $certificateSource | Should -Match "(Authenticated)" + } +} + +Describe "Get package sources" { + BeforeAll { + Clean-Sources + Register-TestPackageSources + } + + AfterAll { + Clean-Sources + } + + It "lists all registered sources" { + $registeredSources = Get-PackageSource -ProviderName $chocolateyOneGet + $resolved = $registeredSources | Where-Object { $_.Name -eq $expectedSourceName } + $resolved -ne $Null -and $registeredSources.Count -ge 2 | Should -Be $True + } + + It "lists only sources by wildcard" { + $filteredSources = Get-PackageSource -ProviderName $chocolateyOneGet "*Certificate*" + $resolved = $filteredSources | Where-Object { $_.Name -eq $expectedCertificateSource } + $resolved.Name | Should -Be $expectedCertificateSource + } + + It "lists only sources by name parameter" { + $filteredSources = Get-PackageSource -ProviderName $chocolateyOneGet -Name "*Certificate*" + $resolved = $filteredSources | Where-Object { $_.Name -eq $expectedCertificateSource } + $resolved.Name | Should -Be $expectedCertificateSource + } + + It "lists sources by exact location value" { + $byPathSource = Get-PackageSource -ProviderName $chocolateyOneGet -Location $testPackagesPathWrong + $byPathSource.Name | Should -Be $expectedCertificateSource + } + + $byPathSource = Get-PackageSource -ProviderName $chocolateyOneGet -Location $PSScriptRoot + + It "not registered location returns source by its location" { + $byPathSource.Location | Should -Be $PSScriptRoot + } + + It "not registered location returns not registered source" { + $byPathSource.IsRegistered | Should -Be $false + } +} + +Describe "Unregister package source" { + BeforeAll { + Clean-Sources + Register-TestPackageSources + } + + AfterAll { + Clean-Sources + } + + It "is removed" { + Unregister-PackageSource -ProviderName $chocolateyOneGet -Name $expectedSourceName + $registeredSource = Get-ChocolateySource + $registeredSource | Should -Be $Null + } +} diff --git a/Tests/TestHelpers.ps1 b/Tests/TestHelpers.ps1 new file mode 100644 index 0000000..7c875e4 --- /dev/null +++ b/Tests/TestHelpers.ps1 @@ -0,0 +1,54 @@ +$chocolateyOneGet = "Chocolatey-OneGet" +$expectedSourceName = "Chocolatey-TestScriptRoot" +$expectedCertificateSource = "Chocolatey-CertificateTestScriptRoot" +$testPackageName = "TestPackage" +$previousVersion = "1.0.2" +$latestVersion = "1.0.3" +$prereleaseVersion = "1.1.0-beta1" + +$testPackagesPath = Join-Path $PSScriptRoot "..\Build\Output\TestPackages" +$testPackagesPath = $(Resolve-Path $testPackagesPath).Path +$testPackagesPathWrong = "$testPackagesPath-Wrong" + +# If import failed, chocolatey.dll is locked and is necessary to reload powershell +# Import-PackageProvider $chocolateyOneGet -force + +function Get-ChocolateySource(){ + return choco source list | Where-Object { $_.Contains($expectedSourceName)} +} + +function Clean-Sources (){ + Invoke-Expression "choco source remove -n=$expectedSourceName" + Invoke-Expression "choco source remove -n=$expectedCertificateSource" + # because chocolatey.dll is unable to reload config file, we need to clean up manually + UnRegister-PackageSource -ProviderName $chocolateyOneGet -Name $expectedSourceName -ErrorAction SilentlyContinue | Out-Null + Unregister-PackageSource -ProviderName $chocolateyOneGet -Name $expectedCertificateSource -ErrorAction SilentlyContinue | Out-Null +} + +function Register-TestPackageSources(){ + $userPassword = "UserPassword" | ConvertTo-SecureString -AsPlainText -Force + $credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist "UserName", $userPassword + + Register-PackageSource -ProviderName $chocolateyOneGet -Name $expectedSourceName -Location $testPackagesPath ` + -Priority 10 -BypassProxy -AllowSelfService -VisibleToAdminsOnly ` + -Credential $credentials + + Register-PackageSource -ProviderName $chocolateyOneGet -Name $expectedCertificateSource -Location $testPackagesPathWrong ` + -Certificate "testCertificate" -CertificatePassword "testCertificatePassword" +} + +function Uninstall-TestPackage(){ + # requires atleast one package source + Invoke-Expression "choco uninstall $testPackageName --all-versions --yes --force" +} + +function Install-TestPackages(){ + # requires atleast one package source + Invoke-Expression "choco install $testPackageName --version $previousVersion --yes --allow-multiple-versions --force" + Invoke-Expression "choco install $testPackageName --version $latestVersion --yes --allow-multiple-versions --force" + Invoke-Expression "choco install $testPackageName --version $prereleaseVersion --prerelease --yes --allow-multiple-versions --force" +} + +function Find-InstalledTestPackage() { + return choco list -localonly --allversions | findstr $testPackageName +} \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..6b72b7b --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,25 @@ +# Provider development + +## Prerequisities + +* Recommended development environnement is visual Studio Code with PowerShell extension +* Run ```build/prepareEnvironment.ps1``` script to install all tools used for provider development, it installs used tools +* Used tools: + * Pester - powershell testing framework + * PackageManagement - Required dependency, we develop its plugin + * Chocolatey - chocolatey library API + * Paket - dependencies nuget packages downloader + +## Development + +* Build: Run ```build\build.ps1``` +* Outcome is stored in ```Build\Output``` +* Use "Invoke-Psake Publish" from build directory to publish into PsGet online repository + +## Debugging + +* If you are unable to import the module, restart powershell, maybe the chocolatey.dll is in use by the process +* From Visual studio Code with powershell extension, you can launch the predefined tasks. Keep in mind to kill the terminal to be able restart debugging +* When debugging tests, breakpoint in the module script wouldnt hit directly, stop on break point in the test, then manually step into the provider method. After that breakpoint inside the provider should hit. +* To run only selected test add wildcard filter into the $testFilter parameter in psakeFile.ps1 +* See also [OneGet debugging](https://github.com/OneGet/oneget/blob/WIP/docs/writepowershellbasedprovider.md#debugging-your-provider) \ No newline at end of file diff --git a/docs/howto.md b/docs/howto.md new file mode 100644 index 0000000..d3362f9 --- /dev/null +++ b/docs/howto.md @@ -0,0 +1,166 @@ +# How to use Chocolatey-OneGet provider + +## 1. Install the module + +> **NOTE:** This module requires chocolatey application to be installed. + +To install the provider follow one of these scenarios + +### Online install + +You can install the module directly from PowershellGet online repository: + +```powershell +Import-Module -Name PackageManagement +Install-Module -Name Chocolatey-OneGet +Import-Module Chocolatey-OneGet +Import-PackageProvider -Name Chocolatey-OneGet +``` + +### Offline install + +1. Download chocolatey package from https://chocolatey.org/packages/chocolatey +2. Download Chocolatey-OneGet provider package from ```TODO add link``` +3. Execute following script from current directory, where the downloaded files reside + +```powershell +Copy-Item .\chocolatey.0.10.9.nupkg chocolatey.0.10.9.zip +Expand-Archive .\chocolatey.0.10.9.zip +.\chocolatey.0.10.9\tools\chocolateyInstall.ps1 +Register-PackageSource -ProviderName PowerShellGet -Name Downloaded -Location $pwd +Install-Package chocolatey-oneget -Source Downloaded +Unregister-PackageSource -ProviderName PowerShellGet Downloaded +Import-Module Chocolatey-OneGet +Import-PackageProvider -Name Chocolatey-OneGet +``` + +> **NOTE:** If chocolatey is already installed, it is enough to copy the provider directory to your modules folder (usually "$HOME\Documents\WindowsPowerShell\Modules\"). + +To verify the provider is available: + +```powershell +Get-PackageProvider -Name Chocolatey-OneGet +``` + +## 2. Register package source + +To register chocolatey source you need path (can be local path or http url) and name for the new source. + +```powershell +$sourceName = "LocalProvider" +$sourceLocation = "C:\LocalChocolateyPackages" +Register-PackageSource -ProviderName Chocolatey-OneGet -Name $sourceName -Location $sourceLocation +``` + +Register package source supports all other options you can use from chocolatey command line. All options to register package source are optional. How to use the dynamic options see related documentation. Following example shows how to use the extra parameters. + +```powershell +Register-PackageSource -ProviderName $chocolateyOneGet -Name $sourceName -Location $sourceLocation ` + -Priority 10 -BypassProxy -AllowSelfService -VisibleToAdminsOnly +``` + +> **NOTE:** All additional parameters used in this provider follow the chocolatey command line options, so for more details about their values usage, refer directly to [chocolatey documentation](https://github.com/chocolatey/choco/wiki/CommandsReference). + +If your package source needs authenticate you can use credentials powershell object (as standard One-Get parameter) or certificate via additional parameters. Both have the same behavior like chocolatey command line. + +```powershell +$credentials = Get-Credential +Register-PackageSource -ProviderName Chocolatey-OneGet -Name $sourceName -Location $sourceLocation -Credential $credentials +``` + +or if your source needs certificate based authentication + +```powershell +$certificate = "C:\Users\bob\Documents\bob.pfx" +$certificatePassword = "CertitificatePassword" +Register-PackageSource -ProviderName Chocolatey-OneGet -Name $sourceName -Location $sourceLocation -Certificate $certificate -CertificatePassword $certificatePassword +``` + +## 3. List registered package sources + +By default chocolatey installs default package source. When you install this provider only, no package source is added by default. Purpose for this is enterprise environment, where companies want to use their local package source only. Wildcards are supported in source names. When no filter is provided all sources are returned. +To see all already registered package sources + +```powershell +$filter = "*Company*" +Get-PackageSource -ProviderName Chocolatey-OneGet $filter +``` + +## 4. Unregister package source + +To remove package source, you only need to know the source name. Package source can be simply removed by + +```powershell +Unregister-PackageSource -ProviderName Chocolatey-OneGet -Name $sourceName +``` + +## 5. Find package + +To find package to be installed you have multiple options. The main difference when comparing to chocolatey command is usage of tags. Se following examples + +```powershell +$packageName = "git" +# Find latest version of package by name or description in one source +Find-Package -Name $packageName -ProviderName Chocolatey-OneGet -Source $sourceName +# Find package by name or description in all sources +Find-Package -Name $packageName -ProviderName Chocolatey-OneGet +# Find all packages containing one of these tags +Find-Package -ProviderName Chocolatey-OneGet -Tag @("TagC", "TagA") +# Find all versions of package +Find-Package -Name $packageName -ProviderName Chocolatey-OneGet -AllVersions +# Find latest version of package including prerelease versions +Find-Package -Name $packageName -ProviderName Chocolatey-OneGet -PrereleaseVersions +# search for exact version (similar usage by -MinimumVersion or -MaximumVersion) +Find-Package -Name $packageName -ProviderName Chocolatey-OneGet -RequiredVersion 2.18.0 +``` + +## 6. Install package + +Because of wide range of chocolatey install arguments not all arguments are supported. Also keep in mind to [escape custom package parameters](https://github.com/chocolatey/choco/wiki/CommandsReference#how-to-pass-options--switches). See following examples + +```powershell +# install latest version of package available on any registered compatible source +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet +# install required version +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet -RequiredVersion 2.18.0 +# install from required source +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet -Source $sourceName +# install prerelease version +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet -PrereleaseVersions +# install multiple versions side by side +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet -AllowMultipleVersions +# install using custom package arguments +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet -PackageParameters '/customA:""Path spaced"" /customB:""value""' +# upgrade package +Install-Package -Name $packageName -ProviderName Chocolatey-OneGet -Upgrade +``` + +## 7. Get installed package + +To search for installed package is similar to searching for package in remote source by `Find-Package`. See examples + + > **NOTE:** Switch `-AllVersions` can't be used together with `-RequiredVersion` `-MinimumVersion` or `-MaximumVersion` + +```powershell +# list all installed packages (only latest version per package) +Get-Package -ProviderName Chocolatey-OneGet +#find installed package by name +Get-Package -Name $packageName -ProviderName Chocolatey-OneGet +# find all installed package versions +Get-Package -Name $packageName -ProviderName Chocolatey-OneGet -AllVersions +# find required package version (similar usage by -MinimumVersion or -MaximumVersion) +Get-Package -Name $packageName -ProviderName Chocolatey-OneGet -RequiredVersion 2.18.0 +``` + +## 8. Uninstall package + +If no version is provided and multiple versions are installed, only latest version is uninstalled. To uninstall all versions of the package use `-AllVersions` switch. + +```powershell +# remove only latest version +Uninstall-Package -Name $packageName -ProviderName Chocolatey-OneGet +# remove concrete version only +Uninstall-Package -Name $packageName -ProviderName Chocolatey-OneGet -RequiredVersion 2.18.0 +# remove all versions +Uninstall-Package -Name $packageName -ProviderName Chocolatey-OneGet -AllVersions +``` \ No newline at end of file diff --git a/install-provider.ps1 b/install-provider.ps1 deleted file mode 100644 index ee4b3de..0000000 --- a/install-provider.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -#.Synopsis -# Copy the provider assembly to LocalAppData -#.Description -# By default it will find the newest .*Provider.dll and copy it to the right location -# You can also specify the build name (e.g. 'debug' or 'release') to use. -[CmdletBinding()] -param( - # If specified, force to use the output in a specific build folder - [string]$build = '', - [string]$providerName = 'ChocolateyProvider', - # How many levels UP to check for output folders (defaults to 2) - $depth = 2 -) - -Push-Location $PSScriptRoot - - -while($depth-- -gt 0) { - Write-Verbose "Searching '$pwd' for '${providerName}.dll'" - $candidates = Get-ChildItem -Recurse -Filter "${providerName}.dll" | - Where-Object { $_.FullName -match "\\output\\" } - Sort-Object -Descending -Property LastWriteTime - - if( $build ) { - $candidates = $candidates | Where-Object { $_.FullName -match $build } - } - - $provider = $candidates | Select-Object -First 1 - if( -not $provider ) { - cd .. - } -} - -if( -not $provider ) { - Write-Error "Can't find assembly '${providerName}.dll' under '$Pwd' with '\output\' and '$build' somewhere in the path`n" - Pop-Location - return -} - -$srcpath = $provider.Fullname -$filename = $provider.Name - -$output = "${Env:LocalAppData}\PackageManagement\providerassemblies\$fileName" - -if(Test-Path $output) { - Write-Warning "Found existing provider. Deleting `n '$output' `n" - # delete the old provider assembly - # even if it's in use. - $tmpName = "$filename.delete-me.$(get-random)" - $tmpPath = "$env:localappdata\PackageManagement\providerassemblies\$tmpName" - - Rename-Item $output $tmpName -force -ea SilentlyContinue - Remove-Item -force -ea SilentlyContinue $tmpPath - if(Test-Path $tmpPath) { - # locked. Move to temp folder - Write-Warning "Old provider is in use, moving to `n '$env:TEMP' folder `n However, you must restart any processes using it!" - Move-Item $tmpPath $env:TEMP - } - - if(Test-Path $output) { - Write-Error "Cannot remove existing provider file: `n $output `n" - Pop-Location - return - } - -} - -Write-Host "Copying provider `nFrom: '$srcPath'`nTo: '$output' `n" - -Copy-Item -force $srcPath $output - -Pop-Location diff --git a/packages.config b/packages.config deleted file mode 100644 index 98e8b13..0000000 --- a/packages.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/paket.dependencies b/paket.dependencies new file mode 100644 index 0000000..ab746a3 --- /dev/null +++ b/paket.dependencies @@ -0,0 +1,4 @@ +source https://www.nuget.org/api/v2 + +nuget chocolatey.lib +nuget log4net == 2.0.3 \ No newline at end of file diff --git a/paket.lock b/paket.lock new file mode 100644 index 0000000..f8d0984 --- /dev/null +++ b/paket.lock @@ -0,0 +1,5 @@ +NUGET + remote: https://www.nuget.org/api/v2 + chocolatey.lib (0.10.11) + log4net (>= 2.0.3) + log4net (2.0.3) diff --git a/provider.manifest b/provider.manifest deleted file mode 100644 index 49d5918..0000000 --- a/provider.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - -