diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml new file mode 100644 index 0000000..ed7d756 --- /dev/null +++ b/.github/workflows/mirror.yml @@ -0,0 +1,200 @@ +name: 'Mirror' + +on: + - push + +env: + OWNER: '${{ github.repository_owner }}' + USER_AGENT: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0' + +jobs: + + # ------------------------------------------------------------------------------------------------------------------ # + # GitLab. + # ------------------------------------------------------------------------------------------------------------------ # + + mirror_gitlab: + runs-on: ubuntu-latest + name: 'GitLab' + env: + DOMAIN: 'https://gitlab.com' + VERSION: 'v4' + NSID: '69852292' + steps: + - name: 'Get repository name' + shell: bash + run: | + echo "REPO_NAME=$( echo '${{ github.repository }}' | awk -F '/' '{ print $2 }' )" >> $GITHUB_ENV + - name: 'Create repository' + shell: bash + run: | + http="$( curl -s -o '/dev/null' -I -w '%{http_code}' -A '${{ env.USER_AGENT }}' '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}' )" + if [[ "${http}" -ne 200 ]]; then + curl -X POST \ + -H 'Authorization: Bearer ${{ secrets.BOT_MIRROR_TOKEN_GITLAB }}' \ + -H 'Content-Type: application/json' \ + -A '${{ env.USER_AGENT }}' \ + '${{ env.DOMAIN }}/api/${{ env.VERSION }}/projects/' \ + -d '{"name":"${{ env.REPO_NAME }}","path":"${{ env.REPO_NAME }}","namespace_id":"${{ env.NSID }}","visibility":"public"}' + fi + - name: 'Mirror repository' + uses: ghastore/github-mirror@main + with: + src_repo: '${{ github.server_url }}/${{ github.repository }}.git' + src_user: '${{ secrets.BOT_MIRROR_NAME }}' + src_token: '${{ secrets.BOT_MIRROR_TOKEN_GITHUB }}' + dst_repo: '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}.git' + dst_user: '${{ secrets.BOT_MIRROR_NAME }}' + dst_token: '${{ secrets.BOT_MIRROR_TOKEN_GITLAB }}' + + # ------------------------------------------------------------------------------------------------------------------ # + # Codeberg. + # ------------------------------------------------------------------------------------------------------------------ # + + mirror_codeberg: + runs-on: ubuntu-latest + name: 'Codeberg' + env: + DOMAIN: 'https://codeberg.org' + VERSION: 'v1' + steps: + - name: 'Get repository name' + shell: bash + run: | + echo "REPO_NAME=$( echo '${{ github.repository }}' | awk -F '/' '{ print $2 }' )" >> $GITHUB_ENV + - name: 'Create repository' + shell: bash + run: | + http="$( curl -s -o '/dev/null' -I -w '%{http_code}' -A '${{ env.USER_AGENT }}' '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}' )" + if [[ "${http}" -ne 200 ]]; then + curl -X POST \ + -H 'Authorization: token ${{ secrets.BOT_MIRROR_TOKEN_CODEBERG }}' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -A '${{ env.USER_AGENT }}' \ + '${{ env.DOMAIN }}/api/${{ env.VERSION }}/orgs/${{ env.OWNER }}/repos' \ + -d '{"name":"${{ env.REPO_NAME }}"}' + fi + - name: 'Mirror repository' + uses: ghastore/github-mirror@main + with: + src_repo: '${{ github.server_url }}/${{ github.repository }}.git' + src_user: '${{ secrets.BOT_MIRROR_NAME }}' + src_token: '${{ secrets.BOT_MIRROR_TOKEN_GITHUB }}' + dst_repo: '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}.git' + dst_user: '${{ secrets.BOT_MIRROR_NAME }}' + dst_token: '${{ secrets.BOT_MIRROR_TOKEN_CODEBERG }}' + + # ------------------------------------------------------------------------------------------------------------------ # + # MosHub. + # ------------------------------------------------------------------------------------------------------------------ # + + mirror_moshub: + runs-on: ubuntu-latest + name: 'MosHub' + env: + DOMAIN: 'https://hub.mos.ru' + VERSION: 'v4' + NSID: '38795' + steps: + - name: 'Get repository name' + shell: bash + run: | + echo "REPO_NAME=$( echo '${{ github.repository }}' | awk -F '/' '{ print $2 }' )" >> $GITHUB_ENV + - name: 'Create repository' + shell: bash + run: | + http="$( curl -s -o '/dev/null' -I -w '%{http_code}' -A '${{ env.USER_AGENT }}' '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}' )" + if [[ "${http}" -ne 200 ]]; then + curl -X POST \ + -H 'Authorization: Bearer ${{ secrets.BOT_MIRROR_TOKEN_MOSHUB }}' \ + -H 'Content-Type: application/json' \ + -A '${{ env.USER_AGENT }}' \ + '${{ env.DOMAIN }}/api/${{ env.VERSION }}/projects/' \ + -d '{"name":"${{ env.REPO_NAME }}","path":"${{ env.REPO_NAME }}","namespace_id":"${{ env.NSID }}","visibility":"public"}' + fi + - name: 'Mirror repository' + uses: ghastore/github-mirror@main + with: + src_repo: '${{ github.server_url }}/${{ github.repository }}.git' + src_user: '${{ secrets.BOT_MIRROR_NAME }}' + src_token: '${{ secrets.BOT_MIRROR_TOKEN_GITHUB }}' + dst_repo: '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}.git' + dst_user: '${{ secrets.BOT_MIRROR_NAME }}' + dst_token: '${{ secrets.BOT_MIRROR_TOKEN_MOSHUB }}' + + # ------------------------------------------------------------------------------------------------------------------ # + # GIT.ORG.RU. + # ------------------------------------------------------------------------------------------------------------------ # + + mirror_gitorgru: + runs-on: ubuntu-latest + name: 'GIT.ORG.RU' + env: + DOMAIN: 'https://git.org.ru' + VERSION: 'v1' + steps: + - name: 'Get repository name' + shell: bash + run: | + echo "REPO_NAME=$( echo '${{ github.repository }}' | awk -F '/' '{ print $2 }' )" >> $GITHUB_ENV + - name: 'Create repository' + shell: bash + run: | + http="$( curl -s -o '/dev/null' -I -w '%{http_code}' -A '${{ env.USER_AGENT }}' '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}' )" + if [[ "${http}" -ne 200 ]]; then + curl -X POST \ + -H 'Authorization: token ${{ secrets.BOT_MIRROR_TOKEN_GITORGRU }}' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -A '${{ env.USER_AGENT }}' \ + '${{ env.DOMAIN }}/api/${{ env.VERSION }}/orgs/${{ env.OWNER }}/repos' \ + -d '{"name":"${{ env.REPO_NAME }}"}' + fi + - name: 'Mirror repository' + uses: ghastore/github-mirror@main + with: + src_repo: '${{ github.server_url }}/${{ github.repository }}.git' + src_user: '${{ secrets.BOT_MIRROR_NAME }}' + src_token: '${{ secrets.BOT_MIRROR_TOKEN_GITHUB }}' + dst_repo: '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}.git' + dst_user: '${{ secrets.BOT_MIRROR_NAME }}' + dst_token: '${{ secrets.BOT_MIRROR_TOKEN_GITORGRU }}' + + # ------------------------------------------------------------------------------------------------------------------ # + # Disroot. + # ------------------------------------------------------------------------------------------------------------------ # + + mirror_disroot: + runs-on: ubuntu-latest + name: 'Disroot' + env: + DOMAIN: 'https://git.disroot.org' + VERSION: 'v1' + steps: + - name: 'Get repository name' + shell: bash + run: | + echo "REPO_NAME=$( echo '${{ github.repository }}' | awk -F '/' '{ print $2 }' )" >> $GITHUB_ENV + - name: 'Create repository' + shell: bash + run: | + http="$( curl -s -o '/dev/null' -I -w '%{http_code}' -A '${{ env.USER_AGENT }}' '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}' )" + if [[ "${http}" -ne 200 ]]; then + curl -X POST \ + -H 'Authorization: token ${{ secrets.BOT_MIRROR_TOKEN_DISROOT }}' \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json' \ + -A '${{ env.USER_AGENT }}' \ + '${{ env.DOMAIN }}/api/${{ env.VERSION }}/orgs/${{ env.OWNER }}/repos' \ + -d '{"name":"${{ env.REPO_NAME }}"}' + fi + - name: 'Mirror repository' + uses: ghastore/github-mirror@main + with: + src_repo: '${{ github.server_url }}/${{ github.repository }}.git' + src_user: '${{ secrets.BOT_MIRROR_NAME }}' + src_token: '${{ secrets.BOT_MIRROR_TOKEN_GITHUB }}' + dst_repo: '${{ env.DOMAIN }}/${{ env.OWNER }}/${{ env.REPO_NAME }}.git' + dst_user: '${{ secrets.BOT_MIRROR_NAME }}' + dst_token: '${{ secrets.BOT_MIRROR_TOKEN_DISROOT }}' diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e69de29 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..c5b4523 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing + +- Feedback, wishes and suggestions can be sent by email. +- Constructive criticism, bug descriptions and other reports are welcome. +- Email: [mail@ihub.to](mailto:mail@ihub.to). + +## Sources + +- [**GitHub**](https://github.com/pkgstore) +- [GitLab](https://gitlab.com/pkgstore) (MIRROR) +- [Codeberg](https://codeberg.org/pkgstore) (MIRROR) +- [Disroot](https://git.disroot.org/pkgstore) (MIRROR) +- [MosHub](https://hub.mos.ru/pkgstore) (MIRROR) +- [Git.Org.Ru](https://git.org.ru/pkgstore) (MIRROR) diff --git a/LICENSE b/LICENSE index 8dbae8f..9cc965c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Package Store +Copyright (c) 2023 iHub.TO Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/PkgStore.Install.psd1 b/PkgStore.Install.psd1 new file mode 100644 index 0000000..a4a4fae --- /dev/null +++ b/PkgStore.Install.psd1 @@ -0,0 +1,132 @@ +# +# Module manifest for module 'PkgStore.Install' +# +# Generated by: Kitsune Solar +# +# Generated on: 19.11.2023 +# + +@{ + +# Script module or binary module file associated with this manifest. +RootModule = 'PkgStore.Install.psm1' + +# Version number of this module. +ModuleVersion = '0.1.0' + +# Supported PSEditions +# CompatiblePSEditions = @() + +# ID used to uniquely identify this module +GUID = '1abccb3f-ac98-437f-8e47-ecb87673b99d' + +# Author of this module +Author = 'Kitsune Solar' + +# Company or vendor of this module +CompanyName = 'iHub.TO' + +# Copyright statement for this module +Copyright = '(c) 2023 Library Online. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'A kernel for PowerShell modules from Package Store.' + +# Minimum version of the PowerShell engine required by this module +PowerShellVersion = '7.2' + +# Name of the PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. +# ClrVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. +FunctionsToExport = 'Install-CustomModule' + +# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. +CmdletsToExport = @() + +# Variables to export from this module +# VariablesToExport = @() + +# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. +AliasesToExport = @() + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = 'pwsh','install' + + # A URL to the license for this module. + LicenseUri = 'https://github.com/pkgstore/pwsh-install/blob/main/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/pkgstore/pwsh-install' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + # Prerelease string of this module + # Prerelease = '' + + # Flag to indicate whether the module requires explicit user acceptance for install/update/save + # RequireLicenseAcceptance = $false + + # External dependent modules of this module + # ExternalModuleDependencies = @() + + } # End of PSData hashtable + + } # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} + diff --git a/PkgStore.Install.psm1 b/PkgStore.Install.psm1 new file mode 100644 index 0000000..4138d41 --- /dev/null +++ b/PkgStore.Install.psm1 @@ -0,0 +1,51 @@ +$ModuleManifest = (Get-ChildItem -Path $PSScriptRoot | Where-Object {$_.Extension -eq '.psd1'}) +$CurrentManifest = (Test-ModuleManifest $ModuleManifest) + +$Aliases = @() +$PrivateFunctions = (Get-ChildItem -Path (Join-Path $PSScriptRoot 'Private') | Where-Object {$_.Extension -eq '.ps1'}) +$PublicFunctions = (Get-ChildItem -Path (Join-Path $PSScriptRoot 'Public') | Where-Object {$_.Extension -eq '.ps1'}) + +(@($PrivateFunctions) + @($PublicFunctions)) | ForEach-Object { + try { + Write-Verbose "Loading: '$($_.FullName)'." + . $_.FullName + } catch { + $_.Exception.Message | Write-Warning + } +} + +@($PublicFunctions) | ForEach-Object { + $Alias = (Get-Alias -Definition $_.BaseName -ErrorAction 'SilentlyContinue') + + if ($Alias) { + $Aliases += $Alias + Export-ModuleMember -Function $_.BaseName -Alias $Alias + } else { + Export-ModuleMember -Function $_.BaseName + } +} + +$FunctionsAdded = ($PublicFunctions | Where-Object {$_.BaseName -notin $CurrentManifest.ExportedFunctions.Keys}) +$FunctionsRemoved = ($CurrentManifest.ExportedFunctions.Keys | Where-Object {$_ -notin $PublicFunctions.BaseName}) +$AliasesAdded = ($Aliases | Where-Object {$_ -notin $CurrentManifest.ExportedAliases.Keys}) +$AliasesRemoved = ($CurrentManifest.ExportedAliases.Keys | Where-Object {$_ -notin $Aliases}) + +if ($FunctionsAdded -or $FunctionsRemoved -or $AliasesAdded -or $AliasesRemoved) { + try { + $UpdateModuleManifestParams = @{} + $UpdateModuleManifestParams.Add('Path', $ModuleManifest) + $UpdateModuleManifestParams.Add('ErrorAction', 'Stop') + + if ($Aliases.Count -gt 0) { + $UpdateModuleManifestParams.Add('AliasesToExport', $Aliases) + } + + if ($PublicFunctions.Count -gt 0) { + $UpdateModuleManifestParams.Add('FunctionsToExport', $PublicFunctions.BaseName) + } + + Update-ModuleManifest @UpdateModuleManifestParams + } catch { + $_ | Write-Error + } +} diff --git a/Private/.gitkeep b/Private/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Public/Install-CustomModule.ps1 b/Public/Install-CustomModule.ps1 new file mode 100644 index 0000000..501c385 --- /dev/null +++ b/Public/Install-CustomModule.ps1 @@ -0,0 +1,30 @@ +function Install-CustomModule() { + param( + [Parameter(Mandatory)][Alias('MN')][string]$ModuleName, + [Alias('MP')][string]$ModulePrefix = 'PkgStore', + [Alias('MV')][string]$ModuleVersion = 'latest', + [Alias('MD')][string]$ModuleDirectory = "$(($Env:PSModulePath -split ';')[0])", + [Parameter(Mandatory)][Alias('GHP')][string]$GitHubPath, + [Parameter(Mandatory)][Alias('GHT')][string]$GitHubToken +) + + $ModuleFullName = "${ModulePrefix}.${ModuleName}" + $ModuleVersion = ($ModuleVersion -eq 'latest') ? $ModuleVersion : "tags/${ModuleVersion}" + $ModulePath = (Join-Path $ModuleDirectory $ModuleFullName) + $Headers = @{ + Authorization="Bearer ${GitHubToken}" + } + + try { + Invoke-RestMethod -Headers $Headers -Uri "https://api.github.com/repos/${GitHubPath}/releases/${ModuleVersion}" + | ForEach-Object 'zipball_url' + | ForEach-Object { Invoke-WebRequest $_ -OutFile "${ModulePath}.zip" } + + Expand-Archive -Path "${ModulePath}.zip" -DestinationPath "${ModuleDirectory}" + if (Test-Path -Path "${ModulePath}") { Remove-Item -Path "${ModulePath}" -Recurse -Force} + Rename-Item -Path (Join-Path $ModuleDirectory "$($GitHubPath.replace('/','-'))-*") -NewName "${ModulePath}" + Remove-Item -Path "${ModulePath}.zip" + } catch { + $_ | Write-Error + } +} diff --git a/README.md b/README.md index 8a9f42a..46329e8 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -# pwsh-install \ No newline at end of file +# PowerShell Install Module + +Module for installing third-party modules from GitHub. + +## Install + +```powershell +$MOD = "Install"; $PFX = "PkgStore"; $DIR = "$(($Env:PSModulePath -split ';')[0])"; Invoke-WebRequest "https://github.com/pkgstore/pwsh-${MOD}/archive/refs/heads/main.zip" -OutFile (Join-Path $DIR "${MOD}.zip"); Expand-Archive -Path (Join-Path $DIR "${MOD}.zip") -DestinationPath "${DIR}"; if (Test-Path -Path (Join-Path $DIR "${PFX}.${MOD}")) { Remove-Item -Path (Join-Path $DIR "${PFX}.${MOD}") -Recurse -Force }; Rename-Item -Path (Join-Path $DIR "pwsh-${MOD}-main") -NewName (Join-Path $DIR "${PFX}.${MOD}"); Remove-Item -Path (Join-Path $DIR "${MOD}.zip"); +```