build: NSIS based Windows installer (#3240)
This commit adds support for creating Windows installers to ci.go
This commit is contained in:
		
							parent
							
								
									6707f70b4a
								
							
						
					
					
						commit
						9bc97a5785
					
				
							
								
								
									
										17
									
								
								appveyor.yml
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								appveyor.yml
									
									
									
									
									
								
							| @ -1,39 +1,40 @@ | ||||
| os: Visual Studio 2015 | ||||
| 
 | ||||
| # Clone directly into GOPATH. | ||||
| clone_folder: c:\gopath\src\github.com\ethereum\go-ethereum | ||||
| clone_folder: C:\gopath\src\github.com\ethereum\go-ethereum | ||||
| clone_depth: 5 | ||||
| version: "{branch}.{build}" | ||||
| environment: | ||||
|   global: | ||||
|     GOPATH: c:\gopath | ||||
|     GOPATH: C:\gopath | ||||
|     CC: gcc.exe | ||||
|   matrix: | ||||
|     - GETH_ARCH: amd64 | ||||
|       MSYS2_ARCH: x86_64 | ||||
|       MSYS2_BITS: 64 | ||||
|       MSYSTEM: MINGW64 | ||||
|       PATH: C:\msys64\mingw64\bin\;%PATH% | ||||
|       PATH: C:\msys64\mingw64\bin\;C:\Program Files (x86)\NSIS\;%PATH% | ||||
|     - GETH_ARCH: 386 | ||||
|       MSYS2_ARCH: i686 | ||||
|       MSYS2_BITS: 32 | ||||
|       MSYSTEM: MINGW32 | ||||
|       PATH: C:\msys64\mingw32\bin\;%PATH% | ||||
|       PATH: C:\msys64\mingw32\bin\;C:\Program Files (x86)\NSIS\;%PATH% | ||||
| 
 | ||||
| install: | ||||
|   - rmdir c:\go /s /q | ||||
|   - rmdir C:\go /s /q | ||||
|   - appveyor DownloadFile https://storage.googleapis.com/golang/go1.7.3.windows-amd64.zip | ||||
|   - 7z x go1.7.3.windows-amd64.zip -y -oC:\ > NUL | ||||
|   - go version | ||||
|   - gcc --version | ||||
| 
 | ||||
| build_script: | ||||
|   - go run build\\ci.go install -arch %GETH_ARCH% | ||||
|   - go run build\ci.go install -arch %GETH_ARCH% | ||||
| 
 | ||||
| after_build: | ||||
|   - go run build\\ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds | ||||
|   - go run build\ci.go archive -arch %GETH_ARCH% -type zip -signer WINDOWS_SIGNING_KEY -upload gethstore/builds | ||||
|   - go run build\ci.go nsis -arch %GETH_ARCH% -signer WINDOWS_SIGNING_KEY -upload gethstore/builds | ||||
| 
 | ||||
| test_script: | ||||
|   - set GOARCH=%GETH_ARCH% | ||||
|   - set CGO_ENABLED=1 | ||||
|   - go run build\\ci.go test -vet -coverage | ||||
|   - go run build\ci.go test -vet -coverage | ||||
|  | ||||
							
								
								
									
										75
									
								
								build/ci.go
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								build/ci.go
									
									
									
									
									
								
							| @ -28,6 +28,7 @@ Available commands are: | ||||
|    archive    [-arch architecture] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts | ||||
|    importkeys                                                                                -- imports signing keys from env | ||||
|    debsrc     [ -signer key-id ] [ -upload dest ]                                            -- creates a debian source package | ||||
|    nsis                                                                                      -- creates a Windows NSIS installer | ||||
|    xgo        [ options ]                                                                    -- cross builds according to options | ||||
| 
 | ||||
| For all commands, -n prevents execution of external programs (dry run mode). | ||||
| @ -122,6 +123,8 @@ func main() { | ||||
| 		doArchive(os.Args[2:]) | ||||
| 	case "debsrc": | ||||
| 		doDebianSource(os.Args[2:]) | ||||
| 	case "nsis": | ||||
| 		doWindowsInstaller(os.Args[2:]) | ||||
| 	case "xgo": | ||||
| 		doXgo(os.Args[2:]) | ||||
| 	default: | ||||
| @ -429,7 +432,7 @@ func makeWorkdir(wdflag string) string { | ||||
| 	if wdflag != "" { | ||||
| 		err = os.MkdirAll(wdflag, 0744) | ||||
| 	} else { | ||||
| 		wdflag, err = ioutil.TempDir("", "eth-deb-build-") | ||||
| 		wdflag, err = ioutil.TempDir("", "geth-build-") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| @ -559,6 +562,76 @@ func stageDebianSource(tmpdir string, meta debMetadata) (pkgdir string) { | ||||
| 	return pkgdir | ||||
| } | ||||
| 
 | ||||
| // Windows installer
 | ||||
| 
 | ||||
| func doWindowsInstaller(cmdline []string) { | ||||
| 	// Parse the flags and make skip installer generation on PRs
 | ||||
| 	var ( | ||||
| 		arch    = flag.String("arch", runtime.GOARCH, "Architecture for cross build packaging") | ||||
| 		signer  = flag.String("signer", "", `Environment variable holding the signing key (e.g. WINDOWS_SIGNING_KEY)`) | ||||
| 		upload  = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`) | ||||
| 		workdir = flag.String("workdir", "", `Output directory for packages (uses temp dir if unset)`) | ||||
| 	) | ||||
| 	flag.CommandLine.Parse(cmdline) | ||||
| 	*workdir = makeWorkdir(*workdir) | ||||
| 	env := build.Env() | ||||
| 	maybeSkipArchive(env) | ||||
| 
 | ||||
| 	// Aggregate binaries that are included in the installer
 | ||||
| 	var ( | ||||
| 		devTools []string | ||||
| 		allTools []string | ||||
| 		gethTool string | ||||
| 	) | ||||
| 	for _, file := range allToolsArchiveFiles { | ||||
| 		if file == "COPYING" { // license, copied later
 | ||||
| 			continue | ||||
| 		} | ||||
| 		allTools = append(allTools, filepath.Base(file)) | ||||
| 		if filepath.Base(file) == "geth.exe" { | ||||
| 			gethTool = file | ||||
| 		} else { | ||||
| 			devTools = append(devTools, file) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Render NSIS scripts: Installer NSIS contains two installer sections,
 | ||||
| 	// first section contains the geth binary, second section holds the dev tools.
 | ||||
| 	templateData := map[string]interface{}{ | ||||
| 		"License":  "COPYING", | ||||
| 		"Geth":     gethTool, | ||||
| 		"DevTools": devTools, | ||||
| 	} | ||||
| 	build.Render("build/nsis.geth.nsi", filepath.Join(*workdir, "geth.nsi"), 0644, nil) | ||||
| 	build.Render("build/nsis.install.nsh", filepath.Join(*workdir, "install.nsh"), 0644, templateData) | ||||
| 	build.Render("build/nsis.uninstall.nsh", filepath.Join(*workdir, "uninstall.nsh"), 0644, allTools) | ||||
| 	build.Render("build/nsis.envvarupdate.nsh", filepath.Join(*workdir, "EnvVarUpdate.nsh"), 0644, nil) | ||||
| 	build.CopyFile(filepath.Join(*workdir, "SimpleFC.dll"), "build/nsis.simplefc.dll", 0755) | ||||
| 	build.CopyFile(filepath.Join(*workdir, "COPYING"), "COPYING", 0755) | ||||
| 
 | ||||
| 	// Build the installer. This assumes that all the needed files have been previously
 | ||||
| 	// built (don't mix building and packaging to keep cross compilation complexity to a
 | ||||
| 	// minimum).
 | ||||
| 	version := strings.Split(build.VERSION(), ".") | ||||
| 	if env.Commit != "" { | ||||
| 		version[2] += "-" + env.Commit[:8] | ||||
| 	} | ||||
| 	installer, _ := filepath.Abs("geth-" + archiveBasename(*arch, env) + ".exe") | ||||
| 	build.MustRunCommand("makensis.exe", | ||||
| 		"/DOUTPUTFILE="+installer, | ||||
| 		"/DMAJORVERSION="+version[0], | ||||
| 		"/DMINORVERSION="+version[1], | ||||
| 		"/DBUILDVERSION="+version[2], | ||||
| 		"/DARCH="+*arch, | ||||
| 		filepath.Join(*workdir, "geth.nsi"), | ||||
| 	) | ||||
| 
 | ||||
| 	// Sign and publish installer.
 | ||||
| 	if err := archiveUpload(installer, *upload, *signer); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Cross compilation
 | ||||
| 
 | ||||
| func doXgo(cmdline []string) { | ||||
|  | ||||
							
								
								
									
										327
									
								
								build/nsis.envvarupdate.nsh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								build/nsis.envvarupdate.nsh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,327 @@ | ||||
| /** | ||||
|  *  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 '<space>;' | ||||
|     ${Loop} | ||||
|     ${Do} | ||||
|       ${${UN}StrStr} $7 $0 "; " | ||||
|       ${If} $7 == "" | ||||
|         ${ExitDo} | ||||
|       ${EndIf} | ||||
|       ${${UN}StrRep} $0  $0 "; " ";"         ; Remove ';<space>' | ||||
|     ${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 ';<EnvVar>' to '<EnvVar>' | ||||
|     ${EndIf} | ||||
|     StrLen $6 $0 | ||||
|     IntOp $6 $6 - 1 | ||||
|     StrCpy $7  $0 1 $6 | ||||
|     ${If} $7 == ";" | ||||
|      StrCpy $0  $0 $6                      ; Change ';<EnvVar>' to '<EnvVar>' | ||||
|     ${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 | ||||
							
								
								
									
										65
									
								
								build/nsis.geth.nsi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								build/nsis.geth.nsi
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| # Builds a Windows installer with NSIS. | ||||
| # It expects the following command line arguments: | ||||
| # - OUTPUTFILE, filename of the installer (without extension) | ||||
| # - MAJORVERSION, major build version | ||||
| # - MINORVERSION, minor build version | ||||
| # - BUILDVERSION, build id version | ||||
| # | ||||
| # The created installer executes the following steps: | ||||
| # 1. install geth for all users | ||||
| # 2. install optional development tools such as abigen | ||||
| # 3. create an uninstaller | ||||
| # 4. configures the Windows firewall for geth | ||||
| # 5. create geth, attach and uninstall start menu entries | ||||
| # 6. configures the registry that allows Windows to manage the package through its platform tools | ||||
| # 7. adds the environment system wide variable ETHEREUM_SOCKET | ||||
| # 8. adds the install directory to %PATH% | ||||
| # | ||||
| # Requirements: | ||||
| # - NSIS, http://nsis.sourceforge.net/Main_Page | ||||
| # - SFP, http://nsis.sourceforge.net/NSIS_Simple_Firewall_Plugin (put dll in NSIS\Plugins\x86-ansi) | ||||
| # | ||||
| # based on: http://nsis.sourceforge.net/A_simple_installer_with_start_menu_shortcut_and_uninstaller | ||||
| # | ||||
| # TODO: | ||||
| # - sign installer | ||||
| CRCCheck on | ||||
| 
 | ||||
| !define GROUPNAME "Ethereum" | ||||
| !define APPNAME "Geth" | ||||
| !define DESCRIPTION "Official Go implementation of the Ethereum protocol" | ||||
| !addplugindir .\ | ||||
| 
 | ||||
| # Require admin rights on NT6+ (When UAC is turned on) | ||||
| RequestExecutionLevel admin | ||||
| 
 | ||||
| # Use LZMA compression | ||||
| SetCompressor /SOLID lzma | ||||
| 
 | ||||
| !include LogicLib.nsh | ||||
| !include EnvVarUpdate.nsh | ||||
| 
 | ||||
| !macro VerifyUserIsAdmin | ||||
| UserInfo::GetAccountType | ||||
| pop $0 | ||||
| ${If} $0 != "admin" # Require admin rights on NT4+ | ||||
|   messageBox mb_iconstop "Administrator rights required!" | ||||
|   setErrorLevel 740 # ERROR_ELEVATION_REQUIRED | ||||
|   quit | ||||
| ${EndIf} | ||||
| !macroend | ||||
| 
 | ||||
| function .onInit | ||||
|   # make vars are global for all users since geth is installed global | ||||
|   setShellVarContext all | ||||
|   !insertmacro VerifyUserIsAdmin | ||||
| 
 | ||||
|   ${If} ${ARCH} == "amd64" | ||||
|     StrCpy $InstDir "$PROGRAMFILES64\${APPNAME}" | ||||
|   ${Else} | ||||
|     StrCpy $InstDir "$PROGRAMFILES32\${APPNAME}" | ||||
|   ${Endif} | ||||
| functionEnd | ||||
| 
 | ||||
| !include install.nsh | ||||
| !include uninstall.nsh | ||||
							
								
								
									
										102
									
								
								build/nsis.install.nsh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								build/nsis.install.nsh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,102 @@ | ||||
| Name "geth ${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}" # VERSION variables set through command line arguments | ||||
| InstallDir "$InstDir" | ||||
| OutFile "${OUTPUTFILE}" # set through command line arguments | ||||
| 
 | ||||
| # Links for "Add/Remove Programs" | ||||
| !define HELPURL "https://github.com/ethereum/go-ethereum/issues" | ||||
| !define UPDATEURL "https://github.com/ethereum/go-ethereum/releases" | ||||
| !define ABOUTURL "https://github.com/ethereum/go-ethereum#ethereum-go" | ||||
| !define /date NOW "%Y%m%d" | ||||
| 
 | ||||
| PageEx license | ||||
|   LicenseData {{.License}} | ||||
| PageExEnd | ||||
| 
 | ||||
| # Install geth binary | ||||
| Section "Geth" GETH_IDX | ||||
|   SetOutPath $INSTDIR | ||||
|   file {{.Geth}} | ||||
| 
 | ||||
|   # Create start menu launcher | ||||
|   createDirectory "$SMPROGRAMS\${APPNAME}" | ||||
|   createShortCut "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" "$INSTDIR\geth.exe" "--fast" "--cache=512" | ||||
|   createShortCut "$SMPROGRAMS\${APPNAME}\Attach.lnk" "$INSTDIR\geth.exe" "attach" "" "" | ||||
|   createShortCut "$SMPROGRAMS\${APPNAME}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "" "" | ||||
| 
 | ||||
|   # Firewall - remove rules (if exists) | ||||
|   SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)" | ||||
|   SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)" | ||||
|   SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)" | ||||
| 
 | ||||
|   # Firewall - add rules | ||||
|   SimpleFC::AdvAddRule "Geth incoming peers (TCP:30303)" ""  6 1 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" 30303 "" "" "" | ||||
|   SimpleFC::AdvAddRule "Geth outgoing peers (TCP:30303)" ""  6 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" "" | ||||
|   SimpleFC::AdvAddRule "Geth UDP discovery (UDP:30303)" "" 17 2 1 2147483647 1 "$INSTDIR\geth.exe" "" "" "Ethereum" "" 30303 "" "" | ||||
| 
 | ||||
|   # Set default IPC endpoint (https://github.com/ethereum/EIPs/issues/147) | ||||
|   ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc" | ||||
|   ${EnvVarUpdate} $0 "ETHEREUM_SOCKET" "A" "HKLM" "\\.\pipe\geth.ipc" | ||||
| 
 | ||||
|   # Add geth to PATH | ||||
|   ${EnvVarUpdate} $0 "PATH" "A" "HKLM" $INSTDIR | ||||
| SectionEnd | ||||
| 
 | ||||
| # Install optional develop tools. | ||||
| Section /o "Development tools" DEV_TOOLS_IDX | ||||
|   SetOutPath $INSTDIR | ||||
|   {{range .DevTools}}file {{.}} | ||||
|   {{end}} | ||||
| SectionEnd | ||||
| 
 | ||||
| # Return on top of stack the total size (as DWORD) of the selected/installed sections. | ||||
| Var GetInstalledSize.total | ||||
| Function GetInstalledSize | ||||
|   StrCpy $GetInstalledSize.total 0 | ||||
| 
 | ||||
|   ${if} ${SectionIsSelected} ${GETH_IDX} | ||||
|     SectionGetSize ${GETH_IDX} $0 | ||||
|     IntOp $GetInstalledSize.total $GetInstalledSize.total + $0 | ||||
|   ${endif} | ||||
| 
 | ||||
|   ${if} ${SectionIsSelected} ${DEV_TOOLS_IDX} | ||||
|     SectionGetSize ${DEV_TOOLS_IDX} $0 | ||||
|     IntOp $GetInstalledSize.total $GetInstalledSize.total + $0 | ||||
|   ${endif} | ||||
| 
 | ||||
|   IntFmt $GetInstalledSize.total "0x%08X" $GetInstalledSize.total | ||||
|   Push $GetInstalledSize.total | ||||
| FunctionEnd | ||||
| 
 | ||||
| # Write registry, Windows uses these values in various tools such as add/remove program. | ||||
| # PowerShell: Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, InstallLocation, InstallDate | Format-Table –AutoSize | ||||
| function .onInstSuccess | ||||
|   # Save information in registry in HKEY_LOCAL_MACHINE branch, Windows add/remove functionality depends on this | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayName" "${GROUPNAME} - ${APPNAME} - ${DESCRIPTION}" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallLocation" "$INSTDIR" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "InstallDate" "${NOW}" | ||||
|   # Wait for Alex | ||||
|   #WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayIcon" "$\"$INSTDIR\logo.ico$\"" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "Publisher" "${GROUPNAME}" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "HelpLink" "${HELPURL}" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLUpdateInfo" "${UPDATEURL}" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "URLInfoAbout" "${ABOUTURL}" | ||||
|   WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "DisplayVersion" "${MAJORVERSION}.${MINORVERSION}.${BUILDVERSION}" | ||||
|   WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMajor" ${MAJORVERSION} | ||||
|   WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "VersionMinor" ${MINORVERSION} | ||||
|   # There is no option for modifying or repairing the install | ||||
|   WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoModify" 1 | ||||
|   WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "NoRepair" 1 | ||||
| 
 | ||||
|   Call GetInstalledSize | ||||
|   Pop $0 | ||||
|   WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" "EstimatedSize" "$0" | ||||
| 
 | ||||
|   # Create uninstaller | ||||
|   writeUninstaller "$INSTDIR\uninstall.exe" | ||||
| functionEnd | ||||
| 
 | ||||
| Page components | ||||
| Page directory | ||||
| Page instfiles | ||||
							
								
								
									
										
											BIN
										
									
								
								build/nsis.simplefc.dll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								build/nsis.simplefc.dll
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								build/nsis.simplefc.source.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								build/nsis.simplefc.source.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										32
									
								
								build/nsis.uninstall.nsh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								build/nsis.uninstall.nsh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| Section "Uninstall" | ||||
|   # uninstall for all users | ||||
|   setShellVarContext all | ||||
| 
 | ||||
|   # Delete (optionally) installed files | ||||
|   {{range $}}Delete $INSTDIR\{{.}} | ||||
|   {{end}} | ||||
|   Delete $INSTDIR\uninstall.exe | ||||
| 
 | ||||
|   # Delete install directory | ||||
|   rmDir $INSTDIR | ||||
| 
 | ||||
|   # Delete start menu launcher | ||||
|   Delete "$SMPROGRAMS\${APPNAME}\${APPNAME}.lnk" | ||||
|   Delete "$SMPROGRAMS\${APPNAME}\Attach.lnk" | ||||
|   Delete "$SMPROGRAMS\${APPNAME}\Uninstall.lnk" | ||||
|   rmDir "$SMPROGRAMS\${APPNAME}" | ||||
| 
 | ||||
|   # Firewall - remove rules if exists | ||||
|   SimpleFC::AdvRemoveRule "Geth incoming peers (TCP:30303)" | ||||
|   SimpleFC::AdvRemoveRule "Geth outgoing peers (TCP:30303)" | ||||
|   SimpleFC::AdvRemoveRule "Geth UDP discovery (UDP:30303)" | ||||
| 
 | ||||
|   # Remove IPC endpoint (https://github.com/ethereum/EIPs/issues/147) | ||||
|   ${un.EnvVarUpdate} $0 "ETHEREUM_SOCKET" "R" "HKLM" "\\.\pipe\geth.ipc" | ||||
| 
 | ||||
|   # Remove install directory from PATH | ||||
|   ${un.EnvVarUpdate} $0 "PATH" "R" "HKLM" $INSTDIR | ||||
| 
 | ||||
|   # Cleanup registry (deletes all sub keys) | ||||
|   DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${GROUPNAME} ${APPNAME}" | ||||
| SectionEnd | ||||
| @ -20,6 +20,7 @@ import ( | ||||
| 	"bytes" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"log" | ||||
| 	"os" | ||||
| @ -117,3 +118,25 @@ func render(tpl *template.Template, outputFile string, outputPerm os.FileMode, x | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // CopyFile copies a file.
 | ||||
| func CopyFile(dst, src string, mode os.FileMode) { | ||||
| 	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	destFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	defer destFile.Close() | ||||
| 
 | ||||
| 	srcFile, err := os.Open(src) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 	defer srcFile.Close() | ||||
| 
 | ||||
| 	if _, err := io.Copy(destFile, srcFile); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user