From 97216b59687659bc0df8d894ef971a737f3496e7 Mon Sep 17 00:00:00 2001 From: Yuanle Song Date: Fri, 15 Nov 2019 20:25:47 +0800 Subject: [PATCH] allow msi upgrade; add shortcuts when installing; - allow msi major upgrade - add desktop and start menu shortcut for mbackup.exe file - set HOME env variable when running rsync.exe. ssh.exe wants to access HOME dir. but this change seems not working in win 10 VM. - add Version info in mbackup.fsproj - mbackup.exe supports --version option. - when build msi file, include version in filename - use printf %A to print exception detail. --- .gitignore | 1 + GetVersion.ps1 | 2 + Lib.fs | 1 + Makefile | 16 ++++--- Program.fs | 26 ++++++++++- mbackup.fsproj | 1 + mbackup.wxs | 45 ++++++++++++++++--- operational | 120 +++++++++++++++++++++++++++++++++++++++++++++++-- 8 files changed, 194 insertions(+), 18 deletions(-) create mode 100644 GetVersion.ps1 diff --git a/.gitignore b/.gitignore index ee654e1..60cb967 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ bin/ *.wixpdb *.msi *-files.wxs +t1* \ No newline at end of file diff --git a/GetVersion.ps1 b/GetVersion.ps1 new file mode 100644 index 0000000..c1253a2 --- /dev/null +++ b/GetVersion.ps1 @@ -0,0 +1,2 @@ +[xml]$FSPROJ = Get-Content mbackup.fsproj +Write-Output $FSPROJ.Project.PropertyGroup.Version diff --git a/Lib.fs b/Lib.fs index 704f633..664fc28 100644 --- a/Lib.fs +++ b/Lib.fs @@ -40,6 +40,7 @@ type Logger() = let appendWhen (pred: bool) (lst: string list) (s: string) = if pred then List.append lst [s] else lst let getEnv (varName: string) = Environment.GetEnvironmentVariable varName +let setEnv (varName: string) (value: string) = Environment.SetEnvironmentVariable(varName, value) let getEnvDefault (varName: string) (defaultValue: string) = let value = Environment.GetEnvironmentVariable varName diff --git a/Makefile b/Makefile index 1669064..267abcc 100644 --- a/Makefile +++ b/Makefile @@ -5,12 +5,16 @@ LIGHT := "$(WIX_DIR)\light.exe" -nologo RSYNC_MINGW_DIR := D:\downloads\apps\rsync-w64 MBACKUP_PUBLISH_DIR := bin\Release\netcoreapp3.0\publish +MSI_DIR := D:\downloads\upload +VERSION := $(shell powershell -NoProfile -File GetVersion.ps1) default: build help: - @cmd /C echo 'Usage: make [build|test|release|clean|dist|all]' + @cmd /C echo "Usage: make [build|test|release|clean|dist|all]" +version: + @cmd /C "echo Version=$(VERSION)" all: test release dist -dist: mbackup.msi +dist: msi release: test dotnet publish --nologo -c Release --self-contained false test: @@ -22,7 +26,7 @@ clean: dotnet clean --nologo cmd /C 'del *.wixobj *.wixpdb *.msi rsync-mingw64-files.wxs' %.wixobj: %.wxs - $(CANDLE) $< + $(CANDLE) -dVersion=$(VERSION) $< rsync-mingw64-files.wxs: $(HEAT) dir $(RSYNC_MINGW_DIR) -cg RsyncHeatGenerated -dr MBACKUP_PROGRAM_FILES -var var.RsyncSourceDir -gg -nologo -out $@ -sw5150 rsync-mingw64-files.wixobj: rsync-mingw64-files.wxs @@ -31,6 +35,6 @@ mbackup-files.wxs: release $(HEAT) dir $(MBACKUP_PUBLISH_DIR) -cg MbackupHeatGenerated -dr MBACKUP_PROGRAM_FILES -var var.MbackupPublishDir -gg -nologo -out $@ -sw5150 mbackup-files.wixobj: mbackup-files.wxs $(CANDLE) -dMbackupPublishDir=$(MBACKUP_PUBLISH_DIR) $< -mbackup.msi: mbackup.wixobj rsync-mingw64-files.wixobj mbackup-files.wixobj - $(LIGHT) $^ -o $@ -.PHONY: default help all dist release test check build clean rsync-mingw64-files.wxs mbackup-files.wxs +msi: mbackup.wixobj rsync-mingw64-files.wixobj mbackup-files.wixobj + $(LIGHT) $^ -o $(MSI_DIR)\mbackup-$(VERSION).msi +.PHONY: default help all dist release test check build clean msi rsync-mingw64-files.wxs mbackup-files.wxs diff --git a/Program.fs b/Program.fs index 4ab276d..d39ac49 100644 --- a/Program.fs +++ b/Program.fs @@ -21,11 +21,14 @@ open Argu open Mbackup.Lib open Mbackup.ConfigParser +let ExitSuccess = 0 let ExitBadParam = 1 let ExitTimeout = 2 let ExitIOError = 3 let ExitUserError = 4 +let version = Reflection.Assembly.GetEntryAssembly().GetName().Version +let versionStr = version.ToString() [] type CLIArguments = @@ -35,6 +38,7 @@ type CLIArguments = | [] Itemize_Changes | Node_Name of nodeName: string | Ssh_Key of sshKeyFilename: string + | [] Version interface IArgParserTemplate with member s.Usage = match s with @@ -44,6 +48,7 @@ type CLIArguments = | Itemize_Changes _ -> "add -i option to rsync" | Node_Name _ -> "local node's name, used in remote logging" | Ssh_Key _ -> "ssh private key, used when backup to remote ssh node" + | Version _ -> "show mbackup version and exit" let programFilesDirWin = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) |> ensureWinDir let programFilesDir = toMingwPath programFilesDirWin @@ -196,6 +201,11 @@ let main argv = let parser = ArgumentParser.Create(programName = "mbackup.exe", errorHandler = errorHandler) let results = parser.Parse argv + + if results.Contains Version then + printfn "mbackup %s" versionStr + Environment.Exit(ExitSuccess) + let dryRun = results.Contains Dry_Run let itemizeChanges = results.Contains Itemize_Changes @@ -257,7 +267,19 @@ let main argv = logger.Info "Note: if you run the following rsync command yourself, make sure the generated file list (%s) is up-to-date.\n%s" mbackupFile (rsyncExe + " " + rsyncArgs) - let proc = Process.Start(rsyncExe, rsyncArgs) + let processStartInfo = + ProcessStartInfo( + FileName = rsyncExe, + Arguments = rsyncArgs) + //set HOME dir to prevent ssh.exe can't access /home//.ssh error. + try + processStartInfo.EnvironmentVariables.Add("HOME", userHomeWin) + setEnv "HOME" userHomeWin + with + | :? ArgumentException -> () // variable already exists + | ex -> logger.Warning "set HOME environment variable failed: %A" ex + // not a critical error, allow program to continue. + let proc = Process.Start(processStartInfo) if proc.WaitForExit Int32.MaxValue then logger.Info "mbackup exit" proc.ExitCode @@ -274,5 +296,5 @@ let main argv = logger.Error "IO Error: %s %s" ex.Source ex.Message ExitIOError | ex -> - logger.Error "Unexpected Error: %s" ex.Message + logger.Error "Unexpected Error: %A" ex ExitIOError diff --git a/mbackup.fsproj b/mbackup.fsproj index 7ac4a9e..fd3fc6f 100644 --- a/mbackup.fsproj +++ b/mbackup.fsproj @@ -6,6 +6,7 @@ win10-x64 Mbackup true + 0.2.3.0 diff --git a/mbackup.wxs b/mbackup.wxs index ea786d9..be729be 100644 --- a/mbackup.wxs +++ b/mbackup.wxs @@ -1,16 +1,45 @@ - + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -35,6 +64,8 @@ + + diff --git a/operational b/operational index e95d9d5..702cfdc 100644 --- a/operational +++ b/operational @@ -80,7 +80,20 @@ dotnet run -- -i this lib doesn't work with dotnet core 3. - Formatted text using printf | F# for fun and profit https://fsharpforfunandprofit.com/posts/printf/ -- +- Wix: a tool to create msi file + WiX Toolset + https://wixtoolset.org/ + Windows Installer XML (WiX) + https://wixtoolset.org/documentation/manual/v3/main/ + + To learn the basics, do read the WiX Tutorial. + https://www.firegiant.com/wix/tutorial/ + https://www.firegiant.com/wix/tutorial/getting-started/ + + Then you can follow the how-tos. + + How To: Implement a Major Upgrade In Your Installer + https://wixtoolset.org/documentation/manual/v3/howtos/updates/major_upgrade.html ** 2019-11-13 install dir layout. C:\Program Files\mbackup\rsync-w64\usr\bin\rsync.exe @@ -211,13 +224,112 @@ Both local.list and local.exclude. - TODO how to add some dir to PATH? I only have one exe. Maybe just create a start menu or desktop shortcut? create desktop shortcut to mbackup.exe - - TODO how to support upgrade when I click a new msi? + installer - Create shortcut to desktop using WiX - Stack Overflow + https://stackoverflow.com/questions/11868499/create-shortcut-to-desktop-using-wix + it works. + install will install two shortcuts. + uninstall will remove both shortcuts. + - DONE how to support upgrade when I click a new msi? currently every msi is a standalone msi and will always install fresh. is the UpgradeCode used for this? does version have any effect on generated msi file? how to integrate this version with dotnet application version? - *now* + + search: wix msi how to support upgrade + How To: Implement a Major Upgrade In Your Installer + https://wixtoolset.org/documentation/manual/v3/howtos/updates/major_upgrade.html + - how to support L10N for wxs file? DowngradeErrorMessage + + - in my application, downgrade should be supported. + - note: element should come after . + - add --version support. + search: dotnet application where to put version info and support --version parameter + + https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build + Build the project and set version 1.2.3.4 as a build parameter using the -p MSBuild option: + dotnet build -p:Version=1.2.3.4 + + how to get the Version in code? + Get App Version in .NET Core - Edi.Wang + https://edi.wang/post/2018/9/27/get-app-version-net-core + First, let's see a typical .NET Core project file with versioning. We can define + the version numbers for AssemblyVersion, FileVersion and Version in the project + file (.csproj). + + + + Exe + netcoreapp2.1 + 1.1.1.1 + 2.2.2.2 + 3.3.3.3-xyz + + + + - problems + - Could not create directory '/home/IEUser/.ssh'. + how to make this error gone? + check ssh option. maybe just set HOME env variable if it doesn't exist when starting rsync process? + + search: dotnet set environment variable + Environment.SetEnvironmentVariable Method + - how to get Version for use in Makefile? + $(file < mbackup.fsproj) doesn't get expanded? + try use $(shell) instead. + FSPROJ := $(shell powershell -NoProfile -Command {cat mbackup.fsproj}) + still not working. + FSPROJ has value of cat mbackup.fsproj + search: makefile read file in windows + no result. + Make is not well supported in windows. + + FSPROJ := $(shell powershell -NoProfile -Command "cat mbackup.fsproj") + this works. + - 此时不应有 < + try do everything in powershell. + makefile in windows sucks. + - upgrade and --version both works. tested in win 10 VM. + - set HOME dir still not working. + Could not create directory '/home/IEUser/.ssh'. + c# - Set environment variables for a process - Stack Overflow + https://stackoverflow.com/questions/14553830/set-environment-variables-for-a-process + System.Environment.SetEnvironmentVariable changes the environment variables of the current process. + If you want to change the variables of a process you create, just use the EnvironmentVariables dictionary property. + still fail. + try set it to unix style path. + neither windows path nor unix path works. + + windows - Could not create directory '/home/username/.ssh' - Stack Overflow + https://stackoverflow.com/questions/36011084/could-not-create-directory-home-username-ssh + try create etc/nsswitch.conf in rsync distribution. + content: + db_home: env windows cygwin desc + this doesn't work. + + To test this problem, just run this command and see the default file name: + & 'C:\Program Files\mbackup\rsync-w64\usr\bin\ssh-keygen.exe' + + windows - vagrant up "Error: Could not create directory '/home/username/.ssh'" when using cygwin - Stack Overflow + https://stackoverflow.com/questions/34754717/vagrant-up-error-could-not-create-directory-home-username-ssh-when-using + + Under Windows, RSync will try and update the %HOME%/.ssh/known_hosts file. If %HOME% is not defined as one of your + environment variables, it may try and add/update that file where it has no permissions, and fail. Solution: Set user + environment variable HOME to be %USERPROFILE%. + + // set HOME dir on system level works on B75I3. maybe when rsync invoke ssh, env variable is lost. + // if system level env variable is required, set HOME when msi is installed if HOME is not set. + + *now* + - System.ArgumentException: Value does not fall within the expected range. + this happens when I run dotnet run on B75I3 dev node. + what is this error? + + this line caused this error: + processStartInfo.EnvironmentVariables.Add("HOME", userHome) + you can't add a var if it already exists. + - mbackup.msi works on B75I3 host. - try mbackup.msi on win 10 VM. how to require dotnet core 3.0 in .wxs file? @@ -246,6 +358,8 @@ Both local.list and local.exclude. in f#, you should use exception. + Environment.Exit(exitCode) also works. + - problems - each file require it's own tag. rsync mingw have many files. I seems I need to generate an installer for -- GitLab