Skip to content

Commit af15503

Browse files
Uploading files to org project
1 parent d3b1dee commit af15503

File tree

10 files changed

+569
-1
lines changed

10 files changed

+569
-1
lines changed

.github/workflows/CI.yml

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# This is a basic workflow to help you get started with Actions
2+
3+
name: CI
4+
5+
on:
6+
push:
7+
branches: [ main ]
8+
pull_request:
9+
branches: [ main ]
10+
release:
11+
types: [ published ]
12+
13+
jobs:
14+
Build:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout Repository
18+
uses: actions/checkout@v3
19+
- name: Bundle up module
20+
uses: actions/upload-artifact@v3
21+
with:
22+
name: module
23+
path: ./src/
24+
Test:
25+
needs: Build
26+
runs-on: windows-latest
27+
steps:
28+
- name: Checkout Repository
29+
uses: actions/checkout@v3
30+
- name: Download module
31+
uses: actions/download-artifact@v3
32+
with:
33+
name: module
34+
path: C:\Users\runneradmin\Documents\PowerShell\Modules\AnyPackage.Chocolatey\
35+
- name: Install Foil
36+
run: Install-Module Foil -Force
37+
- name: Install AnyPackage
38+
run: Install-Module AnyPackage -Force -AllowClobber
39+
- name: Test with Pester
40+
run: |
41+
Invoke-Pester -Configuration (New-PesterConfiguration -Hashtable @{
42+
Run = @{
43+
Exit = $true
44+
}
45+
Output = @{
46+
Verbosity = 'Detailed'
47+
}
48+
})
49+
- name: Upload Chocolatey logs
50+
if: always()
51+
uses: actions/upload-artifact@v3
52+
with:
53+
name: Chocolatey-logs
54+
path: C:\ProgramData\chocolatey\logs\
55+
Publish:
56+
needs: Test
57+
if: github.event_name == 'release' && github.event.action == 'published'
58+
runs-on: ubuntu-latest
59+
steps:
60+
- name: Download module
61+
uses: actions/download-artifact@v3
62+
with:
63+
name: module
64+
path: '~/.local/share/powershell/Modules/AnyPackage.Chocolatey'
65+
- name: Install Foil
66+
shell: pwsh
67+
run: Install-Module Foil -Force
68+
- name: Install AnyPackage
69+
shell: pwsh
70+
run: Install-Module AnyPackage -Force -AllowClobber
71+
- name: Publish Module
72+
env:
73+
NUGET_KEY: ${{ secrets.NUGET_KEY }}
74+
shell: pwsh
75+
run: Write-Output "Publishing..."; Publish-Module -Name AnyPackage.Chocolatey -NuGetApiKey $env:NUGET_KEY

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [0.0.1] - 2023-01-21
8+
Initial release

README.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,56 @@
11
# AnyPackage.Chocolatey
2-
Chocolatey provider for AnyPackage
2+
AnyPackage.Chocolatey is an AnyPackage provider that facilitates installing Chocolatey packages from any NuGet repository.
3+
4+
## Install AnyPackage.Chocolatey
5+
```PowerShell
6+
Install-Module AnyPackage.Chocolatey -Force
7+
```
8+
9+
# Importing AnyPackage.Chocolatey
10+
```PowerShell
11+
Import-Module AnyPackage.Chocolatey
12+
```
13+
14+
## Sample usages
15+
16+
### Search for a package
17+
```PowerShell
18+
Find-Package -Name nodejs
19+
20+
Find-Package -Name firefox*
21+
```
22+
23+
### Install a package
24+
```PowerShell
25+
Find-Package nodejs | Install-Package
26+
27+
Install-Package -Name 7zip
28+
```
29+
30+
### Get list of installed packages
31+
```PowerShell
32+
Get-Package nodejs
33+
```
34+
35+
### Uninstall a package
36+
```PowerShell
37+
Get-Package keepass-plugin-winhello | Uninstall-Package
38+
```
39+
40+
### Manage package sources
41+
```PowerShell
42+
Register-PackageSource privateRepo -Location 'https://somewhere/out/there/api/v2/'
43+
Find-Package nodejs -Source privateRepo | Install-Package
44+
Unregister-PackageSource privateRepo
45+
```
46+
AnyPackage.Chocolatey integrates with Choco.exe to manage and store source information
47+
48+
## Known Issues
49+
### Compatibility
50+
AnyPackage.Chocolatey works with PowerShell for both FullCLR/'Desktop' (ex 5.1) and CoreCLR (ex: 7.0.1), though Chocolatey itself still requires FullCLR.
51+
52+
### Save a package
53+
Save-Package is not supported with the AnyPackage.Chocolatey provider, due to Chocolatey not supporting package downloads without special licensing.
54+
55+
## Legal and Licensing
56+
AnyPackage.Chocolatey is licensed under the [MIT license](./LICENSE.txt).

src/AnyPackage.Chocolatey.psd1

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@{
2+
RootModule = 'AnyPackage.Chocolatey.psm1'
3+
ModuleVersion = '0.0.1'
4+
GUID = '070f2b8f-c7db-4566-9296-2f7cc9146bf0'
5+
Author = 'Ethan Bergstrom'
6+
Copyright = '2023'
7+
Description = 'AnyPackage provider that facilitates installing Chocolatey packages from any NuGet repository.'
8+
PowerShellVersion = '5.1'
9+
RequiredModules = @(
10+
@{
11+
ModuleName = 'AnyPackage'
12+
ModuleVersion = '0.1.0'
13+
},
14+
@{
15+
ModuleName = 'Foil'
16+
ModuleVersion = '0.1.0'
17+
}
18+
)
19+
PrivateData = @{
20+
AnyPackageProviders = 'AnyPackage.Chocolatey.psm1'
21+
PSData = @{
22+
# Tags applied to this module to indicate this is a AnyPackage Provider.
23+
Tags = @('AnyPackage','Provider','Chocolatey','PSEdition_Desktop','PSEdition_Core','Windows')
24+
25+
# A URL to the license for this module.
26+
LicenseUri = 'https://github.com/PowerShell/PowerShell/blob/master/LICENSE.txt'
27+
28+
# A URL to the main website for this project.
29+
ProjectUri = 'https://github.com/AnyPackage/AnyPackage.Chocolatey'
30+
31+
# ReleaseNotes of this module
32+
ReleaseNotes = 'This is a PowerShell AnyPackage provider. It is a wrapper on top of Choco.
33+
It discovers Chocolatey packages from https://www.chocolatey.org and other NuGet repos.'
34+
}
35+
}
36+
}

src/AnyPackage.Chocolatey.psm1

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using module AnyPackage
2+
using namespace AnyPackage.Provider
3+
4+
# Current script path
5+
[string]$ScriptPath = Split-Path (Get-Variable MyInvocation -Scope Script).Value.MyCommand.Definition -Parent
6+
7+
# Dot sourcing private script files
8+
Get-ChildItem $ScriptPath/private -Recurse -Filter '*.ps1' -File | ForEach-Object {
9+
. $_.FullName
10+
}
11+
12+
class InstallPackageDynamicParameters {
13+
[Parameter()]
14+
[switch]
15+
$ParamsGlobal = $false
16+
17+
[Parameter()]
18+
[string]
19+
$Parameters
20+
}
21+
22+
class UninstallPackageDynamicParameters {
23+
[Parameter()]
24+
[switch]
25+
$RemoveDependencies = $false
26+
}
27+
28+
[PackageProvider("Chocolatey")]
29+
class ChocolateyProvider : PackageProvider, IGetSource, ISetSource, IGetPackage, IFindPackage, IInstallPackage, IUninstallPackage {
30+
ChocolateyProvider() : base('070f2b8f-c7db-4566-9296-2f7cc9146bf0') { }
31+
32+
[object] GetDynamicParameters([string] $commandName) {
33+
return $(switch ($commandName) {
34+
'Install-Package' {[InstallPackageDynamicParameters]::new()}
35+
'Uninstall-Package' {[UninstallPackageDynamicParameters]::new()}
36+
Default {$null}
37+
})
38+
}
39+
40+
[void] GetSource([SourceRequest] $Request) {
41+
Foil\Get-ChocoSource | Where-Object {$_.Disabled -eq 'False'} | Where-Object {$_.Name -Like $Request.Name} | ForEach-Object {
42+
$Request.WriteSource($_.Name, $_.Location, $true)
43+
}
44+
}
45+
46+
[void] RegisterSource([SourceRequest] $Request) {
47+
Foil\Register-ChocoSource -Name $Request.Name -Location $Request.Location
48+
# Choco doesn't return anything after source operations, so we make up our own output object
49+
$Request.WriteSource($Request.Name, $Request.Location.TrimEnd("\"), $Request.Trusted)
50+
}
51+
52+
[void] UnregisterSource([SourceRequest] $Request) {
53+
Foil\Unregister-ChocoSource -Name $Request.Name
54+
# Choco doesn't return anything after source operations, so we make up our own output object
55+
$Request.WriteSource($Request.Name, '')
56+
}
57+
58+
[void] SetSource([SourceRequest] $Request) {
59+
$this.RegisterSource($Request)
60+
}
61+
62+
[void] GetPackage([PackageRequest] $Request) {
63+
Get-ChocoPackage | Write-Package
64+
}
65+
66+
[void] FindPackage([PackageRequest] $Request) {
67+
Find-ChocoPackage | Write-Package
68+
}
69+
70+
[void] InstallPackage([PackageRequest] $Request) {
71+
$chocoParams = @{
72+
ParamsGlobal = $Request.DynamicParameters.ParamsGlobal
73+
Parameters = $Request.DynamicParameters.Parameters
74+
}
75+
76+
# Run the package request first through Find-ChocoPackage to determine which source to use, and filter by any version requirements
77+
Find-ChocoPackage | Foil\Install-ChocoPackage @chocoParams | Write-Package
78+
}
79+
80+
[void] UninstallPackage([PackageRequest] $Request) {
81+
$chocoParams = @{
82+
RemoveDependencies = $Request.DynamicParameters.RemoveDependencies
83+
}
84+
85+
# Run the package request first through Get-ChocoPackage to filter by any version requirements
86+
Get-ChocoPackage | Foil\Uninstall-ChocoPackage @chocoParams | Write-Package
87+
}
88+
}
89+
90+
[PackageProviderManager]::RegisterProvider([ChocolateyProvider], $MyInvocation.MyCommand.ScriptBlock.Module)
91+
92+
Export-ModuleMember -Cmdlet *

src/private/Find-ChocoPackage.ps1

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
function Find-ChocoPackage {
2+
param (
3+
[Parameter()]
4+
[PackageRequest]
5+
$Request = $Request
6+
)
7+
8+
[array]$RegisteredPackageSources = Foil\Get-ChocoSource
9+
10+
$selectedSource = $(
11+
if ($Request.Source) {
12+
# Finding the matched package sources from the registered ones
13+
if ($RegisteredPackageSources.Name -eq $Request.Source) {
14+
# Found the matched registered source
15+
$Request.Source
16+
} else {
17+
ThrowError -ExceptionName 'System.ArgumentException' `
18+
-ExceptionMessage ($LocalizedData.PackageSourceNotFound -f ($Request.Source)) `
19+
-ErrorId 'PackageSourceNotFound' `
20+
-ErrorCategory InvalidArgument `
21+
-ExceptionObject $Request.Source
22+
}
23+
} else {
24+
# User did not specify a source. Now what?
25+
if ($RegisteredPackageSources.Count -eq 1) {
26+
# If no source name is specified and only one source is available, use that source
27+
$RegisteredPackageSources[0].Name
28+
} elseif ($RegisteredPackageSources.Name -eq $DefaultPackageSource) {
29+
# If multiple sources are avaiable but none specified, use the default package source if present
30+
$DefaultPackageSource
31+
} else {
32+
# If the default assumed source is not present and no source specified, we can't guess what the user wants - throw an exception
33+
ThrowError -ExceptionName 'System.ArgumentException' `
34+
-ExceptionMessage $LocalizedData.UnspecifiedSource `
35+
-ErrorId 'UnspecifiedSource' `
36+
-ErrorCategory InvalidArgument
37+
}
38+
}
39+
)
40+
41+
$chocoParams = @{
42+
Name = $Request.Name
43+
Source = $selectedSource
44+
}
45+
46+
if (-Not [WildcardPattern]::ContainsWildcardCharacters($Request.Name)) {
47+
# Limit NuGet result set to just the specific package name unless it contains a wildcard
48+
$chocoParams.Add('Exact',$true)
49+
}
50+
51+
# Choco does not support searching by min or max version, so if a user is picky we'll need to pull back all versions and filter ourselves
52+
if ($Request.Version) {
53+
$chocoParams.Add('AllVersions',$true)
54+
}
55+
56+
# Filter results by any name and version requirements
57+
# We apply additional package name filtering when using wildcards to make Chocolatey's wildcard behavior more PowerShell-esque
58+
# The final results must be grouped by package name, showing the highest available version for install, to make the results easier to consume
59+
# Choco does not include source information in it's result set, so we need to include it in the results as a calculated property
60+
Foil\Get-ChocoPackage @chocoParams |
61+
Where-Object {$Request.IsMatch($_.Name)} |
62+
Where-Object {-Not $Request.Version -Or (([NuGet.Versioning.VersionRange]$Request.Version).Satisfies($_.Version))} | Group-Object Name |
63+
Select-Object Name,@{
64+
Name = 'Version'
65+
Expression = {$_.Group | Sort-Object -Descending Version | Select-Object -First 1 -ExpandProperty Version}
66+
},@{
67+
Name = 'Source'
68+
Expression = {$selectedSource}
69+
}
70+
}

src/private/Get-ChocoPackage.ps1

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function Get-ChocoPackage {
2+
param (
3+
[Parameter()]
4+
[PackageRequest]
5+
$Request = $Request
6+
)
7+
8+
$chocoParams = @{
9+
LocalOnly = $true
10+
AllVersions = $true
11+
}
12+
13+
# If a user provides a name without a wildcard, include it in the search
14+
# This provides wildcard search behavior for locally installed packages, which Chocolatey lacks
15+
if ($Request.Name -And -Not ([WildcardPattern]::ContainsWildcardCharacters($Request.Name))) {
16+
$chocoParams.Add('Name',$Request.Name)
17+
}
18+
19+
# Filter results by any name and version requirements
20+
# We apply additional package name filtering when using wildcards to make Chocolatey's wildcard behavior more PowerShell-esque
21+
Foil\Get-ChocoPackage @chocoParams |
22+
Where-Object {-Not $Request.Name -Or ($Request.IsMatch($_.Name))} |
23+
Where-Object {-Not $Request.Version -Or (([NuGet.Versioning.VersionRange]$Request.Version).Satisfies($_.Version))}
24+
}

src/private/Write-Package.ps1

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function Write-Package {
2+
param (
3+
[Parameter(ValueFromPipeline)]
4+
[object[]]
5+
$InputObject,
6+
7+
[Parameter()]
8+
[PackageRequest]
9+
$Request = $Request
10+
)
11+
12+
process {
13+
foreach ($package in $InputObject) {
14+
if ($package.Source) {
15+
# If source information is provided (usually from Find-ChocoPackage), construct a source object for inclusion in the results
16+
$source = $Request.NewSourceInfo($package.Source,(Foil\Get-ChocoSource | Where-Object Name -EQ $package.Source | Select-Object -ExpandProperty Location),$true)
17+
$Request.WritePackage($package.Name, $package.Version, '', $source)
18+
} else {
19+
$Request.WritePackage($package.Name, $package.Version)
20+
}
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)