From 92a3c9c21568a0a4d5955e1694bdcaa1ea09522d Mon Sep 17 00:00:00 2001 From: David GABISON Date: Thu, 22 Dec 2022 12:16:51 +0100 Subject: [PATCH 01/22] fix: /task "" no longer works since version 1.3.20 --- launcher/src/CmderLauncher.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/launcher/src/CmderLauncher.cpp b/launcher/src/CmderLauncher.cpp index fc34eeb..9f033c3 100644 --- a/launcher/src/CmderLauncher.cpp +++ b/launcher/src/CmderLauncher.cpp @@ -425,11 +425,6 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr swprintf_s(args, L"%s /single", args); } - if (!streqi(cmderTask.c_str(), L"")) - { - swprintf_s(args, L"%s /run {%s}", args, cmderTask.c_str()); - } - if (!streqi(cmderTitle.c_str(), L"")) { swprintf_s(args, L"%s /title \"%s\"", args, cmderTitle.c_str()); @@ -445,6 +440,14 @@ void StartCmder(std::wstring path = L"", bool is_single_mode = false, std::wstr swprintf_s(args, L"%s %s", args, cmderConEmuArgs.c_str()); } + // The `/run` arg and its value MUST be the last arg of ConEmu + // see : https://conemu.github.io/en/ConEmuArgs.html + // > This must be the last used switch (excepting -new_console and -cur_console) + if (!streqi(cmderTask.c_str(), L"")) + { + swprintf_s(args, L"%s /run {%s}", args, cmderTask.c_str()); + } + SetEnvironmentVariable(L"CMDER_ROOT", exeDir); if (wcscmp(userConfigDirPath, configDirPath) != 0) { From f1e2fb569792d0ab70727688c1c91f7e8dfc8b8c Mon Sep 17 00:00:00 2001 From: "Dax T. Games" Date: Sun, 26 Feb 2023 18:00:26 -0800 Subject: [PATCH 02/22] prevent timer results every time. --- vendor/bin/create-cmdercfg.ps1 | 2 +- vendor/init.bat | 2 +- vendor/{user_init.cmd.template => user_init.template.cmd} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename vendor/{user_init.cmd.template => user_init.template.cmd} (98%) diff --git a/vendor/bin/create-cmdercfg.ps1 b/vendor/bin/create-cmdercfg.ps1 index 5fb23a0..16c83fa 100644 --- a/vendor/bin/create-cmdercfg.ps1 +++ b/vendor/bin/create-cmdercfg.ps1 @@ -11,7 +11,7 @@ $CmderFunctions = Join-Path $CmderModulePath "Cmder.ps1" if ($shell -match 'cmd') { write-host "Generating Cmder Config for '$shell' shell in '$outfile'..." - templateExpand "$env:cmder_root\vendor\user_init.cmd.template" "$outfile" + templateExpand "$env:cmder_root\vendor\user_init.template.cmd" "$outfile" } elseif ($shell -match 'powershell') { write-host "'$shell' is not supported at this time!" } elseif ($shell -match 'bash') { diff --git a/vendor/init.bat b/vendor/init.bat index 97694e6..88df305 100644 --- a/vendor/init.bat +++ b/vendor/init.bat @@ -562,7 +562,7 @@ if defined CMDER_USER_CONFIG ( if not defined CMDER_CONFIGURED set CMDER_CONFIGURED=1 set CMDER_INIT_END=%time% - if "%CMDER_INIT_END%" neq "" if "%CMDER_INIT_START%" neq "" ( + if "%time_init%" == "1" if "%CMDER_INIT_END%" neq "" if "%CMDER_INIT_START%" neq "" ( call "%cmder_root%\vendor\bin\timer.cmd" "%CMDER_INIT_START%" "%CMDER_INIT_END%" ) diff --git a/vendor/user_init.cmd.template b/vendor/user_init.template.cmd similarity index 98% rename from vendor/user_init.cmd.template rename to vendor/user_init.template.cmd index acc36f9..ebfaf85 100644 --- a/vendor/user_init.cmd.template +++ b/vendor/user_init.template.cmd @@ -144,7 +144,7 @@ goto :SKIP_CLINK set CMDER_INIT_END=%time% - if "%CMDER_INIT_END%" neq "" if "%CMDER_INIT_START%" neq "" ( + if "%time_init%" == "1" if "%CMDER_INIT_END%" neq "" if "%CMDER_INIT_START%" neq "" ( call "%cmder_root%\vendor\bin\timer.cmd" "%CMDER_INIT_START%" "%CMDER_INIT_END%" ) From e0b694324ca0248bcb6b2035b26390ea242a8b91 Mon Sep 17 00:00:00 2001 From: "Dax T. Games" Date: Sun, 5 Mar 2023 15:00:11 -0800 Subject: [PATCH 03/22] add bypass --- vendor/init.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/init.bat b/vendor/init.bat index 88df305..ae4e518 100644 --- a/vendor/init.bat +++ b/vendor/init.bat @@ -551,7 +551,7 @@ if defined CMDER_USER_CONFIG ( %print_error% "Failed to generate Cmder config" ) ) else if not exist "%CMDER_ROOT%\config\user_init.cmd" ( - powershell -f %cmder_root%\vendor\bin\create-cmdercfg.ps1 -shell cmd -outfile "%CMDER_ROOT%\config\user_init.cmd" + powershell -executionpolicy bypass -f %cmder_root%\vendor\bin\create-cmdercfg.ps1 -shell cmd -outfile "%CMDER_ROOT%\config\user_init.cmd" if not exist "%CMDER_ROOT%\config\user_init.cmd" ( %print_error% "Failed to generate Cmder config" From 4efbe0bd62a20291dae8fa9c42afaa940b7f3e97 Mon Sep 17 00:00:00 2001 From: DRSDavidSoft Date: Fri, 10 Mar 2023 13:42:19 +0000 Subject: [PATCH 04/22] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependencie?= =?UTF-8?q?s=20(git-for-windows=20v2.40.0-rc2.windows.1,=20clink=20v1.4.22?= =?UTF-8?q?,=20clink-completions=20v0.4.7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/sources.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/sources.json b/vendor/sources.json index f4c3c33..f96c2c1 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -1,13 +1,13 @@ [ { "name": "git-for-windows", - "version": "2.39.0.windows.2", - "url": "https://github.com/git-for-windows/git/releases/download/v2.39.0.windows.2/PortableGit-2.39.0.2-64-bit.7z.exe" + "version": "2.40.0-rc2.windows.1", + "url": "https://github.com/git-for-windows/git/releases/download/v2.40.0-rc2.windows.1/PortableGit-2.40.0-rc2-64-bit.7z.exe" }, { "name": "clink", - "version": "1.4.10", - "url": "https://github.com/chrisant996/clink/releases/download/v1.4.10/clink.1.4.10.45c041.zip" + "version": "1.4.22", + "url": "https://github.com/chrisant996/clink/releases/download/v1.4.22/clink.1.4.22.33f515.zip" }, { "name": "conemu-maximus5", @@ -16,7 +16,7 @@ }, { "name": "clink-completions", - "version": "0.4.4", - "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.4.4.zip" + "version": "0.4.7", + "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.4.7.zip" } ] From c4d93655841773e6d8b34a2dbfbc607c0af09f2f Mon Sep 17 00:00:00 2001 From: "Dax T. Games" Date: Sat, 11 Mar 2023 14:59:12 -0800 Subject: [PATCH 05/22] x --- vendor/init.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/init.bat b/vendor/init.bat index ae4e518..97c1b07 100644 --- a/vendor/init.bat +++ b/vendor/init.bat @@ -572,6 +572,7 @@ if defined CMDER_USER_CONFIG ( set CMDER_INIT_END= set CMDER_INIT_START= set CMDER_USER_FLAGS= + set CMDER_CLINK= set debug_output= set fast_init= set max_depth= From 42568b7316f2e28b5ca4c6518912b5b4edf85bfa Mon Sep 17 00:00:00 2001 From: "Dax T. Games" Date: Sun, 12 Mar 2023 13:02:08 -0700 Subject: [PATCH 06/22] Document '--' command line argument --- README.md | 2 +- launcher/src/strings.rc2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 735fd1e..cda18e9 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ The Cmder's user interface is also designed to be more eye pleasing, and you can | `/SINGLE` | Start Cmder in single mode. | | `/START [start_path]` | Folder path to start in. | | `/TASK [task_name]` | Task to start after launch. | -| `/X [ConEmu extras pars]` | Forwards parameters to ConEmu | +| `-- [ConEmu extras pars]` | Forwards ALL remaining parameters to ConEmu. | ## Context Menu Integration diff --git a/launcher/src/strings.rc2 b/launcher/src/strings.rc2 index 0887307..67866de 100644 --- a/launcher/src/strings.rc2 +++ b/launcher/src/strings.rc2 @@ -6,7 +6,7 @@ STRINGTABLE { IDS_TITLE "Cmder Launcher" - IDS_SWITCHES L"Valid options:\n\n /c [CMDER User Root Path]\n /task [ConEmu Task Name]\n /icon [CMDER Icon Path]\n [/start [Start in Path] | [Start in Path]]\n /single\n /m\n /x [ConEmu extra arguments]\n\nor, either:\n /register [USER | ALL]\n /unregister [USER | ALL]" + IDS_SWITCHES L"Valid options:\n\n /c [CMDER User Root Path]\n /task [ConEmu Task Name]\n /icon [CMDER Icon Path]\n [/start [Start in Path] | [Start in Path]]\n /single\n /m\n -- [ConEmu extra arguments]\n\nNote: '-- [...]' must be the last argument!\n\nor, either:\n /register [USER | ALL]\n /unregister [USER | ALL]" } ///////////////////////////////////////////////////////////////////////////// From 36ad85c7b73824f1e39ac98f797140068ce040ac Mon Sep 17 00:00:00 2001 From: DRSDavidSoft Date: Thu, 16 Mar 2023 13:43:09 +0000 Subject: [PATCH 07/22] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependencie?= =?UTF-8?q?s=20(git-for-windows=20v2.40.0.windows.1,=20clink=20v1.4.23)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/sources.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/sources.json b/vendor/sources.json index f96c2c1..9ae99c1 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -1,13 +1,13 @@ [ { "name": "git-for-windows", - "version": "2.40.0-rc2.windows.1", - "url": "https://github.com/git-for-windows/git/releases/download/v2.40.0-rc2.windows.1/PortableGit-2.40.0-rc2-64-bit.7z.exe" + "version": "2.40.0.windows.1", + "url": "https://github.com/git-for-windows/git/releases/download/v2.40.0.windows.1/PortableGit-2.40.0-64-bit.7z.exe" }, { "name": "clink", - "version": "1.4.22", - "url": "https://github.com/chrisant996/clink/releases/download/v1.4.22/clink.1.4.22.33f515.zip" + "version": "1.4.23", + "url": "https://github.com/chrisant996/clink/releases/download/v1.4.23/clink.1.4.23.5fc3fc.zip" }, { "name": "conemu-maximus5", From 1d1e815c9183540420eb3b63eaca6bf6665e86c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 16:02:00 +0000 Subject: [PATCH 08/22] Bump peter-evans/create-pull-request from 4 to 5 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4 to 5. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v4...v5) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/vendor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/vendor.yml b/.github/workflows/vendor.yml index 1e8aecd..e01155f 100644 --- a/.github/workflows/vendor.yml +++ b/.github/workflows/vendor.yml @@ -51,7 +51,7 @@ jobs: Set-GHVariable -Name LIST_UPDATED -Value $listUpdated.Trim(', ') echo "UPDATE_MESSAGE<< 0 with: title: 'Updates to `${{ env.COUNT_UPDATED }}` vendored dependencies' From a4ea326a62a4e85a47f447746e0c00aa24b96ddc Mon Sep 17 00:00:00 2001 From: daxgames Date: Wed, 19 Apr 2023 13:44:11 +0000 Subject: [PATCH 09/22] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependencie?= =?UTF-8?q?s=20(git-for-windows=20v2.40.0.windows.1,=20clink=20v1.4.24,=20?= =?UTF-8?q?clink-completions=20v0.4.7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/sources.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vendor/sources.json b/vendor/sources.json index f4c3c33..00f8378 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -1,13 +1,13 @@ [ { "name": "git-for-windows", - "version": "2.39.0.windows.2", - "url": "https://github.com/git-for-windows/git/releases/download/v2.39.0.windows.2/PortableGit-2.39.0.2-64-bit.7z.exe" + "version": "2.40.0.windows.1", + "url": "https://github.com/git-for-windows/git/releases/download/v2.40.0.windows.1/PortableGit-2.40.0-64-bit.7z.exe" }, { "name": "clink", - "version": "1.4.10", - "url": "https://github.com/chrisant996/clink/releases/download/v1.4.10/clink.1.4.10.45c041.zip" + "version": "1.4.24", + "url": "https://github.com/chrisant996/clink/releases/download/v1.4.24/clink.1.4.24.688975.zip" }, { "name": "conemu-maximus5", @@ -16,7 +16,7 @@ }, { "name": "clink-completions", - "version": "0.4.4", - "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.4.4.zip" + "version": "0.4.7", + "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.4.7.zip" } ] From d80202c791e2de85c07aa4a0de249d70c1b857e0 Mon Sep 17 00:00:00 2001 From: David Refoua Date: Sun, 23 Apr 2023 23:39:35 +0330 Subject: [PATCH 10/22] add task to auto push to development --- .github/workflows/branches.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/branches.yml diff --git a/.github/workflows/branches.yml b/.github/workflows/branches.yml new file mode 100644 index 0000000..e850479 --- /dev/null +++ b/.github/workflows/branches.yml @@ -0,0 +1,31 @@ +name: Update branches + +# Controls when the action will run. +on: + # Triggers the workflow on push events for the development branch + push: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This job updates the development branch with the master branch + update-development: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it + - uses: actions/checkout@v3 + + # Runs a single command using the runners shell + - name: Merge master into development + run: | + git config user.name "${{ github.actor }}" + git config user.email "${{ github.actor }}@users.noreply.github.com" + git checkout development + git merge --no-ff master + git push origin development From d838f861af01805e79574c47e96e23ab5707b43b Mon Sep 17 00:00:00 2001 From: David Refoua Date: Sun, 23 Apr 2023 23:43:26 +0330 Subject: [PATCH 11/22] checkout development --- .github/workflows/branches.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/branches.yml b/.github/workflows/branches.yml index e850479..4341c79 100644 --- a/.github/workflows/branches.yml +++ b/.github/workflows/branches.yml @@ -20,6 +20,8 @@ jobs: steps: # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it - uses: actions/checkout@v3 + with: + ref: development # Runs a single command using the runners shell - name: Merge master into development From 23488fcbb2b845b7c73f74c967096ccd7ec7bcf8 Mon Sep 17 00:00:00 2001 From: David Refoua Date: Sun, 23 Apr 2023 23:47:28 +0330 Subject: [PATCH 12/22] fetch all history for all branches and tags --- .github/workflows/branches.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branches.yml b/.github/workflows/branches.yml index 4341c79..b745893 100644 --- a/.github/workflows/branches.yml +++ b/.github/workflows/branches.yml @@ -21,7 +21,7 @@ jobs: # Checks-out the repository under $GITHUB_WORKSPACE, so the job can access it - uses: actions/checkout@v3 with: - ref: development + fetch-depth: 0 # fetch all history for all branches and tags # Runs a single command using the runners shell - name: Merge master into development From 7daeb465e8d2c1c21f2b3fcb1832b60c37109d33 Mon Sep 17 00:00:00 2001 From: DRSDavidSoft Date: Mon, 24 Apr 2023 13:41:39 +0000 Subject: [PATCH 13/22] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependencie?= =?UTF-8?q?s=20(clink=20v1.4.24)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/sources.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/sources.json b/vendor/sources.json index 9ae99c1..00f8378 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -6,8 +6,8 @@ }, { "name": "clink", - "version": "1.4.23", - "url": "https://github.com/chrisant996/clink/releases/download/v1.4.23/clink.1.4.23.5fc3fc.zip" + "version": "1.4.24", + "url": "https://github.com/chrisant996/clink/releases/download/v1.4.24/clink.1.4.24.688975.zip" }, { "name": "conemu-maximus5", From 7b880efda4953234ebf27100d0298c0bf5d53717 Mon Sep 17 00:00:00 2001 From: DRSDavidSoft Date: Wed, 26 Apr 2023 13:40:36 +0000 Subject: [PATCH 14/22] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependencie?= =?UTF-8?q?s=20(git-for-windows=20v2.40.1.windows.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/sources.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/sources.json b/vendor/sources.json index 00f8378..a846108 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -1,8 +1,8 @@ [ { "name": "git-for-windows", - "version": "2.40.0.windows.1", - "url": "https://github.com/git-for-windows/git/releases/download/v2.40.0.windows.1/PortableGit-2.40.0-64-bit.7z.exe" + "version": "2.40.1.windows.1", + "url": "https://github.com/git-for-windows/git/releases/download/v2.40.1.windows.1/PortableGit-2.40.1-64-bit.7z.exe" }, { "name": "clink", From 74381ecd19aa7923ea082abd25129b0a41125099 Mon Sep 17 00:00:00 2001 From: Chris Antos Date: Mon, 15 May 2023 09:15:36 -0700 Subject: [PATCH 15/22] Fix #2846; errors when git/svn/hg not installed. Also fixes error when HEAD is not available in a git repo, e.g. due to a corrupt repo. --- vendor/clink.lua | 81 +++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/vendor/clink.lua b/vendor/clink.lua index 6a9058e..8c24373 100644 --- a/vendor/clink.lua +++ b/vendor/clink.lua @@ -255,7 +255,8 @@ local function get_git_dir(path) local gitfile = io.open(dir..'/.git') if not gitfile then return false end - local git_dir = gitfile:read():match('gitdir: (.*)') + local line = gitfile:read() or '' + local git_dir = line:match('gitdir: (.*)') gitfile:close() if os.isdir then -- only available in Clink v1.0.0 and higher @@ -303,6 +304,9 @@ local function get_git_branch(git_dir) local HEAD = head_file:read() head_file:close() + -- If HEAD is missing, something is wrong. + if not HEAD then return end + -- if HEAD matches branch expression, then we're on named branch -- otherwise it is a detached commit local branch_name = HEAD:match('ref: refs/heads/(.+)') @@ -322,6 +326,9 @@ local function get_hg_branch() -- local cmd = "hg prompt \"{branch}{status}{|{patch}}{update}\"" local cmd = "hg branch 2>nul" local file = io.popen(cmd) + if not file then + return false + end for line in file:lines() do local m = line:match("(.+)$") @@ -341,6 +348,10 @@ end --- local function get_svn_branch(svn_dir) local file = io_popenyield("svn info 2>nul") + if not file then + return false + end + for line in file:lines() do local m = line:match("^Relative URL:") if m then @@ -359,6 +370,10 @@ end --- local function get_git_status() local file = io_popenyield("git --no-optional-locks status --porcelain 2>nul") + if not file then + return {} + end + local conflict_found = false local is_status = true for line in file:lines() do @@ -374,10 +389,10 @@ local function get_git_status() end end file:close() + return { status = is_status, conflict = conflict_found } end - --- -- Get the status of working dir -- @return {bool} @@ -399,13 +414,17 @@ end --- local function get_svn_status() local file = io_popenyield("svn status -q") - for line in file:lines() do + if not file then + return { error = true } + end + + for line in file:lines() do -- luacheck: ignore 512, no unused file:close() - return false + return { clean = false } end file:close() - return true + return { clean = true } end --- @@ -433,24 +452,28 @@ local function get_git_status_setting() end local gitStatusConfig = io_popenyield("git --no-pager config cmder.status 2>nul") - for line in gitStatusConfig:lines() do - if string.match(line, 'false') then - gitStatusConfig:close() - last_git_status_setting = false - return false + if gitStatusConfig then + for line in gitStatusConfig:lines() do + if string.match(line, 'false') then + gitStatusConfig:close() + last_git_status_setting = false + return false + end end + gitStatusConfig:close() end - gitStatusConfig:close() local gitCmdStatusConfig = io_popenyield("git --no-pager config cmder.cmdstatus 2>nul") - for line in gitCmdStatusConfig:lines() do - if string.match(line, 'false') then - gitCmdStatusConfig:close() - last_git_status_setting = false - return false + if gitCmdStatusConfig then + for line in gitCmdStatusConfig:lines() do + if string.match(line, 'false') then + gitCmdStatusConfig:close() + last_git_status_setting = false + return false + end end + gitCmdStatusConfig:close() end - gitCmdStatusConfig:close() last_git_status_setting = true return true @@ -536,8 +559,6 @@ local function hg_prompt_filter() return false end - local result = "" - local hg_dir = get_hg_dir() if hg_dir then -- Colors for mercurial status @@ -559,16 +580,20 @@ local function hg_prompt_filter() local color = colors.clean local pipe = io.popen("hg status -amrd 2>&1") - local output = pipe:read('*all') - local rc = { pipe:close() } + if pipe then + output = pipe:read('*all') + pipe:close() + if output ~= nil and output ~= "" then color = colors.dirty end + end - if output ~= nil and output ~= "" then color = colors.dirty end - result = color .. "(" .. branch .. ")" + local result = color .. "(" .. branch .. ")" + clink.prompt.value = string.gsub(clink.prompt.value, "{hg}", " "..verbatim(result)) + return false end end - clink.prompt.value = string.gsub(clink.prompt.value, "{hg}", " "..verbatim(result)) - return false + -- No hg present or not in hg repo + clink.prompt.value = string.gsub(clink.prompt.value, "{hg}", "") end local function svn_prompt_filter() @@ -589,7 +614,6 @@ local function svn_prompt_filter() if svn_dir then -- if we're inside of svn repo then try to detect current branch local branch = get_svn_branch() - local color if branch then -- If in a different repo or branch than last time, discard cached info if cached_info.svn_dir ~= svn_dir or cached_info.svn_branch ~= branch then @@ -613,9 +637,10 @@ local function svn_prompt_filter() svnStatus = get_svn_status() end - if svnStatus == nil then + local color + if not svnStatus or svnStatus.error then color = colors.nostatus - elseif svnStatus then + elseif svnStatus.clean then color = colors.clean else color = colors.dirty From c9153c96bf4d480eeb81c57135132a9979ee031a Mon Sep 17 00:00:00 2001 From: Chris Antos Date: Mon, 15 May 2023 09:17:01 -0700 Subject: [PATCH 16/22] Fix global Lua namespace pollution. Some variables were global when the intent was to be local variables. --- vendor/clink.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vendor/clink.lua b/vendor/clink.lua index 8c24373..86cbcf9 100644 --- a/vendor/clink.lua +++ b/vendor/clink.lua @@ -151,12 +151,12 @@ local function set_prompt_filter() cwd = string.gsub(cwd, clink.get_env("HOME"), prompt_homeSymbol) end - uah = '' + local uah = '' if prompt_useUserAtHost then uah = clink.get_env("USERNAME") .. "@" .. clink.get_env("COMPUTERNAME") .. ' ' end - cr = "\n" + local cr = "\n" if prompt_singleLine then cr = ' ' end @@ -170,7 +170,7 @@ local function set_prompt_filter() local version_control = prompt_includeVersionControl and "{git}{hg}{svn}" or "" - prompt = "{uah}{cwd}" .. version_control .. cr .. get_lamb_color() .. "{env}{lamb}\x1b[0m " + local prompt = "{uah}{cwd}" .. version_control .. cr .. get_lamb_color() .. "{env}{lamb}\x1b[0m " prompt = string.gsub(prompt, "{uah}", uah) prompt = string.gsub(prompt, "{cwd}", cwd) prompt = string.gsub(prompt, "{env}", env) From 5fab87f4d64170a75436fe5702fdd47619341b37 Mon Sep 17 00:00:00 2001 From: Chris Antos Date: Mon, 15 May 2023 09:18:47 -0700 Subject: [PATCH 17/22] Remove unused function. The `get_hg_status()` function has been unused since commit 35eab7a51a1ac4294df9861ff2fe5f40e94e0218 in 2018. --- vendor/clink.lua | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/vendor/clink.lua b/vendor/clink.lua index 86cbcf9..486426b 100644 --- a/vendor/clink.lua +++ b/vendor/clink.lua @@ -393,21 +393,6 @@ local function get_git_status() return { status = is_status, conflict = conflict_found } end ---- --- Get the status of working dir --- @return {bool} ---- -local function get_hg_status() - local file = io.popen("hg status -0") - for line in file:lines() do - file:close() - return false - end - file:close() - - return true -end - --- -- Get the status of working dir -- @return {bool} From a605ec520db082f3710ba6003b56d0532c235753 Mon Sep 17 00:00:00 2001 From: Chris Antos Date: Mon, 15 May 2023 09:18:59 -0700 Subject: [PATCH 18/22] Clean luacheck warnings. --- vendor/clink.lua | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/vendor/clink.lua b/vendor/clink.lua index 486426b..83ef0c0 100644 --- a/vendor/clink.lua +++ b/vendor/clink.lua @@ -3,7 +3,12 @@ -- !!! THIS FILE IS OVERWRITTEN WHEN CMDER IS UPDATED -- !!! Use "%CMDER_ROOT%\config\.lua" to add your lua startup scripts --- luacheck: globals clink +-- luacheck: globals CMDER_SESSION +-- luacheck: globals uah_color cwd_color lamb_color clean_color dirty_color conflict_color unknown_color +-- luacheck: globals prompt_homeSymbol prompt_lambSymbol prompt_type prompt_useHomeSymbol prompt_useUserAtHost +-- luacheck: globals prompt_singleLine prompt_includeVersionControl +-- luacheck: globals prompt_overrideGitStatusOptIn prompt_overrideSvnStatusOptIn +-- luacheck: globals clink io.popenyield os.isdir settings.get -- At first, load the original clink.lua file -- this is needed as we set the script path to this dir and therefore the original @@ -191,7 +196,7 @@ end local function get_dir_contains(path, dirname) -- return parent path for specified entry (either file or directory) - local function pathname(path) + local function pathname(path) -- luacheck: ignore 432 local prefix = "" local i = path:find("[\\/:][^\\/:]*$") if i then @@ -201,14 +206,14 @@ local function get_dir_contains(path, dirname) end -- Navigates up one level - local function up_one_level(path) + local function up_one_level(path) -- luacheck: ignore 432 if path == nil then path = '.' end if path == '.' then path = clink.get_cwd() end return pathname(path) end -- Checks if provided directory contains git directory - local function has_specified_dir(path, specified_dir) + local function has_specified_dir(path, specified_dir) -- luacheck: ignore 432 if path == nil then path = '.' end local found_dirs = clink.find_dirs(path..'/'..specified_dir) if #found_dirs > 0 then return true end @@ -236,7 +241,7 @@ end local function get_git_dir(path) -- return parent path for specified entry (either file or directory) - local function pathname(path) + local function pathname(path) -- luacheck: ignore 432 local prefix = "" local i = path:find("[\\/:][^\\/:]*$") if i then @@ -346,7 +351,7 @@ end -- Find out current branch -- @return {false|svn branch name} --- -local function get_svn_branch(svn_dir) +local function get_svn_branch() local file = io_popenyield("svn info 2>nul") if not file then return false @@ -379,7 +384,7 @@ local function get_git_status() for line in file:lines() do local code = line:sub(1, 2) -- print (string.format("code: %s, line: %s", code, line)) - if code == "DD" or code == "AU" or code == "UD" or code == "UA" or code == "DU" or code == "AA" or code == "UU" then + if code == "DD" or code == "AU" or code == "UD" or code == "UA" or code == "DU" or code == "AA" or code == "UU" then -- luacheck: no max line length is_status = false conflict_found = true break @@ -608,7 +613,7 @@ local function svn_prompt_filter() end -- Get the svn status using coroutine if available and option is enabled. Otherwise use a blocking call local svnStatus - if clink.promptcoroutine and io.popenyield and settings.get("prompt.async") and prompt_overrideSvnStatusOptIn then + if clink.promptcoroutine and io.popenyield and settings.get("prompt.async") and prompt_overrideSvnStatusOptIn then -- luacheck: no max line length svnStatus = clink_promptcoroutine(function () return get_svn_status() end) From 48e4dff882c0374e03c48c09f4ea091071973c9f Mon Sep 17 00:00:00 2001 From: DRSDavidSoft Date: Tue, 16 May 2023 13:40:42 +0000 Subject: [PATCH 19/22] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependencie?= =?UTF-8?q?s=20(clink-completions=20v0.4.8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vendor/sources.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/sources.json b/vendor/sources.json index a846108..0bd8563 100644 --- a/vendor/sources.json +++ b/vendor/sources.json @@ -16,7 +16,7 @@ }, { "name": "clink-completions", - "version": "0.4.7", - "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.4.7.zip" + "version": "0.4.8", + "url": "https://github.com/vladimir-kotikov/clink-completions/archive/v0.4.8.zip" } ] From 34f2aabb8eec4f4bee6a25ad3927d7cb88a867dd Mon Sep 17 00:00:00 2001 From: Martin Kemp Date: Tue, 23 May 2023 11:11:39 +0100 Subject: [PATCH 20/22] Remove PSGet Entirely Fixes #2841 Signed-off-by: Martin Kemp --- vendor/profile.ps1 | 1 - vendor/psmodules/PsGet/PsGet.psm1 | 2155 ----------------------------- 2 files changed, 2156 deletions(-) delete mode 100644 vendor/psmodules/PsGet/PsGet.psm1 diff --git a/vendor/profile.ps1 b/vendor/profile.ps1 index d1087b1..1183377 100644 --- a/vendor/profile.ps1 +++ b/vendor/profile.ps1 @@ -28,7 +28,6 @@ if (!$ENV:CMDER_ROOT) { # Remove trailing '\' $ENV:CMDER_ROOT = ($ENV:CMDER_ROOT).TrimEnd("\") -# Do not load bundled PsGet if a module installer is already available # -> recent PowerShell versions include PowerShellGet out of the box $moduleInstallerAvailable = [bool](Get-Command -Name 'Install-Module' -ErrorAction SilentlyContinue) diff --git a/vendor/psmodules/PsGet/PsGet.psm1 b/vendor/psmodules/PsGet/PsGet.psm1 deleted file mode 100644 index 4774dca..0000000 --- a/vendor/psmodules/PsGet/PsGet.psm1 +++ /dev/null @@ -1,2155 +0,0 @@ -<# -.SYNOPSIS - PowerShell module installation stuff. - URL: https://github.com/psget/psget - Based on http://poshcode.org/1875 Install-Module by Joel Bennett -#> -#requires -Version 2.0 - -#region Setup - -Write-Debug 'Set up the global scope config variables.' -if ([Environment]::GetFolderPath('MyDocuments')) { - $global:UserModuleBasePath = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath 'WindowsPowerShell\Modules' -} -else { - # Support scenarios where PSGet is running without a MyDocuments special folder (e.g. executing within a DSC resource) - $global:UserModuleBasePath = Join-Path -Path $env:ProgramFiles -ChildPath 'WindowsPowerShell\Modules' -} - -# NOTE: Path changed to align with current MS conventions -$global:CommonGlobalModuleBasePath = Join-Path -Path $env:ProgramFiles -ChildPath 'WindowsPowerShell\Modules' - -if (-not (Test-Path -Path:variable:global:PsGetDirectoryUrl)) { - $global:PsGetDirectoryUrl = 'https://github.com/psget/psget/raw/master/Directory.xml' -} -# NOTE: $global:PsGetDestinationModulePath is used by Install-Module as configuration if set by user. - -Write-Debug 'Set up needed constants.' -Set-Variable -Name PSGET_ZIP -Value 'ZIP' -Option Constant -Scope Script -Set-Variable -Name PSGET_PSM1 -Value 'PSM1' -Option Constant -Scope Script -Set-Variable -Name PSGET_PSD1 -Value 'PSD1' -Option Constant -Scope Script - -#endregion - -#region Exported Cmdlets - -<# - .SYNOPSIS - Installs PowerShell modules from a variety of sources including: Nuget, PsGet module directory, local directory, zipped folder and web URL. - - .DESCRIPTION - Supports installing modules for the current user or all users (if elevated). - - .PARAMETER Module - Name of the module to install. - - .PARAMETER ModuleUrl - URL to the module to install; Can be direct link to PSM1 file or ZIP file. Can be a shortened link. - - .PARAMETER ModulePath - Local path to the module to install. - - .PARAMETER ModuleName - In context with -ModuleUrl or -ModulePath it is not always possible to interfere the right ModuleName, eg. the filename is unknown or the zip archive contains multiple modules. - - .PARAMETER Type - When ModuleUrl or ModulePath specified, allows specifying type of the package. Can be ZIP or PSM1. - - .PARAMETER NuGetPackageId - NuGet package name containing the module to install. - - .PARAMETER PackageVersion - Allows a specific version of the specified NuGet package to used, if not specified then the latest stable version will be used. - - .PARAMETER NugetSource - URL to the NuGet feed containing the package. - - .PARAMETER PreRelease - If PackageVersion is not specified, then this switch allows the latest prerelease package to be used. - - .PARAMETER PreReleaseTag - If PackageVersion is not specified, then this parameter allows the latest version of a particular prerelease tag to be used - - .PARAMETER Destination - When specified the module will be installed below this path. Defaults to '$global:PsGetDestinationModulePath' if defined. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - If set, attempts to install the module to the all users location in C:\Program Files\Common Files\Modules... - - NOTE: If the -Destination directory is specified, then -Global will only have an effect in combination with '-PersistEnvironment'. This is also the case if '$global:PsGetDestinationModulePath' is defined. - - .PARAMETER DoNotImport - Indicates that command should not import module after installation - - .PARAMETER AddToProfile - Adds Import-Module statement for installed module to the profile.ps1 - - .PARAMETER Update - Forces module to be updated - - .PARAMETER DirectoryUrl - URL to central directory. By default it uses the value in the $global:PsGetDirectoryUrl variable - - .PARAMETER PersistEnvironment - If this switch is specified, the installation destination path will be added to either the User's PSModulePath environment variable or Machine's PSModulePath environment variable (if -Global specified) - - .PARAMETER InstallWithModuleName - Allows to specify the name of the module and override the ModuleName normally used. - NOTE: This parameter allows to install a module from the PsGet-Directory more than once and PsGet does not remember that this module is installed with a different name. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. - Default: definition in directory file or 'Install.ps1' - - .PARAMETER Force - OBSOLETE - Alternative name for 'Update'. - - .PARAMETER Startup - OBSOLETE - Alternative name for 'AddToProfile'. - - .LINK - http://psget.net - - .EXAMPLE - # Install-Module PsConfig -DoNotImport - - Description - ----------- - Installs the module without importing it to the current session - - .EXAMPLE - # Install-Module PoshHg -AddToProfile - - Description - ----------- - Installs the module and then adds impoer of the given module to your profile.ps1 file - - .EXAMPLE - # Install-Module PsUrl - - Description - ----------- - This command will query module information from central registry and install required stuff. - - .EXAMPLE - # Install-Module -ModulePath .\Authenticode.psm1 -Global - - Description - ----------- - Installs the Authenticode module to the System32\WindowsPowerShell\v1.0\Modules for all users to use. - - .EXAMPLE - # Install-Module -ModuleUrl https://github.com/chaliy/psurl/raw/master/PsUrl/PsUrl.psm1 - - Description - ----------- - Installs the PsUrl module to the users modules folder - - .EXAMPLE - # Install-Module -ModuleUrl http://bit.ly/e1X4BO -ModuleName "PsUrl" - - Description - ----------- - Installs the PsUrl module with name specified, because command will not be able to guess it - - .EXAMPLE - # Install-Module -ModuleUrl https://github.com/psget/psget/raw/master/TestModules/HelloWorld.zip - - Description - ----------- - Downloads HelloWorld module (module can have more than one file) and installs it - - .EXAMPLE - # Install-Module -NugetPackageId SomePackage - - Description - ----------- - Downloads the latest stable version of the 'SomePackage' module from the NuGet Gallery - - .EXAMPLE - # Install-Module -NugetPackageId SomePackage -PackageVersion 1.0.2-beta - - Description - ----------- - Downloads the specified version of the 'SomePackage' module from the NuGet Gallery - - .EXAMPLE - # Install-Module -NugetPackageId SomePackage -PreRelease - - Description - ----------- - Downloads the latest pre-release version of the 'SomePackage' module from the NuGet Gallery - - .EXAMPLE - # Install-Module -NugetPackageId SomePackage -PreReleaseTag beta -NugetSource http://myget.org/F/myfeed - - Description - ----------- - Downloads the latest 'beta' pre-release version of the 'SomePackage' module from a custom NuGet feed -#> -function Install-Module { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true, ParameterSetName='CentralDirectory')] - [String] $Module, - - [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, ParameterSetName='Web')] - [String] $ModuleUrl, - - [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, ParameterSetName='Local')] - [String] $ModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='Web')] - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='Local')] - [String] $ModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='Web')] - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='Local')] - [ValidateSet('ZIP', 'PSM1', 'PSD1', '')] # $script:PSGET_ZIP, $script:PSGET_PSM1 or $script:PSGET_PSD1 - [String] $Type, - - [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, ParameterSetName='NuGet')] - [ValidatePattern('^\w+([_.-]\w+)*$')] # regex from NuGet.PackageIdValidator._idRegex - [ValidateLength(1,100)] # maximum length from NuGet.PackageIdValidator.MaxPackageIdLength - [String] $NuGetPackageId, - - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NuGet')] - [String] $PackageVersion, - - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NuGet')] - [String] $NugetSource = 'https://nuget.org/api/v2/', - - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NuGet')] - [Switch] $PreRelease, - - [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NuGet')] - [String] $PreReleaseTag, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $Destination = $global:PsGetDestinationModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleHash, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Global, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotImport, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $AddToProfile, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Update, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $DirectoryUrl = $global:PsGetDirectoryUrl, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $PersistEnvironment, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $InstallWithModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotPostInstall, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PostInstallHook, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Force, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Startup - ) - process { - - if ($Force) { - Write-Verbose 'Force parameter is considered obsolete. Please use Update instead.' - $Update = $true - } - - if ($Startup) { - Write-Verbose 'Startup parameter is considered obsolete. Please use AddToProfile instead.' - $AddToProfile = $true - } - - if (-not $Destination) { - $Destination = if ($Global) { $global:CommonGlobalModuleBasePath } else { $global:UserModuleBasePath } - - #Because we are using the default location, always ensure it is persisted - $PersistEnvironment = $true - } - - if (-not $Destination) { - throw 'The destination path was not added to the PSModulePath environment variable, ensure you have the rights to modify environment variables' - } - - $Destination = ConvertTo-CanonicalPath -Path $Destination - - Write-Debug "Execute installation for '$($PSCmdlet.ParameterSetName)' type." - - switch($PSCmdlet.ParameterSetName) { - CentralDirectory { - Install-ModuleFromDirectory -Module:$Module -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -DirectoryUrl:$DirectoryUrl -InstallWithModuleName:$InstallWithModuleName -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } - Web { - Install-ModuleFromWeb -ModuleUrl:$ModuleUrl -ModuleName:$ModuleName -Type:$Type -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -InstallWithModuleName:$InstallWithModuleName -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } - Local { - Install-ModuleFromLocal -ModulePath:$ModulePath -ModuleName:$ModuleName -Type:$Type -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -InstallWithModuleName:$InstallWithModuleName -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } - NuGet { - Install-ModuleFromNuGet -NuGetPackageId:$NuGetPackageId -PackageVersion:$PackageVersion -NugetSource:$NugetSource -PreRelease:$PreRelease -PreReleaseTag:$PreReleaseTag -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -InstallWithModuleName:$InstallWithModuleName -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } - default { - throw "Unknown ParameterSetName '$($PSCmdlet.ParameterSetName)'" - } - } - } -} - -<# - .SYNOPSIS - Updates a module. - - .DESCRIPTION - Supports updating modules for the current user or all users (if elevated). - - .PARAMETER Module - Name of the module to update. - - .PARAMETER All - If -All is defined. all to PsGet known modules will be updated. - - .PARAMETER Destination - When specified the module will be updated below this path. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - If set, attempts to install the module to the all users location in Windows\System32... - - .PARAMETER DoNotImport - Indicates that command should not import module after installation. - - .PARAMETER AddToProfile - Adds installed module to the profile.ps1. - - .PARAMETER Update - Forces module to be updated. - - .PARAMETER DirectoryUrl - URL to central directory. By default it uses the value in the $PsGetDirectoryUrl global variable. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. - Will not be check in combination with -All switch. - Default: 'Install.ps1' - - .LINK - http://psget.net - - .LINK - Install-Module - - .EXAMPLE - # Update-Module PsUrl - - Description - ----------- - Updates the module -#> -function Update-Module { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true)] - [String] $Module, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $All, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $Destination = $global:PsGetDestinationModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleHash, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Global, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotImport, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $AddToProfile, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $DirectoryUrl = $global:PsGetDirectoryUrl, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotPostInstall, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PostInstallHook - ) - process { - if ($All) { - Install-Module -Module PSGet -Force -DoNotImport - - Get-PsGetModuleInfo -ModuleName '*' | Where-Object { - if ($_.Id -ne 'PSGet') { - Get-Module -Name:($_.ModuleName) -ListAvailable - } - } | Install-Module -Update - - Import-Module -Name PSGet -Force -DoNotPostInstall:$DoNotPostInstall - - } - else { - Install-Module -Module:$Module -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -DirectoryUrl:$DirectoryUrl -Update -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } - } -} - -<# - .SYNOPSIS - Retrieve information about module from central directory - - .DESCRIPTION - Command will query central directory to get information about module specified. - - .PARAMETER ModuleName - Name of module to look for in directory. Supports wildcards. - - .PARAMETER DirectoryUrl - URL to central directory. By default it uses the value in the $PsGetDirectoryUrl global variable. - - .LINK - http://psget.net - - .EXAMPLE - Get-PsGetModuleInfo PoshCo* - - Description - ----------- - Retrieves information about all registered modules that start with PoshCo. -#> -function Get-PsGetModuleInfo { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true)] - [String] $ModuleName, - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $DirectoryUrl = $global:PsGetDirectoryUrl - ) - begin { - $client = (new-object Net.WebClient) - $client.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials - - $PsGetDataPath = Join-Path -Path $Env:APPDATA -ChildPath psget - $DirectoryCachePath = Join-Path -Path $PsGetDataPath -ChildPath directorycache.clixml - $DirectoryCache = @() - $CacheEntry = $null - if (Test-Path -Path $DirectoryCachePath) { - $DirectoryCache = Import-Clixml -Path $DirectoryCachePath - $CacheEntry = $DirectoryCache | Where-Object { $_.Url -eq $DirectoryUrl } | Select-Object -First 1 - } - if (-not $CacheEntry) { - $CacheEntry = @{ - Url = $DirectoryUrl - File = '{0}.xml' -f [Guid]::NewGuid().Tostring() - ETag = $null - } - $DirectoryCache += @($CacheEntry) - } - $CacheEntryFilePath = Join-Path -Path $PsGetDataPath -ChildPath $CacheEntry.File - if ($CacheEntry -and $CacheEntry.ETag -and (Test-Path -Path $CacheEntryFilePath)) { - if ((Get-Item -Path $CacheEntryFilePath).LastWriteTime.AddDays(1) -gt (Get-Date)) { - # use cached directory if it is less than 24 hours old - $client.Headers.Add('If-None-Match', $CacheEntry.ETag) - } - } - - try { - Write-Verbose "Downloading modules repository from $DirectoryUrl" - $stream = $client.OpenRead($DirectoryUrl) - $repoXmlTemp = New-Object -TypeName System.Xml.XmlDocument - $repoXmlTemp.Load($stream) - $StatusCode = 200 - } - catch [System.Net.WebException] { - $Response = $_.Exception.Response - if ($Response) { $StatusCode = [int]$Response.StatusCode } - } - - if ($StatusCode -eq 200) { - $repoXml = [xml]$repoXmlTemp - - $CacheEntry.ETag = $client.ResponseHeaders['ETag'] - if (-not (Test-Path -Path $PsGetDataPath)) { - New-Item -Path $PsGetDataPath -ItemType Container | Out-Null - } - $repoXml.Save($CacheEntryFilePath) - Export-Clixml -InputObject $DirectoryCache -Path $DirectoryCachePath - } - elseif (Test-Path -Path $CacheEntryFilePath) { - if ($StatusCode -ne 304) { - Write-Warning "Could not retrieve modules repository from '$DirectoryUrl'. Status code: $StatusCode" - } - Write-Verbose 'Using cached copy of modules repository' - $repoXml = [xml](Get-Content -Path $CacheEntryFilePath) - } - else { - throw "Could not retrieve modules repository from '$DirectoryUrl'. Status code: $StatusCode" - } - - $nss = @{ a = 'http://www.w3.org/2005/Atom'; - pg = 'urn:psget:v1.0' } - - $feed = $repoXml.feed - $title = $feed.title.innertext - Write-Verbose "Processing $title feed..." - } - process { - # Very naive, ignoring namespaces and so on. - $feed.entry | Where-Object { $_.id -like $ModuleName } | - ForEach-Object { - $Type = '' - switch -regex ($_.content.type) { - 'application/zip' { $Type = $PSGET_ZIP } - default { $Type = $PSGET_PSM1 } - } - - $Verb = if ($_.properties.Verb -imatch 'POST') { 'POST' } else { 'GET' } - - New-Object PSObject -Property @{ - Title = $_.title.innertext - Description = $_.summary.'#text' - Updated = [DateTime]$_.updated - Author= $_.author.name - Id = $_.id - ModuleName = if ($_.properties.ModuleName) { $_.properties.ModuleName } else { $_.id } - Type = $Type - DownloadUrl = $_.content.src - Verb = $Verb - #This was changed from using the $_.properties.ProjectUrl because the value for ModuleUrl needs to be the full path to the module file - #This change was required to get the tests to pass - ModuleUrl = $_.content.src - NoPostInstallHook = if ($_.properties.NoPostInstallHook -eq 'true') { $true } else { $false } - PostInstallHook = $_.properties.PostInstallHook - PostUpdateHook = $_.properties.PostUpdateHook - } | - Select-Object Title, ModuleName, Id, Description, Updated, Type, Verb, ModuleUrl, DownloadUrl, NoPostInstallHook, PostInstallHook, PostUpdateHook - } - } -} - -<# - .SYNOPSIS - Calculate the hash value of a module. - - .DESCRIPTION - Calculate the hash value of the specified module directory for usage with the 'ModuleHash' parameter for validation. - - .PARAMETER Path - Path to the module directory - - .EXAMPLE - Get-PsGetModuleHash $global:UserModuleBasePath\PsGet - - Description - ----------- - Returns the hash value usable with the 'ModuleHash' parameter of 'Install-Module' - - .LINK - Install-Module - - .LINK - http://psget.net -#> -function Get-PsGetModuleHash { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true)] - [Alias('ModuleBase')] - [String] $Path - ) - process { - Get-FolderHash -Path (Resolve-Path -Path $Path).Path - } -} - -#endregion - -#region Sub-Cmdlets - -<# - .SYNOPSIS - Install a module from the defined PsGet directory. - - .PARAMETER Module - Name of the module to install from PsGet directory. - - .PARAMETER Destination - When specified the module will be installed below this path. Defaults to '$global:PsGetDestinationModulePath' if defined. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - If set, attempts to install the module to the all users location in C:\Program Files\Common Files\Modules... - - NOTE: If the -Destination directory is specified, then -Global will only have an effect in combination with '-PersistEnvironment'. This is also the case if '$global:PsGetDestinationModulePath' is defined. - - .PARAMETER DoNotImport - Indicates that command should not import module after installation - - .PARAMETER AddToProfile - Adds Import-Module statement for installed module to the profile.ps1 - - .PARAMETER Update - Forces module to be updated - - .PARAMETER DirectoryUrl - URL to central directory. By default it uses the value in the $global:PsGetDirectoryUrl variable - - .PARAMETER PersistEnvironment - If this switch is specified, the installation destination path will be added to either the User's PSModulePath environment variable or Machine's PSModulePath environment variable (if -Global specified) - - .PARAMETER InstallWithModuleName - Allows to specify the name of the module and override the ModuleName normally used. - NOTE: This parameter allows to install a module from the PsGet-Directory more than once and PsGet does not remember that this module is installed with a different name. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. - Default: definition in directory file or 'Install.ps1' -#> -function Install-ModuleFromDirectory { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true)] - [String] $Module, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $Destination = $global:PsGetDestinationModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleHash, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Global, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotImport, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $AddToProfile, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Update, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $DirectoryUrl = $global:PsGetDirectoryUrl, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $PersistEnvironment, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $InstallWithModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotPostInstall, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PostInstallHook - ) - process { - $testModuleName = if ($InstallWithModuleName) { $InstallWithModuleName } else { $Module } - if (Test-ModuleInstalledAndImport -ModuleName:$testModuleName -Destination:$Destination -Update:$Update -DoNotImport:$DoNotImport -ModuleHash:$ModuleHash) { - return - } - - Write-Verbose "Module $Module will be installed from central repository" - $moduleData = Get-PsGetModuleInfo -ModuleName:$Module -DirectoryUrl:$DirectoryUrl | select -First 1 - if (-not $moduleData) { - throw "Module $Module was not found in central repository" - } - - # $Module and $moduleData.Id are not equally by guarantee, so we have to test again. - if (Test-ModuleInstalledAndImport -ModuleName:$moduleData.ModuleName -Destination:$Destination -Update:$Update -DoNotImport:$DoNotImport -ModuleHash:$ModuleHash) { - return - } - - if (-not $DoNotPostInstall) { - $DoNotPostInstall = $moduledata.NoPostInstallHook - } - - if (-not $PostInstallHook) { - if ($Update) { - $PostInstallHook = $moduleData.PostUpdateHook - } - else { - $PostInstallHook = $moduleData.PostInstallHook - } - - if (-not $PostInstallHook) { - $PostInstallHook = 'Install.ps1' - } - } - - $result = Invoke-DownloadModuleFromWeb -DownloadUrl:$moduleData.DownloadUrl -ModuleName:$moduleData.ModuleName -Type:$moduleData.Type -Verb:$moduleData.Verb - Install-ModuleToDestination -ModuleName:$result.ModuleName -InstallWithModuleName:$InstallWithModuleName -ModuleFolderPath:$result.ModuleFolderPath -TempFolderPath:$result.TempFolderPath -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } -} - -<# - .SYNOPSIS - Install a module from a provided download location. - - .PARAMETER ModuleUrl - URL to the module to install; Can be direct link to PSM1 file or ZIP file. Can be a shortened link. - - .PARAMETER ModuleName - It is not always possible to interfere the right ModuleName, eg. the filename is unknown or the zip archive contains multiple modules. - - .PARAMETER Type - When ModuleUrl or ModulePath specified, allows specifying type of the package. Can be ZIP or PSM1. - - .PARAMETER Destination - When specified the module will be installed below this path. Defaults to '$global:PsGetDestinationModulePath' if defined. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - If set, attempts to install the module to the all users location in C:\Program Files\Common Files\Modules... - - NOTE: If the -Destination directory is specified, then -Global will only have an effect in combination with '-PersistEnvironment'. This is also the case if '$global:PsGetDestinationModulePath' is defined. - - .PARAMETER DoNotImport - Indicates that command should not import module after installation - - .PARAMETER AddToProfile - Adds Import-Module statement for installed module to the profile.ps1 - - .PARAMETER Update - Forces module to be updated - - .PARAMETER PersistEnvironment - If this switch is specified, the installation destination path will be added to either the User's PSModulePath environment variable or Machine's PSModulePath environment variable (if -Global specified) - - .PARAMETER InstallWithModuleName - Allows to specify the name of the module and override the ModuleName normally used. - NOTE: This parameter allows to install a module from the PsGet-Directory more than once and PsGet does not remember that this module is installed with a different name. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. - Default: 'Install.ps1' -#> -function Install-ModuleFromWeb { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true)] - [String] $ModuleUrl, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [ValidateSet('ZIP', 'PSM1', 'PSD1', '')] # $script:PSGET_ZIP, $script:PSGET_PSM1 or $script:PSGET_PSD1 - [String] $Type, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $Destination = $global:PsGetDestinationModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleHash, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Global, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotImport, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $AddToProfile, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Update, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $PersistEnvironment, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $InstallWithModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotPostInstall, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PostInstallHook - ) - process { - Write-Verbose "Module will be installed from $ModuleUrl" - - if ($InstallWithModuleName) { - if (Test-ModuleInstalledAndImport -ModuleName:$InstallWithModuleName -Destination:$Destination -Update:$Update -DoNotImport:$DoNotImport -ModuleHash:$ModuleHash) { - return - } - } - - $result = Invoke-DownloadModuleFromWeb -DownloadUrl:$ModuleUrl -ModuleName:$ModuleName -Type:$Type -Verb:'GET' - - if (-not $PostInstallHook) { - $PostInstallHook = 'Install.ps1' - } - - Install-ModuleToDestination -ModuleName:$result.ModuleName -InstallWithModuleName:$InstallWithModuleName -ModuleFolderPath:$result.ModuleFolderPath -TempFolderPath:$result.TempFolderPath -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } -} - -<# - .SYNOPSIS - Install a module from a provided local path. - - .PARAMETER ModulePath - Local path to the module to install. - - .PARAMETER ModuleName - It is not always possible to interfere the right ModuleName, eg. the filename is unknown or the zip archive contains multiple modules. - - .PARAMETER Type - When ModuleUrl or ModulePath specified, allows specifying type of the package. Can be ZIP or PSM1. - - .PARAMETER Destination - When specified the module will be installed below this path. Defaults to '$global:PsGetDestinationModulePath' if defined. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - If set, attempts to install the module to the all users location in C:\Program Files\Common Files\Modules... - - NOTE: If the -Destination directory is specified, then -Global will only have an effect in combination with '-PersistEnvironment'. This is also the case if '$global:PsGetDestinationModulePath' is defined. - - .PARAMETER DoNotImport - Indicates that command should not import module after installation - - .PARAMETER AddToProfile - Adds Import-Module statement for installed module to the profile.ps1 - - .PARAMETER Update - Forces module to be updated - - .PARAMETER PersistEnvironment - If this switch is specified, the installation destination path will be added to either the User's PSModulePath environment variable or Machine's PSModulePath environment variable (if -Global specified) - - .PARAMETER InstallWithModuleName - Allows to specify the name of the module and override the ModuleName normally used. - NOTE: This parameter allows to install a module from the PsGet-Directory more than once and PsGet does not remember that this module is installed with a different name. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. - Default: 'Install.ps1' -#> -function Install-ModuleFromLocal { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true)] - [String] $ModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [ValidateSet('ZIP', 'PSM1', 'PSD1', '')] # $script:PSGET_ZIP, $script:PSGET_PSM1 or $script:PSGET_PSD1 - [String] $Type, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $Destination = $global:PsGetDestinationModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleHash, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Global, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotImport, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $AddToProfile, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Update, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $PersistEnvironment, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $InstallWithModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotPostInstall, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PostInstallHook - ) - process { - Write-Verbose 'Module will be installed from local path' - - $InstallWithModuleName = if ($InstallWithModuleName) { $InstallWithModuleName } else { $ModuleName } - if ($InstallWithModuleName) { - if (Test-ModuleInstalledAndImport -ModuleName:$InstallWithModuleName -Destination:$Destination -Update:$Update -DoNotImport:$DoNotImport -ModuleHash:$ModuleHash) { - return - } - } - - $tempFolderPath = Join-Path ([IO.Path]::GetTempPath()) ([Guid]::NewGuid().ToString()) - New-Item $tempFolderPath -ItemType Directory | Out-Null - Write-Debug "Temporary work directory created: $tempFolderPath" - - trap { Remove-Item -Path $tempFolderPath -Recurse -Force ; break } - - $newModulePath = Join-Path -Path $tempFolderPath -ChildPath 'module' - New-Item $newModulePath -ItemType Directory | Out-Null - - if (Test-Path -Path $ModulePath -PathType Leaf) { - $extension = (Get-Item $ModulePath).Extension - if ($extension -eq '.psm1') { - $Type = if ($Type) { $Type } else { $PSGET_PSM1 } - } elseif ($extension -eq '.zip') { - $Type = if ($Type) { $Type } else { $PSGET_ZIP } - } - - if ($Type -eq $PSGET_ZIP) { - Expand-ZipModule $ModulePath $newModulePath - } - else { - Copy-Item -Path $ModulePath -Destination $newModulePath - } - } - elseif (Test-Path -Path $ModulePath -PathType Container) { - Copy-Item -Path $ModulePath -Destination $newModulePath -Force -Recurse - } - else { - throw "ModulePath '$ModulePath' does not point to an module." - } - - $foundResult = Find-ModuleNameAndFolder -Path $newModulePath -ModuleName $ModuleName - - if (-not $PostInstallHook) { - $PostInstallHook = 'Install.ps1' - } - - Install-ModuleToDestination -ModuleName:$foundResult.ModuleName -InstallWithModuleName:$InstallWithModuleName -ModuleFolderPath:$foundResult.ModuleFolderPath -TempFolderPath:$tempFolderPath -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } -} - -<# - .SYNOPSIS - Install a module from a NuGet source. - - .PARAMETER NuGetPackageId - NuGet package name containing the module to install. - - .PARAMETER PackageVersion - Allows a specific version of the specified NuGet package to used, if not specified then the latest stable version will be used. - - .PARAMETER NugetSource - URL to the NuGet feed containing the package. - - .PARAMETER PreRelease - If PackageVersion is not specified, then this switch allows the latest prerelease package to be used. - - .PARAMETER PreReleaseTag - If PackageVersion is not specified, then this parameter allows the latest version of a particular prerelease tag to be used - - .PARAMETER Destination - When specified the module will be installed below this path. Defaults to '$global:PsGetDestinationModulePath' if defined. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - If set, attempts to install the module to the all users location in C:\Program Files\Common Files\Modules... - - NOTE: If the -Destination directory is specified, then -Global will only have an effect in combination with '-PersistEnvironment'. This is also the case if '$global:PsGetDestinationModulePath' is defined. - - .PARAMETER DoNotImport - Indicates that command should not import module after installation - - .PARAMETER AddToProfile - Adds Import-Module statement for installed module to the profile.ps1 - - .PARAMETER Update - Forces module to be updated - - .PARAMETER PersistEnvironment - If this switch is specified, the installation destination path will be added to either the User's PSModulePath environment variable or Machine's PSModulePath environment variable (if -Global specified) - - .PARAMETER InstallWithModuleName - Allows to specify the name of the module and override the ModuleName normally used. - NOTE: This parameter allows to install a module from the PsGet-Directory more than once and PsGet does not remember that this module is installed with a different name. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. - Default: 'Install.ps1' -#> -function Install-ModuleFromNuGet { - [CmdletBinding()] - param ( - [Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true)] - [ValidatePattern('^\w+([_.-]\w+)*$')] # regex from NuGet.PackageIdValidator._idRegex - [ValidateLength(1,100)] # maximum length from NuGet.PackageIdValidator.MaxPackageIdLength - [String] $NuGetPackageId, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PackageVersion, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $NugetSource = 'https://nuget.org/api/v2/', - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $PreRelease, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PreReleaseTag, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $Destination = $global:PsGetDestinationModulePath, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $ModuleHash, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Global, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotImport, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $AddToProfile, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $Update, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $PersistEnvironment, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $InstallWithModuleName, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [Switch] $DoNotPostInstall, - - [Parameter(ValueFromPipelineByPropertyName=$true)] - [String] $PostInstallHook - ) - process { - Write-Verbose 'Module will be installed from NuGet' - $InstallWithModuleName = if ($InstallWithModuleName) { $InstallWithModuleName } else { $NuGetPackageId } - - if (Test-ModuleInstalledAndImport -ModuleName:$InstallWithModuleName -Destination:$Destination -Update:$Update -DoNotImport:$DoNotImport -ModuleHash:$ModuleHash) { - return - } - - if (-not $PostInstallHook) { - $PostInstallHook = 'Install.ps1' - } - - try { - $result = Invoke-DownloadNugetPackage -NuGetPackageId $NuGetPackageId -PackageVersion $PackageVersion -Source $NugetSource -PreRelease:$PreRelease -PreReleaseTag $PreReleaseTag - Install-ModuleToDestination -ModuleName:$result.ModuleName -InstallWithModuleName:$InstallWithModuleName -ModuleFolderPath:$result.ModuleFolderPath -TempFolderPath:$result.TempFolderPath -Destination:$Destination -ModuleHash:$ModuleHash -Global:$Global -PersistEnvironment:$PersistEnvironment -DoNotImport:$DoNotImport -AddToProfile:$AddToProfile -Update:$Update -DoNotPostInstall:$DoNotPostInstall -PostInstallHook:$PostInstallHook - } - catch { - Write-Error $_.Exception.Message - return - } - } -} - -#endregion - -#region Internal Cmdlets -#region Module Installation -<# - .SYNOPSIS - Adds value to a "Path" type of environment variable (PATH or PSModulePath). Path type of variables munge the User and Machine values into the value for the current session. - - .PARAMETER Global - The System.EnvironmentVariableTarget of what type of environment variable to modify ("Machine","User" or "Session") - - .PARAMETER PathToAdd - The actual path to add to the environment variable - - .PARAMETER PersistEnvironment - If specified, will permanently store the variable in registry - - .EXAMPLE - AddPathToPSModulePath -Scope "Machine" -PathToAdd "$env:CommonProgramFiles\Modules" - - Description - ----------- - This command add the path "$env:CommonProgramFiles\Modules" to the Machine PSModulePath environment variable -#> -function Add-PathToPSModulePath { - [CmdletBinding()] - param ( - - [Parameter(Mandatory=$true)] - [string] $PathToAdd, - - [switch] $PersistEnvironment, - - [switch] $Global - ) - process { - $PathToAdd = ConvertTo-CanonicalPath -Path $PathToAdd - - if(-not $PersistEnvironment) { - if (-not ($env:PSModulePath.Contains($PathToAdd))) { - Write-Warning "Module install destination `"$PathToAdd`" is not included in the PSModulePath environment variable." - } - return - } - - $scope = 'User' - if ($Global) { - Write-Verbose 'The Machine environment variable PSModulePath will be modified.' - $scope = 'Machine' - } - - $pathValue = '' + [Environment]::GetEnvironmentVariable('PSModulePath', $scope) - - if (-not ($pathValue.Contains($PathToAdd))) { - if ($pathValue -eq '') { - Write-Debug "PSModulePath for scope '$scope' was read empty. Setting PowerShell default instead." - if ($scope -eq 'User') { - $pathValue = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath 'WindowsPowerShell\Modules' - } - else { - $pathValue = Join-Path -Path $PSHOME -ChildPath 'Modules' - } - } - - if (-not ($pathValue.Contains($PathToAdd))) { - $pathValue = "$pathValue;$PathToAdd" - } - - [Environment]::SetEnvironmentVariable('PSModulePath', $pathValue, $scope) - - Update-PSModulePath - - Write-Host """$PathToAdd"" is added to the PSModulePath environment variable" - } - else { - Write-Verbose """$PathToAdd"" already exists in PSModulePath environment variable" - } - } -} - -<# - .SYNOPSIS - Standardize the provided path. - - .DESCRIPTION - A simple routine to standardize path formats. - - .PARAMETER Path -#> -function ConvertTo-CanonicalPath { - [CmdletBinding()] - param( - [Parameter(Mandatory=$true)] - [String] $Path - ) - process { - return [IO.Path]::GetFullPath(($Path.Trim())) - } -} - -<# - .SYNOPSIS - Find the module file in the given path. - - .PARAMETER Path - Path of module - - .PARAMETER ModuleName - Name of the Module -#> -function Get-ModuleFile { - [CmdletBinding()] - param( - [Parameter(Position=0, Mandatory=$true)] - [String] $Path, - - [String] $ModuleName = '*' - ) - process { - $Includes = Get-PossibleModuleFileNames -ModuleName $ModuleName - - # Sort by folder length ensures that we use one from root folder(Issue #12) - $DirectoryNameLengthProperty = @{ - E = { $_.DirectoryName.Length } - } - - # sort by Includes to give PSD1 preference over PSM1, etc - $IncludesPreferenceProperty = @{ - E = { - for ($Index = 0; $Index -lt $Includes.Length; $Index++) { - if ($_.Name -like $Includes[$Index]) { break } - } - $Index - } - } - - Get-ChildItem -Path $Path -Include $Includes -Recurse | - Where-Object { -not $_.PSIsContainer } | - Sort-Object -Property $DirectoryNameLengthProperty, $IncludesPreferenceProperty | - Select-Object -ExpandProperty FullName -First 1 - } -} - -<# - .SYNOPSIS - Get list of possible names for the module file. - - .PARAMETER ModuleName - Name of the module -#> -function Get-PossibleModuleFileNames { - [CmdletBinding()] - param( - [Parameter(Position=0, Mandatory=$true)] - [String] $ModuleName - ) - process { - 'psd1','psm1','ps1','dll','cdxml','xaml' | ForEach-Object { "$ModuleName`.$_" } - } -} - -<# - .SYNOPSIS - Search in the provided folder for a module, if possible with the provided name. - - .PARAMETER Path - Path to search in for the module. - - .PARAMETER ModuleName - ModuleName which is expected. -#> -function Find-ModuleNameAndFolder { - [CmdletBinding()] - param( - [Parameter(Mandatory=$true)] - [String] $Path, - - [String] $ModuleName - ) - process { - if ($ModuleName) { - $moduleFile = Get-ModuleFile -Path $Path -ModuleName $ModuleName - if (-not $moduleFile) { - throw "Could not find a module with name '$ModuleName' in the provided file." - } - } - else { - $moduleFile = Get-ModuleFile -Path $Path - if (-not $moduleFile) { - throw 'Could not find any module in the provided file.' - } - $ModuleName = [IO.Path]::GetFileNameWithoutExtension($moduleFile) - } - - $moduleFolderPath = Split-Path -Path $moduleFile - - return @{ - ModuleName = $ModuleName - ModuleFolderPath = $moduleFolderPath - } - } -} - -<# - .SYNOPSIS - Import given modele - - .DESCRIPTION - Import given module with switch -Global (functions available to other modules) and avoid - a Powershell bug related to binary modules. - - .$ -#> -function Import-ModuleGlobally { - [CmdletBinding()] - param ( - [String] $ModuleName, - [String] $ModuleBase, - [Switch] $Force - ) - process { - Write-Verbose "Importing installed module '$ModuleName' from '$($installedModule.ModuleBase)'" - Import-Module -Name $ModuleBase -Global -Force:$Force - - # For psget no further checks are needed and their execution cause - # an error for the update process of 'psget' - # https://github.com/psget/psget/issues/186 - if ($ModuleName -eq 'PsGet') { - return - } - - $IdentityExtension = [System.IO.Path]::GetExtension((Get-ModuleFile -Path $ModuleBase -ModuleName $ModuleName)) - if ($IdentityExtension -eq '.dll') { - # import module twice for binary modules to workaround PowerShell bug: - # https://connect.microsoft.com/PowerShell/feedback/details/733869/import-module-global-does-not-work-for-a-binary-module - Import-Module -Name $ModuleBase -Global -Force:$Force - } - } -} - -<# - .SYNOPSIS - Download module from URL - - .DESCRIPTION - Download module from URL and try to interfere unknown parameter. - If download target is a zip-archive it will be extracted. - - Returns a map containing the TempFolderPath, ModuleFolderPath and ModuleName. - The TempFolderPath should be removed after processing the result. - - .PARAMETER DownloadUrl - URL to the module delivery file. - - .PARAMETER ModuleName - Name of the module. - - .PARAMETER Type - Type of the module delivery file. - - .PARAMETER Verb - Http method used for download. -#> -function Invoke-DownloadModuleFromWeb { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true)] - [String] $DownloadUrl, - - [String] $ModuleName, - - [String] $Type, - - [String] $Verb - ) - - $tempFolderPath = Join-Path -Path ([IO.Path]::GetTempPath()) -ChildPath ([Guid]::NewGuid().ToString()) - New-Item -Path $tempFolderPath -ItemType Directory | Out-Null - Write-Debug "Temporary work directory created: $tempFolderPath" - - # make certain that the tempFolder will be deleted if there is an error - trap { Remove-Item -Path $tempFolderPath -Recurse -Force; break } - - Write-Verbose "Downloading module from $DownloadUrl" - $client = (new-object Net.WebClient) - $client.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials - $downloadFilePath = Join-Path -Path $tempfolderPath -ChildPath 'download' - if ($Verb -eq 'POST') { - $client.Headers['Content-type'] = 'application/x-www-form-urlencoded' - [IO.File]::WriteAllBytes($downloadFilePath, $client.UploadData($DownloadUrl, '')) - } - else { - $client.DownloadFile($DownloadUrl, $downloadFilePath) - } - - $candidateName = '{undefined}' - $contentDisposition = $client.ResponseHeaders['Content-Disposition'] - Write-Debug "Try to get module file name from content disposition header: Content-Disposition = '$contentDisposition'" - - if ($contentDisposition -match '\bfilename="?(?[^/]+)\.(?psm1|zip)"?') { - $candidateName = $Matches.name - $Type = if ($Type) { $Type } elseif ($Matches.ext -eq 'psm1') { $PSGET_PSM1 } elseif ($Matches.ext -eq 'zip') { $PSGET_ZIP } - } - else { - Write-Debug "Try to get module file name from url: '$DownloadUrl'" - if ($DownloadUrl -match '\b(?[^/]+)\.(?psm1|zip)[\#\?]*') { - $candidateName = $Matches.name - $Type = if ($Type) { $Type } elseif ($Matches.ext -eq 'psm1') { $PSGET_PSM1 } elseif ($Matches.ext -eq 'zip') { $PSGET_ZIP } - } - else { - $locationHeader = $client.ResponseHeaders['Location'] - Write-Debug "Check location header in case of redirect: '$locationHeader'" - if ($locationHeader -match '\b(?[^/]+)\.(?psm1|zip)[\#\?]*') { - $candidateName = $Matches.name - $Type = if ($Type) { $Type } elseif ($Matches.ext -eq 'psm1') { $PSGET_PSM1 } elseif ($Matches.ext -eq 'zip') { $PSGET_ZIP } - } - } - } - - Write-Debug "Invoke-DownloadModuleFromWeb: CandidateName = '$candidateName'" - - if (-not $Type) { - $contentType = $client.ResponseHeaders['Content-Type'] - Write-Debug "Download header Content-Type: '$contentType'" - if ($contentType -eq 'application/zip') { - $type = $PSGET_ZIP - } - # check downloaded file for the PKZip header - elseif ((Get-Item -Path $downloadFilePath).Length -gt 4) { - Write-Debug 'Search for PKZipHeader' - $knownPKZipHeader = 0x50, 0x4b, 0x03, 0x04 - $fileHeader = Get-Content -Path $downloadFilePath -Encoding Byte -TotalCount 4 - if ([System.BitConverter]::ToString($knownPKZipHeader) -eq [System.BitConverter]::ToString($fileHeader)) { - Write-Debug 'Found PKZipHeader => Type = ZIP' - $type = $PSGET_ZIP - } - else { - Write-Debug 'No PKZipHeader found => Type -ne ZIP' - } - } - - if (-not $Type) { - Write-Debug 'If its most likely no zip it has to be an PSM1 file.' - $Type = $PSGET_PSM1 - } - } - - $moduleFolderPath = Join-Path -Path $tempFolderPath -ChildPath 'module' - New-Item -Path $moduleFolderPath -ItemType Directory | Out-Null - - switch ($Type) { - $PSGET_ZIP { - $zipFilePath = $downloadFilePath + '.zip' - Move-Item -Path $downloadFilePath -Destination $zipFilePath - Expand-ZipModule -Path $zipFilePath -Destination $moduleFolderPath - } - $PSGET_PSM1 { - if (-not $ModuleName) { - if ($candidateName -eq '{undefined}') { - throw 'Cannot guess module name. Try specifying ModuleName argument!' - } - $ModuleName = $candidateName - } - - $psmFilePath = Join-Path -Path $moduleFolderPath -ChildPath "$ModuleName.psm1" - Move-Item -Path $downloadFilePath -Destination $psmFilePath - } - default { - throw "Type $Type is not supported yet" - } - } - - $foundResult = Find-ModuleNameAndFolder -Path $moduleFolderPath -ModuleName $ModuleName - - Write-Debug "Invoke-DownloadModuleFromWeb: ModuleName = '$ModuleName'" - - return @{ - TempFolderPath = $tempFolderPath - ModuleFolderPath = $foundResult.ModuleFolderPath - ModuleName = $foundResult.ModuleName - } -} - -<# - .SYNOPSIS - Install the provided module into the defined destination. - - .DESCRIPTION - Install the module inside of the provided directory into the defined destination - and perform the following steps: - - * Rename module if requested by provided InstallWithModuleName - * If a ModuleHash is provided, check if it matches. - * Add the destination path to the PSModulePath if necessary (depends on provided parameters) - * Place the conventions-matching module folder in the destination folder - * Import the module if necessary - * Add the profile import to profile if necessary - - .PARAMETER ModuleName - The name of the module. - - .PARAMETER InstallWithModuleName - The name the module should get. - - .PARAMETER ModuleFolderPath - The path to the module data, which contains the module main file, named according to ModuleName - - .PARAMETER TempFolderPath - TempPath used by PsGet for doing the work. Contains the ModuleFolderPath and will be deleted after processing, - - .PARAMETER Destination - Path to which the module will be installed. - - .PARAMETER ModuleHash - When ModuleHash is specified the chosen module will only be installed if its contents match the provided hash. - - .PARAMETER Global - Influence the PSModulePath changes and profile changes. - - .PARAMETER PersistEnvironment - Defines if the PSModulePath changes should be persistent. - - .PARAMETER DoNotImport - Defines if the installed module should be imported. - - .PARAMETER AddToProfile - Defines if an 'Import-Module' statement should be added to the profile. - - .PARAMETER Update - Defines if an already existing folder in the target may be deleted for installation of the module. - - .PARAMETER DoNotPostInstall - If defined, the PostInstallHook is not executed. - - .PARAMETER PostInstallHook - Defines the name of a script inside the installed module folder which should be executed after installation. -#> -function Install-ModuleToDestination { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true)] - [String] $ModuleName, - - [Parameter(Mandatory=$true)] - [String] $ModuleFolderPath, - - [Parameter(Mandatory=$true)] - [String] $TempFolderPath, - - [Parameter(Mandatory=$true)] - [String] $Destination, - - [String] $InstallWithModuleName, - - [String] $ModuleHash, - - [Switch] $Global, - - [Switch] $PersistEnvironment, - - [Switch] $DoNotImport, - - [Switch] $AddToProfile, - - [Switch] $Update, - - [Switch] $DoNotPostInstall, - - [String] $PostInstallHook - ) - process { - # Make certain the temp folder is deleted - trap { Remove-Item -Path $TempFolderPath -Recurse -Force; break } - - $InstallWithModuleName = if ($InstallWithModuleName) { $InstallWithModuleName } else { $ModuleName } - # Case: no $InstallWithModuleName and module name interfered from install files - if (Test-ModuleInstalledAndImport -ModuleName:$InstallWithModuleName -Destination:$Destination -Update:$Update -DoNotImport:$DoNotImport -ModuleHash:$ModuleHash) { - Remove-Item -Path $TempFolderPath -Recurse -Force - return - } - - $moduleFilePath = Get-ModuleFile -Path $ModuleFolderPath -ModuleName $ModuleName - # sanity checks - if (-not $moduleFilePath) { - throw 'BUG! Module installation failed in step Install-ModuleToDestination. Please report this issue including your command line.' - } - if ($ModuleFolderPath -ne (Split-Path -Path $moduleFilePath)) { - throw 'BUG! Module installation failed in step Install-ModuleToDestination. Please report this issue including your command line.' - } - - if ($InstallWithModuleName -ne $ModuleName) { - Rename-Item -Path $moduleFilePath -NewName ($InstallWithModuleName + (Get-Item $moduleFilePath).Extension) - } - - $targetFolderPath = Join-Path -Path $Destination -ChildPath $InstallWithModuleName - - if ($ModuleHash) { - Write-Verbose 'Ensure that the hash of the module matches the specified hash' - - $newModuleHash = Get-PsGetModuleHash -Path $ModuleFolderPath - Write-Verbose "Hash of module in '$ModuleFolderPath' is: $newModuleHash" - if ($ModuleHash -ne $newModuleHash) { - throw 'Module contents do not match specified module hash. Ensure the expected hash is correct and the module source is trusted.' - } - - if ( Test-Path $targetFolderPath ) { - Write-Verbose 'Module already exists in destination path. Check if hash in destination is correct. If not replace with to be installed module.' - $destinationModuleHash = Get-PsGetModuleHash -Path $targetFolderPath - if ($destinationModuleHash -ne $ModuleHash ) { - $Update = $true - } - } - } - - #Add the Destination path to the User or Machine environment - Add-PathToPSModulePath -PathToAdd:$Destination -PersistEnvironment:$PersistEnvironment -Global:$Global - - if (-not (Test-Path $targetFolderPath)) { - New-Item $targetFolderPath -ItemType Directory -ErrorAction Continue -ErrorVariable FailMkDir | Out-Null - ## Handle the error if they asked for -Global and don't have permissions - if ($FailMkDir -and @($FailMkDir)[0].CategoryInfo.Category -eq 'PermissionDenied') { - throw "You do not have permission to install a module to '$Destination'. You may need to be elevated." - } - Write-Verbose "Create module folder at $targetFolderPath" - } - - Write-Debug 'Empty existing module folder before copying new files.' - Get-ChildItem -Path $targetFolderPath -Force | Remove-Item -Force -Recurse -ErrorAction Stop - - Write-Debug 'Copy module files to destination folder' - Get-ChildItem -Path $ModuleFolderPath | Copy-Item -Destination $targetFolderPath -Force -Recurse - - if (-not $DoNotPostInstall) { - Write-Verbose "PostInstallHook $PostInstallHook" - if ($PostInstallHook -like '*.ps1') { - $postInstallScript = Join-Path -Path $targetFolderPath -ChildPath $PostInstallHook - if (Test-Path -Path $postInstallScript -PathType Leaf) { - Write-Verbose "'$PostInstallHook' found in module. Let's execute it." - & $postInstallScript - } - else { - Write-Verbose "PostInstallHook '$PostInstallHook' not found." - } - } - } - - $isDestinationInPSModulePath = $env:PSModulePath.Contains($Destination) - if ($isDestinationInPSModulePath) { - if (-not (Get-Module $InstallWithModuleName -ListAvailable)) { - throw 'For some unexpected reasons module was not installed.' - } - } - else { - if (-not (Get-ModuleFile -Path $targetFolderPath)) { - throw 'For some unexpected reasons module was not installed.' - } - } - - if ($Update) { - Write-Host "Module $InstallWithModuleName was successfully updated." -Foreground Green - } - else { - Write-Host "Module $InstallWithModuleName was successfully installed." -Foreground Green - } - - if (-not $DoNotImport) { - Import-ModuleGlobally -ModuleName:$InstallWithModuleName -ModuleBase:$targetFolderPath -Force:$Update - } - - if ($isDestinationInPSModulePath -and $AddToProfile) { - # WARNING $Profile is empty on Win2008R2 under Administrator - if ($PROFILE) { - if (-not (Test-Path $PROFILE)) { - Write-Verbose "Creating PowerShell profile...`n$PROFILE" - New-Item $PROFILE -Type File -Force -ErrorAction Stop - } - - if (Select-String $PROFILE -Pattern "Import-Module $InstallWithModuleName") { - Write-Verbose "Import-Module $InstallWithModuleName command already in your profile" - } - else { - $signature = Get-AuthenticodeSignature -FilePath $PROFILE - - if ($signature.Status -eq 'Valid') { - Write-Error "PsGet cannot modify code-signed profile '$PROFILE'." - } - else { - Write-Verbose "Add Import-Module $InstallWithModuleName command to the profile" - "`nImport-Module $InstallWithModuleName" | Add-Content $PROFILE - } - } - } - - } - - Write-Debug "Cleanup temporary work folder '$TempFolderPath'" - Remove-Item -Path $TempFolderPath -Recurse -Force - } -} - -<# - .SYNOPSIS - Test if module is installed and import it then. - - .DESCRIPTION - Test if module with provided name is installed in the target destination. - If it is installed, it will be imported. Returns '$true' if installed. - - .PARAMETER ModuleName - Name of the module - - .PARAMETER Destination - Installation destination - - .PARAMETER Update - If 'Update'-switch is set, this returns always '$true'. - - .PARAMETER DoNotImport - Switch suppress the import of module. - - .PARAMETER ModuleHash - If a hash is provided an installed module will only be accepted as installed if the hash match. -#> -function Test-ModuleInstalledAndImport { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true)] - [String] $ModuleName, - - [Parameter(Mandatory=$true)] - [String] $Destination, - - [Switch] $Update, - - [Switch] $DoNotImport, - - [String] $ModuleHash - ) - process { - if ($Update) { - #TODO: This implementation is more like the old -Force flag, because this will force an installation also if no installation in destination exists. - Write-Verbose "Ignoring if module with name '$ModuleName' is already installed because of update mode." - return $false - } - - $installedModule = Get-Module -Name $ModuleName -ListAvailable - - if ($installedModule) { - if ($installedModule.Count -gt 1) { - $targetModule = $installedModule | Where-Object { (ConvertTo-CanonicalPath -Path (Split-Path $_.ModuleBase)) -eq $Destination } | Select-Object -First 1 - - if (-not $targetModule) { - Write-Warning "Module with name '$ModuleName' was not found in '$Destination'. But it was found in:`n $($installedModule.ModuleBase | Format-List | Out-String)" - return $false - } - - Write-Warning "The module '$ModuleName' was installed at more than one location. Installed paths:`n`t$($installedModule.ModuleBase | Format-List | Out-String)`n'$($firstInstalledModule.ModuleBase)' is the searched destination." - $installedModule = $targetModule - } - elseif ((Split-Path $installedModule.ModuleBase) -ne $Destination) { - Write-Verbose "Module with name '$ModuleName' was found in '$($installedModule.ModuleBase)' but not in '$Destination'." - return $false - } - } - else { - $candidateModulePath = Join-Path -Path $Destination -ChildPath $ModuleName - $possibleModuleFileNames = Get-PossibleModuleFileNames -ModuleName $ModuleName - - if (Test-Path -Path $candidateModulePath\* -Include $possibleModuleFileNames -PathType Leaf) { - Write-Verbose "Module with name '$ModuleName' found in '$Destination' (note: destination is not in PSModulePath)" - $installedModule = @{ ModuleBase = $CandidateModulePath } - } - else { - Write-Verbose "Module with name '$ModuleName' is not installed." - return $false - } - } - - if ($ModuleHash) { - $installedModuleHash = Get-PsGetModuleHash -Path $installedModule.ModuleBase - Write-Verbose "Hash of module in '$($installedModule.ModuleBase)' is: $InstalledModuleHash" - if ($ModuleHash -ne $installedModuleHash) { - Write-Verbose "Expected '$ModuleHash' but calculated '$installedModuleHash'." - return $false - } - } - - Write-Verbose "'$ModuleName' already installed. Use -Update if you need update" - - if ($DoNotImport -eq $false) { - Import-ModuleGlobally -ModuleName $ModuleName -ModuleBase $installedModule.ModuleBase -Force:$Update - } - - return $true - } -} - -<# - .SYNOPSIS - Extract the content of the referenced zip file to the defined destination - - .PARAMETER Path - Path to a zip file with the file extension '.zip' - - .Parameter Destination - Path to which the zip content is extracted -#> -function Expand-ZipModule { - [CmdletBinding()] - param ( - [Parameter(Position=0, Mandatory=$true)] - [String] $Path, - - [Parameter(Position=1, Mandatory=$true)] - [String] $Destination - ) - process { - Write-Debug "Unzipping $Path to $Destination..." - - # Check if powershell v3+ and .net v4.5 is available - $netFailed = $true - if ( $PSVersionTable.PSVersion.Major -ge 3 -and (Get-ChildItem -Path 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4' -Recurse | Get-ItemProperty -Name Version | Where-Object { $_.Version -like '4.5*' -or $_.Version -ge '4.5' }) ) { - Write-Debug 'Attempting unzip using the .NET Framework...' - - try { - [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") - [System.IO.Compression.ZipFile]::ExtractToDirectory($Path, $Destination) - $netFailed = $false - } - catch { - } - } - - if ($netFailed) { - try { - Write-Debug 'Attempting unzip using the Windows Shell...' - $shellApp = New-Object -Com Shell.Application - $shellZip = $shellApp.NameSpace([String]$Path) - $shellDest = $shellApp.NameSpace($Destination) - $shellDest.CopyHere($shellZip.items()) - } - catch { - $shellFailed = $true - } - } - - # if failure already registered or no result - if (($netFailed -and $shellFailed) -or ((Get-ChildItem $Destination | Measure-Object | Where-Object { $_.Count -eq 0}))) { - Write-Warning 'We were unable to decompress the downloaded module. This tends to mean both of the following are true:' - Write-Warning '1. You''ve disabled Windows Explorer Zip file integration or are running on Windows Server Core.' - Write-Warning '2. You don''t have the .NET Framework 4.5 installed.' - Write-Warning 'You''ll need to correct at least one of the above issues depending on your installation to proceed.' - throw 'Unable to unzip downloaded module file!' - } - } -} - -<# - .SYNOPSIS - Update '$env:PSModulePath' from 'User' and 'Machine' scope environment variables -#> -function Update-PSModulePath { - process { - # powershell default - $psModulePath = "$env:ProgramFiles\WindowsPowershell\Modules\" - - $machineModulePath = [Environment]::GetEnvironmentVariable('PSModulePath', 'Machine') - if (-not $machineModulePath) { - # powershell default - $machineModulePath = Join-Path -Path $PSHOME -ChildPath 'Modules' - } - - $userModulePath = [Environment]::GetEnvironmentVariable('PSModulePath', 'User') - if (-not $userModulePath) { - # powershell default - $userModulePath = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath 'WindowsPowerShell\Modules' - } - - $newSessionValue = "$userModulePath;$machineModulePath;$psModulePath" - - #Set the value in the current process - [Environment]::SetEnvironmentVariable('PSModulePath', $newSessionValue, 'Process') - } -} -#endregion - -#region NuGet Handling -<# - .SYNOPSIS - Download a module of type NuGet package - - .PARAMETER NuGetPackageId - NuGet package id - - .PARAMETER PackageVersion - Specific version to be installed. If not defined, install newest. - - .PARAMETER Source - NuGet source url - - .PARAMETER PreRelease - If no PackageVersion is defined, may PreReleases be used? - - .PARAMETER PreReleaseTag - If PreReleases may be used, also use prereleases of a special tag? -#> -function Invoke-DownloadNuGetPackage { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true)] - [String] $NuGetPackageId, - - [String] $PackageVersion, - - [Parameter(Mandatory=$true)] - [String] $Source, - - [Switch] $PreRelease, - - [String] $PreReleaseTag - ) - process { - $WebClient = New-Object -TypeName System.Net.WebClient - $WebClient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials - - if (-not $Source.EndsWith('/')) { - $Source += '/' - } - - Write-Verbose "Querying '$Source' repository for package with Id '$NuGetPackageId'" - try { - $Url = "{1}Packages()?`$filter=tolower(Id)+eq+'{0}'&`$orderby=Id" -f $NuGetPackageId.ToLower(), $Source - Write-Debug "Trying NuGet query url: $Url" - $XmlDoc = [xml]$WebClient.DownloadString($Url) - } - catch { - try { - $Url = "{1}Packages(Id='{0}')?`$orderby=Id" -f $NuGetPackageId, $Source - Write-Debug "Trying NuGet query url: $Url" - $XmlDoc = [xml]$WebClient.DownloadString($Url) - } - catch { - throw "Unable to download from NuGet feed: $($_.Exception.InnerException.Message)" - } - } - - if ($PackageVersion) { - # version regexs can be found in the NuGet.SemanticVersion class - $Entry = $XmlDoc.feed.entry | - Where-Object { $_.properties.Version -eq $PackageVersion } | - Select-Object -First 1 - } - else { - $Entry = Find-LatestNugetPackageFromFeed -Feed:$XmlDoc.feed.entry -PreRelease:$PreRelease -PreReleaseTag:$PreReleaseTag - } - - if ($Entry) { - $PackageVersion = $Entry.properties.Version - Write-Verbose "Found NuGet package version '$PackageVersion'" - } - else { - throw ("Cannot find NuGet package '$NuGetPackageId $PackageVersion' [PreRelease='{0}', PreReleaseTag='{1}']" -f $PreRelease, $PreReleaseTag) - } - - $DownloadUrl = $Entry.content.src - Write-Verbose "Downloading NuGet package from '$DownloadUrl'" - $DownloadResult = Invoke-DownloadModuleFromWeb -DownloadUrl:$DownloadUrl -ModuleName:$NugetPackageId - return $DownloadResult - } -} - -<# - .SYNOPSIS - Find the latest release in the provided NuGet feed for the NuGet package id. - - .PARAMETER Feed - Xml feed node for NuGet package - - .PARAMETER PreRelease - If no PackageVersion is defined, may PreReleases be used? - - .PARAMETER PreReleaseTag - If PreReleases may be used, also use prereleases of a special tag? -#> -function Find-LatestNugetPackageFromFeed { - [CmdletBinding()] - param - ( - [Object[]] $Feed, - - [Switch] $PreRelease, - - [String] $PreReleaseTag - ) - process { - # From NuGet.SemanticVersion - https://github.com/Haacked/NuGet/blob/master/src/Core/SemanticVersion.cs - $semVerRegex = "^(?\d+(\s*\.\s*\d+){0,3})(?-[a-z][0-9a-z-]*)?$" - $semVerStrictRegex = "^(?\d+(\.\d+){2})(?-[a-z][0-9a-z-]*)?$" - - # find only stable versions - $stableRegex = "^(\d+(\s*\.\s*\d+){0,3})?$" - # find stable and prerelease versions - $preReleaseRegex = "^(\d+(\s*\.\s*\d+){0,3})(-[a-z][0-9a-z-]*)?$" - # find only a specific prerelease versions - $specificPreReleaseRegex = "^(\d+(\s*\.\s*\d+){{0,3}}-{0}[0-9a-z-]*)?$" -f $preReleaseTag - - # Set the required search expression - $searchRegex = $stableRegex - if ($preRelease) { $searchRegex = $preReleaseRegex } - if ($preReleaseTag) { $searchRegex = $specificPreReleaseRegex } - - $packages = $feed | Where-Object { - - ($_.properties.Version) -match $searchRegex - } - - return ($packages | Select -Last 1) - } -} - -#endregion - -#region Module Hashing -<# - .SYNOPSIS - Calculate a hash for the given file - - .PARAMETER Path - File path for hasing -#> -function Get-FileHash { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName = $true)] - [Alias('FullName')] - [String] $Path - ) - begin { - $Algorithm = New-Object -TypeName System.Security.Cryptography.SHA256Managed - } - process { - if (-not (Test-Path -Path $Path -PathType Leaf)) { - Write-Error "Cannot find file: $Path" - return - } - - $Stream = [System.IO.File]::OpenRead($Path) - try { - $HashBytes = $Algorithm.ComputeHash($Stream) - [BitConverter]::ToString($HashBytes) -replace '-','' - } - finally { - $Stream.Close() - } - } -} - -<# - .SYNOPSIS - Calculate a hash for the given directory. - - .PARAMETER Path - Path to the folder which should be hashed. -#> -function Get-FolderHash { - [CmdletBinding()] - param ( - [Parameter(Mandatory=$true)] - [String] $Path - ) - process { - if (-not (Test-Path -Path $Path -PathType Container)) { - throw "Cannot find folder: $Path" - } - - $Path = $Path + '\' -replace '\\\\$','\\' - $PathPattern = '^' + [Regex]::Escape($Path) - - $ChildHashes = Get-ChildItem -Path $Path -Recurse -Force | - Where-Object { -not $_.PSIsContainer } | - ForEach-Object { - New-Object -TypeName PSObject -Property @{ - RelativePath = $_.FullName -replace $PathPattern, '' - Hash = Get-FileHash -Path $_.FullName - } - } - - $Text = @($ChildHashes | - Sort-Object -Property RelativePath | - ForEach-Object { - '{0} {1}' -f $_.Hash, $_.RelativePath - }) -join '`r`n' - - Write-Debug "TEXT>$Text Date: Tue, 30 May 2023 11:15:04 -0400 Subject: [PATCH 21/22] don't error if vim slias exists --- vendor/profile.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/profile.ps1 b/vendor/profile.ps1 index d1087b1..4123bfd 100644 --- a/vendor/profile.ps1 +++ b/vendor/profile.ps1 @@ -87,7 +87,7 @@ if ($null -ne $ENV:GIT_INSTALL_ROOT) { } if (Get-Command -Name "vim" -ErrorAction SilentlyContinue) { - New-Alias -name "vi" -value vim + New-Alias -name "vi" -value vim -errorAction SilentlyContinue } if (Get-Module PSReadline -ErrorAction "SilentlyContinue") { From 86b9fb25ab6329438c3307f24cd09802d1baf888 Mon Sep 17 00:00:00 2001 From: "Dax T. Games" Date: Mon, 5 Jun 2023 13:22:28 -0400 Subject: [PATCH 22/22] Add ability to launch git bash from external Installed git whwen using Cmder - Mini --- vendor/ConEmu.xml.default | 131 +++++++++++++++++++++++--------------- vendor/cmder_exinit | 7 +- vendor/git-prompt.sh | 15 ++++- vendor/start_git_bash.cmd | 47 ++++++++++++++ 4 files changed, 142 insertions(+), 58 deletions(-) create mode 100644 vendor/start_git_bash.cmd diff --git a/vendor/ConEmu.xml.default b/vendor/ConEmu.xml.default index a4e5cc1..47b53d4 100644 --- a/vendor/ConEmu.xml.default +++ b/vendor/ConEmu.xml.default @@ -1,7 +1,7 @@ - + @@ -42,8 +42,8 @@ - - + + @@ -58,7 +58,7 @@ - + @@ -78,7 +78,6 @@ - @@ -113,13 +112,13 @@ - + - + - + @@ -128,8 +127,8 @@ - - + + @@ -166,19 +165,19 @@ - + - + - + - + @@ -413,15 +412,15 @@ - + - + - + @@ -484,12 +483,12 @@ - - + + - - + + @@ -497,8 +496,8 @@ - - + + @@ -507,8 +506,8 @@ - - + + @@ -516,61 +515,78 @@ - - - + + + - + + + + + + + + + + + + + + + + + + + + - - + + - + - - + + - - + - + + - - + - - + + - + - + - @@ -676,7 +692,7 @@ - + @@ -845,13 +861,13 @@ - - + + - + - + @@ -869,10 +885,16 @@ + + + + + + - + @@ -902,6 +924,15 @@ + + + + + + + + + diff --git a/vendor/cmder_exinit b/vendor/cmder_exinit index 4ec3351..6c29dfd 100644 --- a/vendor/cmder_exinit +++ b/vendor/cmder_exinit @@ -34,7 +34,6 @@ function runProfiled { if [ ! "x${profile_d_scripts}" = "x" ] ; then for x in ${profile_d_scripts} ; do - echo Sourcing "${1}/${x}"... . "${1}/${x}" done fi @@ -46,10 +45,8 @@ function runProfiled { # We do this for bash as admin sessions since $CMDER_ROOT is not being set if [ "$CMDER_ROOT" = "" -a "$ConEmuDir" != "" ] ; then - if [ -d "${ConEmuDir}../../vendor" ] ; then + if [ -d "${ConEmuDir}/../../vendor" ] ; then case "$ConEmuDir" in *\\*) CMDER_ROOT=$( cd "$(cygpath -u "$ConEmuDir")/../.." ; pwd );; esac - else - echo "Running in ConEmu without Cmder, skipping Cmder integration." fi elif [ "$CMDER_ROOT" != "" ] ; then case "$CMDER_ROOT" in *\\*) CMDER_ROOT="$(cygpath -u "$CMDER_ROOT")";; esac @@ -59,8 +56,6 @@ if [ ! "$CMDER_ROOT" = "" ] ; then # Remove any trailing '/' CMDER_ROOT=$(echo $CMDER_ROOT | sed 's:/*$::') - echo "Using \"CMDER_ROOT\" at \"${CMDER_ROOT}\"." - export CMDER_ROOT PATH=${CMDER_ROOT}/bin:${CMDER_ROOT}/vendor/bin:$PATH:${CMDER_ROOT} diff --git a/vendor/git-prompt.sh b/vendor/git-prompt.sh index a02af62..189e3dc 100644 --- a/vendor/git-prompt.sh +++ b/vendor/git-prompt.sh @@ -38,7 +38,7 @@ then . ~/.config/git/git-prompt.sh fi else - PS1='\[\033]0;$MSYSTEM:${PWD//[^[:ascii:]]/?}\007\]' # set window title + PS1='\[\033]0;$TITLEPREFIX:$PWD\007\]' # set window title # PS1="$PS1"'\n' # new line PS1="$PS1"'\[\033[32m\]' # change to green PS1="$PS1"'\u@\h ' # user@host @@ -71,4 +71,15 @@ else PS1="$PS1"'λ ' # prompt: always λ fi -MSYS2_PS1="$PS1" # for detection by MSYS2 SDK's bash.basrc \ No newline at end of file +MSYS2_PS1="$PS1" # for detection by MSYS2 SDK's bash.basrc + +# Evaluate all user-specific Bash completion scripts (if any) +if test -z "$WINELOADERNOEXEC" +then + for c in "$HOME"/bash_completion.d/*.bash + do + # Handle absence of any scripts (or the folder) gracefully + test ! -f "$c" || + . "$c" + done +fi diff --git a/vendor/start_git_bash.cmd b/vendor/start_git_bash.cmd new file mode 100644 index 0000000..136feab --- /dev/null +++ b/vendor/start_git_bash.cmd @@ -0,0 +1,47 @@ +@echo off + +if not defined CMDER_ROOT ( + if defined ConEmuDir ( + for /f "delims=" %%i in ("%ConEmuDir%\..\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) else ( + for /f "delims=" %%i in ("%~dp0\..") do ( + set "CMDER_ROOT=%%~fi" + ) + ) +) + +if defined ConEmuDir ( + set "gitCommand=--command=%ConEmuBaseDirShort%\conemu-msys2-64.exe" +) + +if exist "%CMDER_ROOT%\vendor\git-for-windows" ( + set "PATH=%CMDER_ROOT%\vendor\git-for-windows\usr\bin;%PATH%" + set "gitCmd=%CMDER_ROOT%\vendor\git-for-windows\git-cmd.exe" + set "bashCmd=%CMDER_ROOT%\vendor\git-for-windows\usr\bin\bash.exe" +) else if exist "%ProgramFiles%\git" ( + set "PATH=%ProgramFiles%\git\usr\bin;%PATH%" + set "gitCmd=%ProgramFiles%\git\git-cmd.exe" + set "bashCmd=%ProgramFiles%\git\usr\bin\bash.exe" + if not exist "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh" ( + echo Run 'mklink "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh" "%CMDER_ROOT%\vendor\cmder_exinit"' in 'cmd::Cmder as Admin' to use Cmder with external Git Bash + echo. + echo or + echo. + echo Run 'echo "" ^> "%ProgramFiles%\git\etc\profile.d\cmder_exinit.sh"' in 'cmd::Cmder as Admin' to disable this message. + ) +) else if exist "%ProgramFiles(x86)%\git" ( + set "PATH=%ProgramFiles(x86)%\git\usr\bin;%PATH%" + set "gitCmd=%ProgramFiles(x86)%\git\git-cmd.exe" + set "bashCmd=%ProgramFiles(x86)%\git\usr\bin\bash.exe" + if not exist "%ProgramFiles(x86)%\git\etc\profile.d\cmder_exinit.sh" ( + echo Run 'mklink "%ProgramFiles^(x86^)%\git\etc\profile.d\cmder_exinit.sh" "%CMDER_ROOT%\vendor\cmder_exinit"' in 'cmd::Cmder as Admin' to use Cmder with external Git Bash + echo. + echo or + echo. + echo Run 'echo "" ^> "%ProgramFiles^(x86^)%\git\etc\profile.d\cmder_exinit.sh"' in 'cmd::Cmder as Admin' to disable this message. + ) +) + +"%gitCmd%" --no-cd %gitCommand% "%bashCmd%" --login -i