diff --git a/installers/windows/EnvVarUpdate.nsh b/installers/windows/EnvVarUpdate.nsh deleted file mode 100644 index 39682000c3..0000000000 --- a/installers/windows/EnvVarUpdate.nsh +++ /dev/null @@ -1,327 +0,0 @@ -/** - * EnvVarUpdate.nsh - * : Environmental Variables: append, prepend, and remove entries - * - * WARNING: If you use StrFunc.nsh header then include it before this file - * with all required definitions. This is to avoid conflicts - * - * Usage: - * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString" - * - * Credits: - * Version 1.0 - * * Cal Turney (turnec2) - * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this - * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar, - * WriteEnvStr, and un.DeleteEnvStr - * * Diego Pedroso (deguix) for StrTok - * * Kevin English (kenglish_hi) for StrContains - * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry - * (dandaman32) for StrReplace - * - * Version 1.1 (compatibility with StrFunc.nsh) - * * techtonik - * - * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries - * - */ - - -!ifndef ENVVARUPDATE_FUNCTION -!define ENVVARUPDATE_FUNCTION -!verbose push -!verbose 3 -!include "LogicLib.nsh" -!include "WinMessages.NSH" -!include "StrFunc.nsh" - -; ---- Fix for conflict if StrFunc.nsh is already includes in main file ----------------------- -!macro _IncludeStrFunction StrFuncName - !ifndef ${StrFuncName}_INCLUDED - ${${StrFuncName}} - !endif - !ifndef Un${StrFuncName}_INCLUDED - ${Un${StrFuncName}} - !endif - !define un.${StrFuncName} "${Un${StrFuncName}}" -!macroend - -!insertmacro _IncludeStrFunction StrTok -!insertmacro _IncludeStrFunction StrStr -!insertmacro _IncludeStrFunction StrRep - -; ---------------------------------- Macro Definitions ---------------------------------------- -!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString - Push "${EnvVarName}" - Push "${Action}" - Push "${RegLoc}" - Push "${PathString}" - Call EnvVarUpdate - Pop "${ResultVar}" -!macroend -!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"' - -!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString - Push "${EnvVarName}" - Push "${Action}" - Push "${RegLoc}" - Push "${PathString}" - Call un.EnvVarUpdate - Pop "${ResultVar}" -!macroend -!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"' -; ---------------------------------- Macro Definitions end------------------------------------- - -;----------------------------------- EnvVarUpdate start---------------------------------------- -!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' -!define hkcu_current_user 'HKCU "Environment"' - -!macro EnvVarUpdate UN - -Function ${UN}EnvVarUpdate - - Push $0 - Exch 4 - Exch $1 - Exch 3 - Exch $2 - Exch 2 - Exch $3 - Exch - Exch $4 - Push $5 - Push $6 - Push $7 - Push $8 - Push $9 - Push $R0 - - /* After this point: - ------------------------- - $0 = ResultVar (returned) - $1 = EnvVarName (input) - $2 = Action (input) - $3 = RegLoc (input) - $4 = PathString (input) - $5 = Orig EnvVar (read from registry) - $6 = Len of $0 (temp) - $7 = tempstr1 (temp) - $8 = Entry counter (temp) - $9 = tempstr2 (temp) - $R0 = tempChar (temp) */ - - ; Step 1: Read contents of EnvVarName from RegLoc - ; - ; Check for empty EnvVarName - ${If} $1 == "" - SetErrors - DetailPrint "ERROR: EnvVarName is blank" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Check for valid Action - ${If} $2 != "A" - ${AndIf} $2 != "P" - ${AndIf} $2 != "R" - SetErrors - DetailPrint "ERROR: Invalid Action - must be A, P, or R" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ${If} $3 == HKLM - ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5 - ${ElseIf} $3 == HKCU - ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5 - ${Else} - SetErrors - DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"' - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Check for empty PathString - ${If} $4 == "" - SetErrors - DetailPrint "ERROR: PathString is blank" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Make sure we've got some work to do - ${If} $5 == "" - ${AndIf} $2 == "R" - SetErrors - DetailPrint "$1 is empty - Nothing to remove" - Goto EnvVarUpdate_Restore_Vars - ${EndIf} - - ; Step 2: Scrub EnvVar - ; - StrCpy $0 $5 ; Copy the contents to $0 - ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or - ; after the last one are not removed here but instead in Step 3) - ${If} $0 != "" ; If EnvVar is not empty ... - ${Do} - ${${UN}StrStr} $7 $0 " ;" - ${If} $7 == "" - ${ExitDo} - ${EndIf} - ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';' - ${Loop} - ${Do} - ${${UN}StrStr} $7 $0 "; " - ${If} $7 == "" - ${ExitDo} - ${EndIf} - ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';' - ${Loop} - ${Do} - ${${UN}StrStr} $7 $0 ";;" - ${If} $7 == "" - ${ExitDo} - ${EndIf} - ${${UN}StrRep} $0 $0 ";;" ";" - ${Loop} - - ; Remove a leading or trailing semicolon from EnvVar - StrCpy $7 $0 1 0 - ${If} $7 == ";" - StrCpy $0 $0 "" 1 ; Change ';' to '' - ${EndIf} - StrLen $6 $0 - IntOp $6 $6 - 1 - StrCpy $7 $0 1 $6 - ${If} $7 == ";" - StrCpy $0 $0 $6 ; Change ';' to '' - ${EndIf} - ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug - ${EndIf} - - /* Step 3. Remove all instances of the target path/string (even if "A" or "P") - $6 = bool flag (1 = found and removed PathString) - $7 = a string (e.g. path) delimited by semicolon(s) - $8 = entry counter starting at 0 - $9 = copy of $0 - $R0 = tempChar */ - - ${If} $5 != "" ; If EnvVar is not empty ... - StrCpy $9 $0 - StrCpy $0 "" - StrCpy $8 0 - StrCpy $6 0 - - ${Do} - ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter - - ${If} $7 == "" ; If we've run out of entries, - ${ExitDo} ; were done - ${EndIf} ; - - ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) - ${Do} - StrCpy $R0 $7 1 - ${If} $R0 != " " - ${ExitDo} - ${EndIf} - StrCpy $7 $7 "" 1 ; Remove leading space - ${Loop} - ${Do} - StrCpy $R0 $7 1 -1 - ${If} $R0 != " " - ${ExitDo} - ${EndIf} - StrCpy $7 $7 -1 ; Remove trailing space - ${Loop} - ${If} $7 == $4 ; If string matches, remove it by not appending it - StrCpy $6 1 ; Set 'found' flag - ${ElseIf} $7 != $4 ; If string does NOT match - ${AndIf} $0 == "" ; and the 1st string being added to $0, - StrCpy $0 $7 ; copy it to $0 without a prepended semicolon - ${ElseIf} $7 != $4 ; If string does NOT match - ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, - StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon - ${EndIf} ; - - IntOp $8 $8 + 1 ; Bump counter - ${Loop} ; Check for duplicates until we run out of paths - ${EndIf} - - ; Step 4: Perform the requested Action - ; - ${If} $2 != "R" ; If Append or Prepend - ${If} $6 == 1 ; And if we found the target - DetailPrint "Target is already present in $1. It will be removed and" - ${EndIf} - ${If} $0 == "" ; If EnvVar is (now) empty - StrCpy $0 $4 ; just copy PathString to EnvVar - ${If} $6 == 0 ; If found flag is either 0 - ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) - DetailPrint "$1 was empty and has been updated with the target" - ${EndIf} - ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), - StrCpy $0 $0;$4 ; append PathString - ${If} $6 == 1 - DetailPrint "appended to $1" - ${Else} - DetailPrint "Target was appended to $1" - ${EndIf} - ${Else} ; If Prepend (and EnvVar is not empty), - StrCpy $0 $4;$0 ; prepend PathString - ${If} $6 == 1 - DetailPrint "prepended to $1" - ${Else} - DetailPrint "Target was prepended to $1" - ${EndIf} - ${EndIf} - ${Else} ; If Action = Remove - ${If} $6 == 1 ; and we found the target - DetailPrint "Target was found and removed from $1" - ${Else} - DetailPrint "Target was NOT found in $1 (nothing to remove)" - ${EndIf} - ${If} $0 == "" - DetailPrint "$1 is now empty" - ${EndIf} - ${EndIf} - - ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change - ; - ClearErrors - ${If} $3 == HKLM - WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section - ${ElseIf} $3 == HKCU - WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section - ${EndIf} - - IfErrors 0 +4 - MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" - DetailPrint "Could not write updated $1 to $3" - Goto EnvVarUpdate_Restore_Vars - - ; "Export" our change - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - - EnvVarUpdate_Restore_Vars: - ; - ; Restore the user's variables and return ResultVar - Pop $R0 - Pop $9 - Pop $8 - Pop $7 - Pop $6 - Pop $5 - Pop $4 - Pop $3 - Pop $2 - Pop $1 - Push $0 ; Push my $0 (ResultVar) - Exch - Pop $0 ; Restore his $0 - -FunctionEnd - -!macroend ; EnvVarUpdate UN -!insertmacro EnvVarUpdate "" -!insertmacro EnvVarUpdate "un." -;----------------------------------- EnvVarUpdate end---------------------------------------- - -!verbose pop -!endif diff --git a/installers/windows/minikube.nsi b/installers/windows/minikube.nsi index f0e2f82961..2204e025ca 100644 --- a/installers/windows/minikube.nsi +++ b/installers/windows/minikube.nsi @@ -36,7 +36,6 @@ Icon "logo.ico" OutFile "minikube-installer.exe" !include "LogicLib.nsh" -!include "EnvVarUpdate.nsh" !include "MUI2.nsh" ; Modern UI !define MUI_ICON "logo.ico" @@ -125,6 +124,7 @@ Section "Install" # Files added here should be removed by the uninstaller (see section "uninstall") File "minikube.exe" File "logo.ico" + File "update_path.bat" # Add any other files for the install directory (license files, app data, etc) here # Uninstaller - See function un.onInit and section "uninstall" for configuration @@ -154,7 +154,10 @@ Section "Install" WriteRegDWORD HKLM "${UNINSTALLDIR}" "EstimatedSize" ${INSTALLSIZE} # Add installed executable to PATH - ${EnvVarUpdate} $0 "PATH" "A" "HKLM" "$INSTDIR" ; appends to the system path + # Cannot uset EnvVarUpdate since the path can be too long + # this is explicitly warned in the documentation page + # http://nsis.sourceforge.net/Environmental_Variables:_append,_prepend,_and_remove_entries + nsExec::Exec '"$INSTDIR\update_path.bat" add $INSTDIR' SectionEnd Section "Uninstall" @@ -164,9 +167,13 @@ Section "Uninstall" # Try to remove the Start Menu folder - this will only happen if it is empty RmDir /REBOOTOK "$SMPROGRAMS\${COMPANYNAME}" + # Remove uninstalled executable from PATH + nsExec::Exec '"$INSTDIR\update_path.bat" remove $INSTDIR' ; appends to the system path + # Remove files Delete /REBOOTOK $INSTDIR\minikube.exe Delete /REBOOTOK $INSTDIR\logo.ico + Delete /REBOOTOK $INSTDIR\update_path.bat # Always delete uninstaller as the last action Delete /REBOOTOK $INSTDIR\uninstall.exe @@ -177,6 +184,4 @@ Section "Uninstall" # Remove uninstaller information from the registry DeleteRegKey HKLM "${UNINSTALLDIR}" - # Remove uninstalled executable from PATH - ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" "$INSTDIR" ; removes from the system path -SectionEnd \ No newline at end of file +SectionEnd diff --git a/installers/windows/update_path.bat b/installers/windows/update_path.bat new file mode 100644 index 0000000000..57a085bcc5 --- /dev/null +++ b/installers/windows/update_path.bat @@ -0,0 +1,42 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion + +if [%1] == [] ( + goto :usage +) + +if [%2] == [] ( + goto :usage +) + + +set TARGET_PATH=%2 %3 %4 %5 %6 %7 %8 %9 + +:: Remove trailing spaces +for /f "tokens=* delims= " %%a in ("!TARGET_PATH!") do set "TARGET_PATH=%%a" +for /l %%a in (1,1,100) do if "!TARGET_PATH:~-1!"==" " set "TARGET_PATH=!TARGET_PATH:~0,-1!" + +:: Remove trailing ; if any +if "%PATH:~-1%"==";" ( + set PATH=!PATH:~0,-1! +) + +if "%1" == "add" ( + set "PATH=!PATH!;%TARGET_PATH%" + goto :update +) + +if "%1" == "remove" ( + set "PATH=!PATH:;%TARGET_PATH%=!" + goto :update +) + +:usage +echo Script to add or remove to path environment variable +echo Usage: +echo %0 [add^|remove] path +exit /b 1 + +:update + +call Setx PATH "!PATH!" /m