diff --git a/.gitignore b/.gitignore index bfd1db1..e506c96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.exe Data/ App/Git +Download diff --git a/App/AppInfo/appinfo.ini b/App/AppInfo/appinfo.ini index 16f89a7..ba1df80 100644 --- a/App/AppInfo/appinfo.ini +++ b/App/AppInfo/appinfo.ini @@ -1,4 +1,4 @@ -[Format] +[Format] Type=PortableApps.comFormat Version=3.5 @@ -43,4 +43,4 @@ ShellCommand= [FileTypeIcons] [Version] PackageVersion=2.25.1.0 -DisplayVersion=2.25.1-beta0-uroesch +DisplayVersion=2.25.1-beta1-uroesch diff --git a/App/AppInfo/update.ini b/App/AppInfo/update.ini new file mode 100644 index 0000000..2d9edc2 --- /dev/null +++ b/App/AppInfo/update.ini @@ -0,0 +1,9 @@ +[Version] +Package = 2.25.1.0 +Display = 2.25.1-beta1-uroesch + +[Archive] +URL1 = https://github.com/git-for-windows/git/releases/download/v2.25.1.windows.1/PortableGit-2.25.1-32-bit.7z.exe +Checksum1 = SHA256:9054e283465ca1153043bae4cf515782b3e0a3bd95c28bfb20f66de3922da1d0 +TargetName1 = Git +ExtractName1 = diff --git a/Other/Update/Postinstall.ps1 b/Other/Update/Postinstall.ps1 new file mode 100644 index 0000000..d9b964b --- /dev/null +++ b/Other/Update/Postinstall.ps1 @@ -0,0 +1,20 @@ +# Run the post-install script + +$_PostInstall = "$AppDir\Git\post-install.bat" + +If (Test-Path $_PostInstall) { + Switch (Is-Unix) { + $True { $_Prefix = 'wine'; break } + default { $_Prefix = ''; break } + } + Try { + Debug info "Run post install command $_Prefix $_PostInstall" + # Will always throw an error as the post-install script + # is removing itself at the end. + Invoke-Expression "$_Prefix $_PostInstall" 2>&1 | Out-Null + } + Catch { + Debug fatal "Failed to run command $_PostInstall" + Exit 127 + } +} diff --git a/Other/Update/Update.ps1 b/Other/Update/Update.ps1 new file mode 100644 index 0000000..2657bbc --- /dev/null +++ b/Other/Update/Update.ps1 @@ -0,0 +1,413 @@ +# ----------------------------------------------------------------------------- +# Description: Generic Update Script for PortableApps +# Author: Urs Roesch +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# Globals +# ----------------------------------------------------------------------------- +$Version = "0.0.11-alpha" +$AppRoot = "$PSScriptRoot\..\.." +$AppDir = "$AppRoot\App" +$AppInfoDir = "$AppDir\AppInfo" +$AppInfoIni = "$AppInfoDir\appinfo.ini" +$UpdateIni = "$AppInfoDir\update.ini" +$Debug = $True + +# ----------------------------------------------------------------------------- +# Classes +# ----------------------------------------------------------------------------- +Class IniConfig { + [string] $File + [object] $Table + [bool] $Verbose = $False + [bool] $Parsed = $False + + IniConfig( + [string] $f + ) { + $This.File = $f + } + + [void] Log([string] $Message) { + If ($This.Verbose) { + Write-Host "IniConfig: $Message" + } + } + + [void] Parse() { + If ($this.Parsed) { return } + $Content = Get-Content $This.File + $Section = '' + $This.Log($Content) + $This.Table = @() + Foreach ($Line in $Content) { + $This.Log("Processing '$Line'") + If ($Line[0] -eq ";") { + $This.Log("Skip comment line") + } + ElseIf ($Line[0] -eq "[") { + $Section = $Line -replace "[\[\]]", "" + $This.Log("Found new section: '$Section'") + } + ElseIf ($Line -like "*=*") { + $This.Log("Found Keyline") + $This.Table += @{ + Section = $Section + Key = $Line.split("=")[0].Trim() + Value = $Line.split("=")[1].Trim() + } + } + } + $This.Parsed = $True + } + + [object] Section([string] $Key) { + $This.Parse() + $Section = @{} + Foreach ($Item in $This.Table) { + If ($Item["Section"] -eq $Key) { + $Section += @{ $Item["Key"] = $Item["Value"] } + } + } + return $Section + } +} +# ----------------------------------------------------------------------------- +Class Download { + [string] $URL + [string] $ExtractName + [string] $TargetName + [string] $Checksum + [string] $DownloadDir = "$PSScriptRoot\..\..\Download" + + Download( + [string] $u, + [string] $en, + [string] $tn, + [string] $c + ){ + $This.URL = $u + $This.ExtractName = $en + $This.TargetName = $tn + $This.Checksum = $c + } + + [string] Basename() { + $Elements = $This.URL.split('/') + $Basename = $Elements[$($Elements.Length-1)] + return $Basename + } + + [string] ExtractTo() { + # If Extract name is empty the downloaded archive has all files + # placed in the root of the archive. In that case we use the + # TargetName and and attach it to the script location + If ($This.ExtractName -eq "") { + return "$($This.DownloadDir)\$($This.TargetName)" + } + return $This.DownloadDir + } + + [string] MoveFrom() { + If ($This.ExtractName -eq "") { + return "$($This.DownloadDir)\$($This.TargetName)" + } + return "$($This.DownloadDir)\$($This.ExtractName)" + } + + [string] MoveTo() { + return "$PSScriptRoot\..\..\App\$($This.TargetName)" + } + + [string] OutFile() { + return "$($This.DownloadDir)\$($This.Basename())" + } +} + +# ----------------------------------------------------------------------------- +# Functions +# ----------------------------------------------------------------------------- +Function Debug() { + param( + [string] $Severity, + [string] $Message + ) + $Color = 'White' + $Severity = $Severity.ToUpper() + Switch ($Severity) { + 'INFO' { $Color = 'Green'; break } + 'WARN' { $Color = 'Yellow'; break } + 'ERROR' { $Color = 'Orange'; break } + 'FATAL' { $Color = 'Red'; break } + default { $Color = 'White'; break } + } + If (-Not($Debug)) { return } + Write-Host "$(Get-Date -Format u) - " -NoNewline + Write-Host $Severity": " -NoNewline -ForegroundColor $Color + Write-Host $Message.Replace("$AppRoot\", '') +} + +# ----------------------------------------------------------------------------- +Function Is-Unix() { + ($PSScriptRoot)[0] -eq '/' +} + +# ----------------------------------------------------------------------------- +Function Which-7Zip() { + $Locations = @( + "$Env:ProgramFiles\7-Zip", + "$Env:ProgramFiles(x86)\7-Zip", + "$AppRoot\..\7-ZipPortable\App\7-Zip" + ) + Switch (Is-Unix) { + $True { + $Prefix = 'wine' + $Binary = '7z' + break + } + default { + $Prefix = '' + $Binary = '7z.exe' + } + } + Try { + $Path = $(Get-Command $Binary).Source.ToString() + } + Catch { + Foreach ($Location in $Locations) { + If (Test-Path "$Location\$Binary") { + $Path = "$Prefix $Location\$Binary" + } + } + } + Finally { + If (!($Path)) { + Debug fatal "Could not locate $Binary" + Exit 76 + } + } + return $Path +} + +# ----------------------------------------------------------------------------- +Function Check-Sum { + param( + [object] $Download + ) + ($Algorithm, $Sum) = $Download.Checksum.Split(':') + $Result = (Get-FileHash -Path $Download.OutFile() -Algorithm $Algorithm).Hash + Debug info "Checksum of INI ($($Sum.ToUpper())) and download ($Result)" + return ($Sum.ToUpper() -eq $Result) +} + +# ----------------------------------------------------------------------------- +Function Download-File { + param( + [object] $Download + ) + If (!(Test-Path $Download.DownloadDir)) { + Debug info "Create directory $($Download.DownloadDir)" + New-Item -Path $Download.DownloadDir -Type directory | Out-Null + } + If (!(Test-Path $Download.OutFile())) { + Debug info "Download URL $($Download.URL) to $($Download.OutFile()).part" + Invoke-WebRequest -Uri $Download.URL ` + -OutFile "$($Download.OutFile()).part" + + Debug info "Move file $($Download.OutFile).part to $($Download.OutFile())" + Move-Item -Path "$($Download.OutFile()).part" ` + -Destination $Download.OutFile() + } + If (!(Check-Sum -Download $Download)) { + Debug fatal "Checksum for $($Download.OutFile()) does not match '$Checksum'" + Exit 1 + } + Debug info "Downloaded file '$($Download.OutFile())'" +} + +# ----------------------------------------------------------------------------- +Function Expand-Download { + param( + [object] $Download + ) + If (!(Test-Path $Download.ExtractTo())) { + Debug info "Create extract directory $($Download.ExtractTo())" + New-Item -Path $Download.ExtractTo() -Type "directory" | Out-Null + } + Debug info "Extract $($Download.OutFile()) to $($Download.ExtractTo())" + Expand-Archive -LiteralPath $Download.OutFile() ` + -DestinationPath $Download.ExtractTo() -Force +} + +# ----------------------------------------------------------------------------- +Function Expand-7Zip { + param( + [object] $Download + ) + $7ZipExe = $(Which-7Zip) + If (!(Test-Path $Download.ExtractTo())) { + Debug info "Create extract directory $($Download.ExtractTo())" + New-Item -Path $Download.ExtractTo() -Type "directory" | Out-Null + } + Debug info "Extract $($Download.OutFile()) to $($Download.ExtractTo())" + $Command = "$7ZipExe x -r -y " + + " -o""$($Download.ExtractTo())"" " + + " ""$($Download.OutFile())""" + Debug info "Running command '$Command'" + Invoke-Expression $Command | Out-Null +} + +# ----------------------------------------------------------------------------- +Function Update-Release { + param( + [object] $Download + ) + Switch -regex ($Download.Basename()) { + '\.[Zz][Ii][Pp]$' { + Expand-Download -Download $Download + break + } + '\.7[Zz]\.[Ee][Xx][Ee]$' { + Expand-7Zip -Download $Download + break + } + } + If (Test-Path $Download.MoveTo()) { + Debug info "Cleanup $($Download.MoveTo())" + Remove-Item -Path $Download.MoveTo() ` + -Force ` + -Recurse + } + Debug info ` + "Move release from $($Download.MoveFrom()) to $($Download.MoveTo())" + Move-Item -Path $Download.MoveFrom() ` + -Destination $Download.MoveTo() ` + -Force +} + +# ----------------------------------------------------------------------------- +Function Update-Appinfo-Item() { + param( + [string] $IniFile, + [string] $Match, + [string] $Replace + ) + If (Test-Path $IniFile) { + Debug info "Update INI File $IniFile with $Match -> $Replace" + $Content = (Get-Content $IniFile) + $Content -replace $Match, $Replace | ` + Out-File -Encoding UTF8 -FilePath $IniFile + } +} + +# ----------------------------------------------------------------------------- +Function Update-Appinfo() { + $Version = $Config.Section("Version") + Update-Appinfo-Item ` + -IniFile $AppInfoIni ` + -Match '^PackageVersion\s*=.*' ` + -Replace "PackageVersion=$($Version['Package'])" + Update-Appinfo-Item ` + -IniFile $AppInfoIni ` + -Match '^DisplayVersion\s*=.*' ` + -Replace "DisplayVersion=$($Version['Display'])" +} + +# ----------------------------------------------------------------------------- +Function Update-Application() { + $Archive = $Config.Section('Archive') + $Position = 1 + While ($True) { + If (-Not ($Archive.ContainsKey("URL$Position"))) { + Break + } + $Download = [Download]::new( + $Archive["URL$Position"], + $Archive["ExtractName$Position"], + $Archive["TargetName$Position"], + $Archive["Checksum$Position"] + ) + Download-File -Download $Download + Update-Release -Download $Download + $Position += 1 + } +} + +# ----------------------------------------------------------------------------- +Function Postinstall() { + $Postinstall = "$PSScriptRoot\Postinstall.ps1" + If (Test-Path $Postinstall) { + . $Postinstall + } +} +# ----------------------------------------------------------------------------- +Function Windows-Path() { + param( [string] $Path ) + $Path = $Path -replace ".*drive_(.*)", '$1' + $Path = $Path.Replace("/", "\") + return $Path +} + +# ----------------------------------------------------------------------------- +Function Create-Launcher() { + Set-Location $AppRoot + $AppPath = (Get-Location) + Try { + Invoke-Helper -Command ` + "..\PortableApps.comLauncher\PortableApps.comLauncherGenerator.exe" + } + Catch { + Debug fatal "Unable to create PortableApps Launcher" + Exit 21 + } +} + +# ----------------------------------------------------------------------------- +Function Create-Installer() { + Try { + Invoke-Helper -Sleep 5 -Command ` + "..\PortableApps.comInstaller\PortableApps.comInstaller.exe" + } + Catch { + Debug fatal "Unable to create installer for PortableApps" + Exit 42 + } +} + +# ----------------------------------------------------------------------------- +Function Invoke-Helper() { + param( + [string] $Command, + [int] $Sleep = $Null + ) + + Set-Location $AppRoot + $AppPath = (Get-Location) + + If (Is-Unix) { + Debug info "Run PA Command: wine $Command $(Windows-Path $AppPath)" + Invoke-Expression "wine $Command $(Windows-Path $AppPath)" + } + Else { + # Windows seems to need a bit of break before + # writing the file completely to disk + Write-FileSystemCache $AppPath.Drive.Name + If ($Sleep) { + Debug info "Waiting for filsystem cache to catch up" + Sleep $Sleep + } + Debug info "Run PA Command '$Command $AppPath'" + Invoke-Expression "$Command $AppPath" + } +} + +# ----------------------------------------------------------------------------- +# Main +# ----------------------------------------------------------------------------- +$Config = [IniConfig]::new($UpdateIni) +Update-Application +Update-Appinfo +Postinstall +Create-Launcher +Create-Installer diff --git a/README.md b/README.md index f6352fd..b8c97d4 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,21 @@ This project is in early beta stage. ## Todo - [ ] Documentation -- [ ] Download script to fetch the application ZIP file +- [x] Download script to fetch the application ZIP file + +## Build + +### Prerequisites + +* [PortableApps.com Launcher](https://portableapps.com/apps/development/portableapps.com_launcher) +* [PortableApps.com Installer](https://portableapps.com/apps/development/portableapps.com_installer) +* [Powershell](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-7) +* [Wine (Linux / MacOS only)](https://www.winehq.org/) + +### Build + +To build the installer run the following command in the root of the git repository. + +``` +powershell Other/Update/Update.ps1 +``` diff --git a/help.html b/help.html index e69de29..88668c4 100644 --- a/help.html +++ b/help.html @@ -0,0 +1,177 @@ +Git for Windows Portable Help + + + + + + +
+

Git for Windows Portable Help

+

compare files on the go

+

Git for Windows Portable allows you to compare and diff files on the go. Learn more about Git for Windows...

+ +Make a Donation - Support PortableApps.com's Hosting and Development + +

Go to the Git for Windows Portable Homepage >>

+ +

Get more portable apps at PortableApps.com

+ +

This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative.

+ +

Git for Windows Portable-Specific Issues

+ + +
+ + +