Commit 97216b59 authored by Yuanle Song's avatar Yuanle Song

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.
parent 45a07dbc
......@@ -5,3 +5,4 @@ bin/
\ No newline at end of file
[xml]$FSPROJ = Get-Content mbackup.fsproj
Write-Output $FSPROJ.Project.PropertyGroup.Version
......@@ -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
......@@ -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
@cmd /C echo 'Usage: make [build|test|release|clean|dist|all]'
@cmd /C echo "Usage: make [build|test|release|clean|dist|all]"
@cmd /C "echo Version=$(VERSION)"
all: test release dist
dist: mbackup.msi
dist: msi
release: test
dotnet publish --nologo -c Release --self-contained false
......@@ -22,7 +26,7 @@ clean:
dotnet clean --nologo
cmd /C 'del *.wixobj *.wixpdb *.msi rsync-mingw64-files.wxs'
%.wixobj: %.wxs
$(CANDLE) $<
$(CANDLE) -dVersion=$(VERSION) $<
$(HEAT) dir $(RSYNC_MINGW_DIR) -cg RsyncHeatGenerated -dr MBACKUP_PROGRAM_FILES -var var.RsyncSourceDir -gg -nologo -out [email protected] -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 [email protected] -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
......@@ -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()
[<SuppressMessage("*", "UnionCasesNames")>]
type CLIArguments =
......@@ -35,6 +38,7 @@ type CLIArguments =
| [<AltCommandLine("-i")>] Itemize_Changes
| Node_Name of nodeName: string
| Ssh_Key of sshKeyFilename: string
| [<AltCommandLine("-V")>] 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<CLIArguments>(programName = "mbackup.exe", errorHandler = errorHandler)
let results = parser.Parse argv
if results.Contains Version then
printfn "mbackup %s" versionStr
let dryRun = results.Contains Dry_Run
let itemizeChanges = results.Contains Itemize_Changes
......@@ -257,7 +267,19 @@ let main argv =
"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 =
FileName = rsyncExe,
Arguments = rsyncArgs)
//set HOME dir to prevent ssh.exe can't access /home/<user>/.ssh error.
processStartInfo.EnvironmentVariables.Add("HOME", userHomeWin)
setEnv "HOME" userHomeWin
| :? 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"
......@@ -274,5 +296,5 @@ let main argv =
logger.Error "IO Error: %s %s" ex.Source ex.Message
| ex ->
logger.Error "Unexpected Error: %s" ex.Message
logger.Error "Unexpected Error: %A" ex
......@@ -6,6 +6,7 @@
<?xml version="1.0"?>
<Wix xmlns="">
<Product Id="*" UpgradeCode="3030B91E-5E3E-4151-9A69-B53B72690430" Version="" Language="1033" Name="mbackup" Manufacturer="Yuanle Song">
<Product Id="*" UpgradeCode="3030B91E-5E3E-4151-9A69-B53B72690430" Version="$(var.Version)" Language="1033" Name="mbackup" Manufacturer="Yuanle Song">
<Package InstallerVersion="300" Compressed="yes"/>
<Media Id="1" Cabinet="" EmbedCab="yes" />
<MajorUpgrade AllowDowngrades="yes"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="MBACKUP_PROGRAM_FILES" Name="mbackup" />
<Directory Id="CommonAppDataFolder">
<Directory Id="MBACKUP_DATA" Name="mbackup"/>
<Directory Id="ProgramFiles64Folder">
<Directory Id="MBACKUP_PROGRAM_FILES" Name="mbackup" />
<Directory Id="CommonAppDataFolder">
<Directory Id="MBACKUP_DATA" Name="mbackup"/>
<Directory Id="DesktopFolder" Name="Desktop" />
<Directory Id="ProgramMenuFolder" />
<DirectoryRef Id="DesktopFolder">
<Component Id="ApplicationShortcutDesktop" Guid="*">
<Shortcut Id="ApplicationDesktopShortcut"
Description="Backup your computer using rsync"
<RemoveFolder Id="DesktopShortcut" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\mbackup" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
<DirectoryRef Id="ProgramMenuFolder">
<Component Id="ApplicationShortcutStartMenu" Guid="F7C168BA-BDC9-4C4D-8AE7-722AC399AFD5">
<Shortcut Id="ApplicationStartMenuShortcut"
Description="Backup your computer using rsync"
<RemoveFolder Id="StartMenuShortCut" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\mbackup" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
<DirectoryRef Id="MBACKUP_DATA">
<Component Id="mbackup_default.exclude" Guid="*">
......@@ -35,6 +64,8 @@
<ComponentRef Id="mbackup_default.list" />
<ComponentRef Id="user_default.list" />
<ComponentRef Id="mbackup.txt" />
<ComponentRef Id="ApplicationShortcutStartMenu" />
<ComponentRef Id="ApplicationShortcutDesktop" />
......@@ -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
- Wix: a tool to create msi file
WiX Toolset
Windows Installer XML (WiX)
To learn the basics, do read the WiX Tutorial.
Then you can follow the how-tos.
How To: Implement a Major Upgrade In Your Installer
** 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
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 <Product> version have any effect on generated msi file?
how to integrate this version with dotnet application version?
search: wix msi how to support upgrade
How To: Implement a Major Upgrade In Your Installer
- how to support L10N for wxs file? DowngradeErrorMessage
<MajorUpgrade AllowDowngrades="no" DowngradeErrorMessage="!(loc.NewerVersionInstalled)"
AllowSameVersionUpgrades="no" />
- in my application, downgrade should be supported.
- note: <MajorUpgrade AllowDowngrades="yes"/> element should come after <Media>.
- add --version support.
search: dotnet application where to put version info and support --version parameter
Build the project and set version as a build parameter using the -p MSBuild option:
dotnet build -p:Version=
how to get the Version in code?
Get App Version in .NET Core - Edi.Wang
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).
<Project Sdk="Microsoft.NET.Sdk">
- 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
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
try create etc/nsswitch.conf in rsync distribution.
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
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.
- 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 <Component> tag.
rsync mingw have many files. I seems I need to generate an installer for
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment