Remove packager (#13384)
This commit is contained in:
Родитель
b1ffed5355
Коммит
ef8a5de9c8
|
@ -1,108 +1,16 @@
|
|||
# Final tests
|
||||
# Prepare the release
|
||||
|
||||
- Check the exact **date** of the last release and the **name** of the last PR.
|
||||
- List the PR-s in order, open the [link and (adjust date!)](https://github.com/WalletWasabi/WalletWasabi/pulls?q=is%3Apr+merged%3A%3E%3D2019-07-07+sort%3Aupdated-asc).
|
||||
- Go through all PR, create the Final Test issue. Create test cases according to PR-s and write a list - [Final Test format](https://github.com/WalletWasabi/WalletWasabi/issues/2227).
|
||||
- Go through all issues and pick the [important ones (adjust date!)](https://github.com/WalletWasabi/WalletWasabi/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%3E%3D2019-07-07+sort%3Aupdated-asc+) and add to Final Tests if required.
|
||||
- Check Tor status. Never release during a Tor network disruption: https://status.torproject.org/
|
||||
- At the end there will be a Final Test document.
|
||||
- Do testing contribution game if needed.
|
||||
- Edit the `Contrib/ReleaseHighlight.md` file with the most important changes.
|
||||
|
||||
# Release candidate
|
||||
# Release
|
||||
|
||||
- Go to your own fork of Wasabi and press Draft a new release. Release candidates are not published in the main repository!
|
||||
- Tag version: add `rc1` postfix e.g: v1.1.7rc1.
|
||||
- Set release title e.g: `Wasabi v1.1.7: <Release Title> - Release candidate`.
|
||||
- Add "Do not use this" to the release notes.
|
||||
- Set as a pre-release. Save Draft.
|
||||
- Do Packaging (see below).
|
||||
- Upload the files to the pre-release.
|
||||
- Check `This is a pre-release` and press Publish Release.
|
||||
- Add the pre-release link to the Final Test issue.
|
||||
- Share the Final Test issue link with developers and test it for 24 hours.
|
||||
- Every PR that is contained in the release must be at least 24 hours old.
|
||||
|
||||
Make sure to run a virus detection scan on one of the Release candidate's .msi installer (preferably the final one). You can use this site for example: https://www.virustotal.com/gui/home/upload.
|
||||
|
||||
# Packaging
|
||||
|
||||
- Make sure the local .NET Core version is up to date.
|
||||
- Make sure CI and CodeFactor check out.
|
||||
- Run tests.
|
||||
- MAKE SURE YOU ARE ON THE RIGHT BRANCH AND UP TO DATE in GitHub Desktop on the release machine!
|
||||
- Discard packages.lock changes if there are. Inserted USB drive name must contain the string USB!
|
||||
- Run the [script file](https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Packager/scripts/Wasabi_release.ps1) on the **Windows Release Laptop** and follow the instructions.
|
||||
- At some point you will need to run [this script](https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Packager/scripts/WasabiNoratize.scpt) file on Mac. Don't forget to open the script file on Mac and insert your Apple dev username and password. Guide how to setup it: [macOS release environment](https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Documentation/Guides/MacOsSigning.md).
|
||||
- Finish the script on Windows. Now a folder should pop up with all the files that need to be uploaded to GitHub.
|
||||
- Test asc file for `.msi`.
|
||||
- Final `.msi` test on own computer. Check the About dialog and optionally the BUILDINFO.json next to the wasabi executable, the commit ID should match with the one on GitHub.
|
||||
|
||||
# Final release
|
||||
|
||||
- Draft a [new release at the main repo](https://github.com/WalletWasabi/WalletWasabi/releases/new).
|
||||
- Bump client version. (WalletWasabi/Helpers/Constants.cs) - maybe you already did this.
|
||||
- Create the release notes by using [the template](https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Documentation/ClientRelease/ReleaseNotesTemplate.md). Make sure the the recent changes are in the What's new section.
|
||||
- Run tests.
|
||||
- Do Packaging (see above).
|
||||
- Upload the files to the main repo!
|
||||
- Download MSI from the draft release to your local computer, test it, and verify the version number in about!
|
||||
- Do not set pre-release flag!
|
||||
- Publish the release.
|
||||
|
||||
# Notify
|
||||
|
||||
- Refresh website download and signature links.
|
||||
- [Deploy testnet and mainnet backend](https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Documentation/HowToDeploy.md). Make sure the client version number is bumped here as well. If it is a hotfix you do not need to update the backend, but you need to update the website!
|
||||
- Make sure the commit to release builds.
|
||||
- Tag the commit you want to release with format v0.0.0.0
|
||||
- Push the tag to GitHub
|
||||
- Test the packages
|
||||
- Mark the release as final (remove the draft flag)
|
||||
|
||||
# Announce
|
||||
|
||||
- [Twitter](https://twitter.com) (tag @wasabiwallet #Bitcoin #Privacy).
|
||||
- Submit to [/r/WasabiWallet](https://old.reddit.com/r/WasabiWallet/) and [/r/Bitcoin](https://old.reddit.com/r/Bitcoin/).
|
||||
|
||||
# Backporting
|
||||
|
||||
Backport is a branch. It is used for creating silent releases (hotfixes, small improvements) on top of the last released version. For this reason it has to be maintained with special care.
|
||||
|
||||
## Merge PR into backport (release branch)
|
||||
|
||||
- There is a PR which is merged to master and selected to backport.
|
||||
- Checkout the current backport branch to a new local branch like bp_whatever: `git checkout -b bp_whatever upstream/backport`.
|
||||
- Go to the merged PR / Commits and copy the hash of the commit.
|
||||
- Cherry-pick: `git cherry-pick 35c4db348__hash of the commit__06abcd9278c`.
|
||||
- git push origin bp_whatever.
|
||||
- Create a PR into upstream/backport and name it as [Backport] Whatever.
|
||||
|
||||
## Code signing certificate
|
||||
|
||||
Digicert holds our Code Signing Certificate under the name "zkSNACKs Limited".
|
||||
- Issuing CA: DigiCert SHA2 Assured ID Code Signing CA
|
||||
- Platform: Microsoft Authenticode
|
||||
- Type: Code Signing
|
||||
- CSR Key Size: 3072
|
||||
|
||||
**Renewal**
|
||||
|
||||
- Create a new Certificate Signing Request (CSR) file with DigiCert® Certificate Utility application.
|
||||
DigiCert® Certificate Utility is using the logged in user's public key to encrypt the file and only the same user can decrypt it after we receive the certificate.
|
||||
Make sure to create the CSR file in David's profile (or wherever the release script is located)!
|
||||
- Upload the CSR file to DigiCert.
|
||||
- Wait for DigiCert to issue a new `zksnacks_limited.p7b` file.
|
||||
- Import the `zksnacks_limited.p7b` file to DigiCert® Certificate Utility.
|
||||
- Choose a friendly name for the certificate and apply the default password to it.
|
||||
- Export the `zksnacks_limited.pfx` to `C:\zksnacks_limited.pfx`.
|
||||
- Rename `C:\zksnacks_limited.pfx` to `C:\digicert.pfx`, so the Packager can find it!!
|
||||
|
||||
|
||||
## Packager environment setup
|
||||
|
||||
### WSL
|
||||
|
||||
You can disable WSL sudo password prompt with this oneliner:
|
||||
|
||||
```
|
||||
echo "`whoami` ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/`whoami` && sudo chmod 0440 /etc/sudoers.d/`whoami`
|
||||
```
|
||||
|
||||
Use WSL 1 otherwise you cannot enter anything to the console (sudo password, appleid). https://github.com/microsoft/WSL/issues/4424
|
||||
|
||||
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
### _[Wasabi Wallet](https://WasabiWallet.io) is an easy to use, privacy-focused, open-source, non-custodial, Bitcoin wallet_
|
||||
|
||||
# Download
|
||||
:window: [Windows](https://github.com/WalletWasabi/WalletWasabi/releases/download/v2.0.x/Wasabi-2.0.x.msi)
|
||||
:green_apple: [Apple M1/M2](https://github.com/WalletWasabi/WalletWasabi/releases/download/v2.0.x/Wasabi-2.0.x-arm64.dmg)
|
||||
:apple: [Apple Intel](https://github.com/WalletWasabi/WalletWasabi/releases/download/v2.0.x/Wasabi-2.0.x.dmg)
|
||||
:penguin: [Ubuntu / Debian](https://github.com/WalletWasabi/WalletWasabi/releases/download/v2.0.x/Wasabi-2.0.x.deb)
|
||||
:penguin: [Other Linux](https://github.com/WalletWasabi/WalletWasabi/releases/download/v2.0.x/Wasabi-2.0.x.tar.gz)
|
||||
|
||||
---
|
||||
## Release Highlights
|
||||
|
||||
## Release Summary
|
||||
|
||||
Read the [related blog](https://blog.wasabiwallet.io/) for more information.
|
||||
|
||||
---
|
||||
## Installation Guide
|
||||
Download the operating system relevant software package and install Wasabi like you would with any other software on your computer.
|
||||
For a detailed installation guide, including **signature verification**, see [the documentation](https://docs.wasabiwallet.io/using-wasabi/InstallPackage.html).
|
||||
|
||||
## Documentation
|
||||
:spider_web: [Website](https://wasabiwallet.io)
|
||||
:onion: [Tor onion site](http://wasabiukrxmkdgve5kynjztuovbg43uxcbcxn6y2okcrsg7gb6jdmbad.onion/)
|
||||
:orange_book: [Documentation](https://docs.wasabiwallet.io)
|
||||
:grey_question: [FAQ](https://github.com/WalletWasabi/WalletWasabi/discussions/categories/faq)
|
||||
|
||||
## Advanced Guide
|
||||
If you want to build or update Wasabi from source code, check out [these easy instructions](https://docs.wasabiwallet.io/using-wasabi/BuildSource.html).
|
||||
|
||||
Wasabi uses [reproducible builds](https://reproducible-builds.org/), which you can verify with [this guide](https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Documentation/Guides/DeterministicBuildGuide.md).
|
||||
|
||||
## Requirements
|
||||
- Windows 10 1607+
|
||||
- Windows 11 22000+
|
||||
- macOS 12.0+
|
||||
- Ubuntu 22.04+
|
||||
- Fedora 37+
|
||||
- Debian 11+
|
||||
---
|
||||
|
||||
## Full Changelog
|
|
@ -1,64 +0,0 @@
|
|||
using System.Linq;
|
||||
|
||||
namespace WalletWasabi.Packager;
|
||||
|
||||
/// <summary>
|
||||
/// Class for processing program's command line arguments.
|
||||
/// </summary>
|
||||
public class ArgsProcessor
|
||||
{
|
||||
public ArgsProcessor(string[] args)
|
||||
{
|
||||
Args = args;
|
||||
}
|
||||
|
||||
public string[] Args { get; }
|
||||
|
||||
/// <summary>Builds Wasabi Wallet binaries for supported platforms to be compared then with the official binaries, and terminates.</summary>
|
||||
/// <seealso href="https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Documentation/Guides/DeterministicBuildGuide.md"/>
|
||||
public bool IsOnlyBinariesMode() => IsOneOf("onlybinaries") || Args is null || Args.Length == 0;
|
||||
|
||||
public bool IsContinuousDeliveryMode() => IsOneOf("cdelivery");
|
||||
|
||||
public bool IsPublish() => IsOneOf("publish");
|
||||
|
||||
public bool IsSign() => IsOneOf("sign");
|
||||
|
||||
public bool IsGeneratePrivateKey() => IsOneOf("generatekeys");
|
||||
|
||||
private bool IsOneOf(params string[] values)
|
||||
{
|
||||
foreach (var value in values)
|
||||
{
|
||||
foreach (var arg in Args)
|
||||
{
|
||||
if (arg.Trim().TrimStart('-').Equals(value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public (string AppleId, string Password) GetAppleIdAndPassword()
|
||||
{
|
||||
string appleId = "";
|
||||
string password = "";
|
||||
|
||||
try
|
||||
{
|
||||
var appleidArg = Args.First(a => a.Contains("appleid", StringComparison.InvariantCultureIgnoreCase));
|
||||
var parameters = appleidArg.Split("=")[1];
|
||||
var idAndPassword = parameters.Split(":");
|
||||
appleId = idAndPassword[0];
|
||||
password = idAndPassword[1];
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
return (appleId, password);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WalletWasabi.Packager;
|
||||
|
||||
/// <summary>
|
||||
/// Contains information about environment and source code that was used to produce a Wasabi Wallet build.
|
||||
/// </summary>
|
||||
public class BuildInfo
|
||||
{
|
||||
[JsonConstructor]
|
||||
public BuildInfo(string netRuntimeVersion, string netSdkVersion, string gitCommitHash)
|
||||
{
|
||||
NetRuntimeVersion = netRuntimeVersion;
|
||||
NetSdkVersion = netSdkVersion;
|
||||
GitCommitHash = gitCommitHash;
|
||||
}
|
||||
|
||||
[JsonPropertyName("NetRuntimeVersion")]
|
||||
public string NetRuntimeVersion { get; }
|
||||
|
||||
[JsonPropertyName("NetSdkVersion")]
|
||||
public string NetSdkVersion { get; }
|
||||
|
||||
/// <summary>Git commit hash corresponding with the code that was used to produce a Wasabi Wallet build.</summary>
|
||||
[JsonPropertyName("GitCommitHash")]
|
||||
public string GitCommitHash { get; }
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LSArchitecturePriority</key>
|
||||
<array>
|
||||
<string>x86_64</string>
|
||||
</array>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>WasabiLogo.icns</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>?</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>?</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>wassabee</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Wasabi Wallet</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>zksnacks.wasabiwallet</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSAppleScriptEnabled</key>
|
||||
<true/>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.finance</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
</dict>
|
||||
</plist>
|
Двоичный файл не отображается.
Двоичные данные
WalletWasabi.Packager/Content/Osx/Dmg/.DS_Store.dat
Двоичные данные
WalletWasabi.Packager/Content/Osx/Dmg/.DS_Store.dat
Двоичный файл не отображается.
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 5.0 KiB |
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -1 +0,0 @@
|
|||
5D4F6D41-8967-4D1E-9953-35A263D5EFDF
|
Двоичные данные
WalletWasabi.Packager/Content/Osx/WasabiLogo.icns
Двоичные данные
WalletWasabi.Packager/Content/Osx/WasabiLogo.icns
Двоичный файл не отображается.
|
@ -1,7 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
key_chain="login.keychain"
|
||||
key_chain_pass=""
|
||||
security unlock-keychain -p "$key_chain_pass" "$key_chain"
|
||||
security import macdevsign.p12 -k "$key_chain" -P "alma" -A
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k "$key_chain_pass" "$key_chain"
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1 +0,0 @@
|
|||
global using System;
|
|
@ -1,462 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using WalletWasabi.Helpers;
|
||||
|
||||
namespace WalletWasabi.Packager;
|
||||
|
||||
public static class MacSignTools
|
||||
{
|
||||
public static void Sign(ArgsProcessor argsProcessor)
|
||||
{
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
throw new NotSupportedException("This signing method is only valid on macOS!");
|
||||
}
|
||||
|
||||
Console.WriteLine("Phase: finding the zip file on desktop which contains the compiled binaries from Windows.");
|
||||
|
||||
string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
string removableDriveFolder = Tools.GetSingleUsbDrive();
|
||||
|
||||
var srcZipFileNamePattern = "WasabiToNotarize-*";
|
||||
var files = Directory.GetFiles(removableDriveFolder, srcZipFileNamePattern);
|
||||
if (files.Length != 2)
|
||||
{
|
||||
throw new InvalidDataException($"{srcZipFileNamePattern} file missing or there are more! There must be exactly two!");
|
||||
}
|
||||
|
||||
var (appleId, password) = argsProcessor.GetAppleIdAndPassword();
|
||||
|
||||
while (string.IsNullOrWhiteSpace(appleId))
|
||||
{
|
||||
Console.WriteLine("Enter appleId (email):");
|
||||
appleId = Console.ReadLine();
|
||||
}
|
||||
|
||||
while (string.IsNullOrWhiteSpace(password))
|
||||
{
|
||||
Console.WriteLine("Enter password:");
|
||||
password = Console.ReadLine();
|
||||
}
|
||||
|
||||
foreach (var zipPath in files)
|
||||
{
|
||||
var zipFile = Path.GetFileName(zipPath);
|
||||
var versionPrefix = Path.GetFileNameWithoutExtension(zipPath).Split('-')[1]; // Example: "WasabiToNotarize-2.0.0.0-arm64.zip or WasabiToNotarize-2.0.0.0.zip ".
|
||||
var workingDir = Path.Combine(desktopPath, "wasabiTemp");
|
||||
var dmgPath = Path.Combine(workingDir, "dmg");
|
||||
var unzippedPath = Path.Combine(workingDir, "unzipped");
|
||||
var appName = $"{Constants.AppName}.app";
|
||||
var appPath = Path.Combine(dmgPath, appName);
|
||||
var appContentsPath = Path.Combine(appPath, "Contents");
|
||||
var appMacOsPath = Path.Combine(appContentsPath, "MacOS");
|
||||
var appResPath = Path.Combine(appContentsPath, "Resources");
|
||||
var appFrameworksPath = Path.Combine(appContentsPath, "Frameworks");
|
||||
var infoFilePath = Path.Combine(appContentsPath, "Info.plist");
|
||||
var dmgFileName = zipFile.Replace("WasabiToNotarize", "Wasabi").Replace("zip", "dmg");
|
||||
var dmgFilePath = Path.Combine(workingDir, dmgFileName);
|
||||
var dmgUnzippedFilePath = Path.Combine(workingDir, $"Wasabi.tmp.dmg");
|
||||
var appNotarizeFilePath = Path.Combine(workingDir, $"Wasabi-{versionPrefix}.zip");
|
||||
var contentsPath = Path.GetFullPath(Path.Combine(Program.PackagerProjectDirectory.Replace("\\", "//"), "Content", "Osx"));
|
||||
var entitlementsPath = Path.Combine(contentsPath, "entitlements.plist");
|
||||
var dmgContentsDir = Path.Combine(contentsPath, "Dmg");
|
||||
var desktopDmgFilePath = Path.Combine(desktopPath, dmgFileName);
|
||||
|
||||
var signArguments = $"--sign \"L233B2JQ68\" --verbose --force --options runtime --timestamp";
|
||||
|
||||
Console.WriteLine("Phase: creating the working directory.");
|
||||
|
||||
if (Directory.Exists(workingDir))
|
||||
{
|
||||
DeleteWithChmod(workingDir);
|
||||
}
|
||||
|
||||
if (File.Exists(desktopDmgFilePath))
|
||||
{
|
||||
File.Delete(desktopDmgFilePath);
|
||||
}
|
||||
|
||||
Console.WriteLine("Phase: creating the app.");
|
||||
|
||||
IoHelpers.EnsureDirectoryExists(appResPath);
|
||||
IoHelpers.EnsureDirectoryExists(appMacOsPath);
|
||||
|
||||
ZipFile.ExtractToDirectory(zipPath, appMacOsPath); // Copy the binaries.
|
||||
|
||||
IoHelpers.CopyFilesRecursively(new DirectoryInfo(Path.Combine(contentsPath, "App")), new DirectoryInfo(appPath));
|
||||
|
||||
Console.WriteLine("Update the plist file with current information for example with version.");
|
||||
|
||||
var lines = File.ReadAllLines(infoFilePath);
|
||||
string? bundleIdentifier = null;
|
||||
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
string line = lines[i];
|
||||
if (!line.TrimStart().StartsWith("<key>", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.Contains("CFBundleShortVersionString", StringComparison.InvariantCulture) ||
|
||||
line.Contains("CFBundleVersion", StringComparison.InvariantCulture))
|
||||
{
|
||||
lines[i + 1] = lines[i + 1].Replace("?", $"{Version.Parse(versionPrefix).ToString(3)}"); // Apple allow only 3 version tags in plist.
|
||||
}
|
||||
else if (line.Contains("CFBundleIdentifier", StringComparison.InvariantCulture))
|
||||
{
|
||||
bundleIdentifier = lines[i + 1].Trim().Replace("<string>", "").Replace("</string>", "");
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(bundleIdentifier))
|
||||
{
|
||||
throw new InvalidDataException("Bundle identifier not found in plist file.");
|
||||
}
|
||||
|
||||
File.Delete(infoFilePath);
|
||||
|
||||
File.WriteAllLines(infoFilePath, lines);
|
||||
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "chmod",
|
||||
Arguments = $"-R u+rwX,go+rX,go-w \"{appPath}\"",
|
||||
WorkingDirectory = workingDir
|
||||
}))
|
||||
{
|
||||
WaitProcessToFinish(process, "chmod");
|
||||
}
|
||||
|
||||
var filesToCheck = new[] { entitlementsPath };
|
||||
|
||||
foreach (var file in filesToCheck)
|
||||
{
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
throw new FileNotFoundException($"File missing: {file}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Signing the files in app.");
|
||||
|
||||
IoHelpers.EnsureDirectoryExists(appResPath);
|
||||
IoHelpers.EnsureDirectoryExists(appMacOsPath);
|
||||
|
||||
var executables = GetExecutables(appPath);
|
||||
|
||||
// The main executable needs to be signed last.
|
||||
var filesToSignInOrder = Directory.GetFiles(appPath, "*.*", SearchOption.AllDirectories)
|
||||
.OrderBy(file => executables.Contains(file))
|
||||
.OrderBy(file => new FileInfo(file).Name == "wassabee")
|
||||
.ToArray();
|
||||
|
||||
foreach (var file in executables)
|
||||
{
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "chmod",
|
||||
Arguments = $"u+x \"{file}\"",
|
||||
WorkingDirectory = workingDir
|
||||
});
|
||||
WaitProcessToFinish(process, "chmod");
|
||||
}
|
||||
|
||||
SignDirectory(filesToSignInOrder, workingDir, signArguments, entitlementsPath);
|
||||
|
||||
Console.WriteLine("Phase: verifying the signature.");
|
||||
|
||||
Verify(appPath);
|
||||
|
||||
Console.WriteLine("Phase: notarize the app.");
|
||||
|
||||
// Source: https://blog.frostwire.com/2019/08/27/apple-notarization-the-signature-of-the-binary-is-invalid-one-other-reason-not-explained-in-apple-developer-documentation/
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "ditto",
|
||||
Arguments = $"-c -k --keepParent \"{appPath}\" \"{appNotarizeFilePath}\"",
|
||||
WorkingDirectory = workingDir
|
||||
}))
|
||||
{
|
||||
WaitProcessToFinish(process, "ditto");
|
||||
}
|
||||
|
||||
Notarize(appleId, appNotarizeFilePath);
|
||||
Staple(appPath);
|
||||
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "spctl",
|
||||
Arguments = $"-a -t exec -vv \"{appPath}\"",
|
||||
WorkingDirectory = workingDir,
|
||||
RedirectStandardError = true
|
||||
}))
|
||||
{
|
||||
var nonNullProcess = WaitProcessToFinish(process, "spctl");
|
||||
string result = nonNullProcess.StandardError.ReadToEnd();
|
||||
if (!result.Contains(": accepted"))
|
||||
{
|
||||
throw new InvalidOperationException(result);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Phase: creating the dmg.");
|
||||
|
||||
if (File.Exists(dmgFilePath))
|
||||
{
|
||||
File.Delete(dmgFilePath);
|
||||
}
|
||||
|
||||
Console.WriteLine("Phase: creating dmg.");
|
||||
|
||||
IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentsDir), new DirectoryInfo(dmgPath));
|
||||
|
||||
File.Copy(Path.Combine(contentsPath, "WasabiLogo.icns"), Path.Combine(dmgPath, ".VolumeIcon.icns"), true);
|
||||
|
||||
var temp = Path.Combine(dmgPath, ".DS_Store.dat");
|
||||
File.Move(temp, Path.Combine(dmgPath, ".DS_Store"), true);
|
||||
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "ln",
|
||||
Arguments = "-s /Applications",
|
||||
WorkingDirectory = dmgPath
|
||||
}))
|
||||
{
|
||||
WaitProcessToFinish(process, "ln");
|
||||
}
|
||||
|
||||
var hdutilCreateArgs = string.Join(
|
||||
" ",
|
||||
new string[]
|
||||
{
|
||||
"create",
|
||||
$"\"{dmgUnzippedFilePath}\"",
|
||||
"-ov",
|
||||
$"-volname \"Wasabi Wallet\"",
|
||||
"-fs HFS+",
|
||||
$"-srcfolder \"{dmgPath}\""
|
||||
});
|
||||
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "hdiutil",
|
||||
Arguments = hdutilCreateArgs,
|
||||
WorkingDirectory = dmgPath
|
||||
}))
|
||||
{
|
||||
WaitProcessToFinish(process, "hdiutil");
|
||||
}
|
||||
|
||||
var hdutilConvertArgs = string.Join(
|
||||
" ",
|
||||
new string[]
|
||||
{
|
||||
"convert",
|
||||
$"\"{dmgUnzippedFilePath}\"",
|
||||
"-format UDZO",
|
||||
$"-o \"{dmgFilePath}\""
|
||||
});
|
||||
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "hdiutil",
|
||||
Arguments = hdutilConvertArgs,
|
||||
WorkingDirectory = dmgPath
|
||||
}))
|
||||
{
|
||||
WaitProcessToFinish(process, "hdiutil");
|
||||
}
|
||||
|
||||
Console.WriteLine("Phase: signing the dmg file.");
|
||||
|
||||
SignFile($"{signArguments} --entitlements \"{entitlementsPath}\" \"{dmgFilePath}\"", dmgPath);
|
||||
|
||||
Console.WriteLine("Phase: verifying the signature.");
|
||||
|
||||
Verify(dmgFilePath);
|
||||
|
||||
Console.WriteLine("Phase: notarize dmg");
|
||||
Notarize(appleId, dmgFilePath);
|
||||
|
||||
Console.WriteLine("Phase: staple dmp");
|
||||
Staple(dmgFilePath);
|
||||
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "spctl",
|
||||
Arguments = $"-a -t open --context context:primary-signature -v \"{dmgFilePath}\"",
|
||||
WorkingDirectory = workingDir,
|
||||
RedirectStandardError = true
|
||||
}))
|
||||
{
|
||||
var nonNullProcess = WaitProcessToFinish(process, "spctl");
|
||||
string result = nonNullProcess.StandardError.ReadToEnd();
|
||||
if (!result.Contains(": accepted"))
|
||||
{
|
||||
throw new InvalidOperationException(result);
|
||||
}
|
||||
}
|
||||
|
||||
File.Move(dmgFilePath, desktopDmgFilePath);
|
||||
DeleteWithChmod(workingDir);
|
||||
|
||||
Console.WriteLine($"Phase: finished for {dmgFileName}.");
|
||||
|
||||
var toRemovableFilePath = Path.Combine(removableDriveFolder, Path.GetFileName(desktopDmgFilePath));
|
||||
File.Move(desktopDmgFilePath, toRemovableFilePath, true);
|
||||
|
||||
if (File.Exists(zipPath))
|
||||
{
|
||||
File.Delete(zipPath);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Phase: finished successfully.");
|
||||
}
|
||||
|
||||
private static Process WaitProcessToFinish(Process? process, string processName)
|
||||
{
|
||||
if (process is null)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not start ${processName} process.");
|
||||
}
|
||||
process.WaitForExit();
|
||||
return process;
|
||||
}
|
||||
|
||||
private static void Notarize(string appleId, string filePath)
|
||||
{
|
||||
Console.WriteLine("Start notarizing, uploading file.");
|
||||
|
||||
// -p WasabiNotarize = Saved the credentials in the keychain profile which keeps the password safe on the local machine. Name of the profile is "WasabiNotarize".
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "xcrun",
|
||||
Arguments = $"notarytool submit --wait --apple-id \"{appleId}\" -p \"WasabiNotarize\" \"{filePath}\" ",
|
||||
RedirectStandardOutput = true,
|
||||
});
|
||||
|
||||
var nonNullProcess = WaitProcessToFinish(process, "xcrum");
|
||||
string result = nonNullProcess.StandardOutput.ReadToEnd();
|
||||
|
||||
Console.WriteLine(result);
|
||||
}
|
||||
|
||||
private static void Staple(string filePath)
|
||||
{
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "xcrun",
|
||||
Arguments = $"stapler staple \"{filePath}\"",
|
||||
});
|
||||
WaitProcessToFinish(process, "xcrum");
|
||||
}
|
||||
|
||||
private static void DeleteWithChmod(string path)
|
||||
{
|
||||
using (var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "chmod",
|
||||
Arguments = $"-R ugo+rwx \"{path}\"",
|
||||
}))
|
||||
{
|
||||
WaitProcessToFinish(process, "chmod");
|
||||
}
|
||||
|
||||
IoHelpers.TryDeleteDirectoryAsync(path).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
private static void SignFile(string arguments, string workingDir)
|
||||
{
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "codesign",
|
||||
Arguments = arguments,
|
||||
WorkingDirectory = workingDir,
|
||||
RedirectStandardError = true
|
||||
});
|
||||
var nonNullProcess = WaitProcessToFinish(process, "codesign");
|
||||
var result = nonNullProcess.StandardError.ReadToEnd();
|
||||
if (result.Contains("code object is not signed at all"))
|
||||
{
|
||||
throw new InvalidOperationException(result);
|
||||
}
|
||||
|
||||
if (result.Contains("xcrun: error: invalid active developer path"))
|
||||
{
|
||||
throw new InvalidOperationException($"{result}\ntip: run xcode-select --install");
|
||||
}
|
||||
|
||||
Console.WriteLine(result.Trim());
|
||||
}
|
||||
|
||||
private static void Verify(string path)
|
||||
{
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "codesign",
|
||||
Arguments = $"-dv --verbose=4 \"{path}\"",
|
||||
RedirectStandardError = true,
|
||||
});
|
||||
var nonNullProcess = WaitProcessToFinish(process, "codesign");
|
||||
string result = nonNullProcess.StandardError.ReadToEnd();
|
||||
if (!result.Contains("Authority=Developer ID Application: zkSNACKs Ltd."))
|
||||
{
|
||||
throw new InvalidOperationException(result);
|
||||
}
|
||||
}
|
||||
|
||||
private static void SignDirectory(string[] files, string workingDir, string signArguments, string entitlementsPath)
|
||||
{
|
||||
// Tor already signed by: The Tor Project, Inc (MADPSAYN6T)
|
||||
|
||||
// Wassabee has to be signed at the end. Otherwise codesign will throw a "submodule not signed" error.
|
||||
foreach (var file in files)
|
||||
{
|
||||
var fileName = new FileInfo(file).Name;
|
||||
|
||||
if (fileName == ".DS_Store")
|
||||
{
|
||||
File.Delete(file);
|
||||
continue;
|
||||
}
|
||||
|
||||
SignFile($"{signArguments} --entitlements \"{entitlementsPath}\" \"{file}\"", workingDir);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetExecutables(string appPath)
|
||||
{
|
||||
string result = ExecuteBashCommand($"find -H \"{appPath}\" -print0 | xargs -0 file | grep \"Mach-O.* executable\"");
|
||||
|
||||
var lines = result.Split("\n").Where(x => !string.IsNullOrWhiteSpace(x));
|
||||
var files = lines.Select(line => line.Split(":").First());
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
private static string ExecuteBashCommand(string command)
|
||||
{
|
||||
// according to: https://stackoverflow.com/a/15262019/637142
|
||||
// Thanks to this we will pass everything as one command.
|
||||
command = command.Replace("\"", "\"\"");
|
||||
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "/bin/bash",
|
||||
Arguments = $"-c \"{command}\"",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true
|
||||
})
|
||||
?? throw new InvalidOperationException("Could not start bash process.");
|
||||
var result = process.StandardOutput.ReadToEnd();
|
||||
process.WaitForExit();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -1,672 +0,0 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using WalletWasabi.Helpers;
|
||||
using WalletWasabi.Userfacing;
|
||||
|
||||
namespace WalletWasabi.Packager;
|
||||
|
||||
/// <summary>
|
||||
/// Instructions:
|
||||
/// <list type="number">
|
||||
/// <item>Bump Client version (or else wrong .msi will be created) - <see cref="Constants.ClientVersion"/>.</item>
|
||||
/// <item>Publish with Packager.</item>
|
||||
/// <item>Build WIX project with Release and x64 configuration.</item>
|
||||
/// <item>Sign with Packager, set restore true so the password won't be kept.</item>
|
||||
/// </list>
|
||||
/// <seealso href="https://github.com/WalletWasabi/WalletWasabi/blob/master/WalletWasabi.Documentation/ClientDeployment.md"/>
|
||||
/// </summary>
|
||||
public static class Program
|
||||
{
|
||||
public const string PfxPath = "C:\\digicert.pfx";
|
||||
|
||||
public const string DaemonExecutableName = Constants.DaemonExecutableName;
|
||||
public const string ExecutableName = Constants.ExecutableName;
|
||||
|
||||
private const string WasabiPrivateKeyFilePath = @"C:\wasabi\Wasabi.privkey";
|
||||
private const string WasabiPublicKeyFilePath = @"C:\wasabi\Wasabi.pubkey";
|
||||
|
||||
/// <remarks>Only 64-bit platforms are supported for now.</remarks>
|
||||
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog"/>
|
||||
private static string[] Targets = new[]
|
||||
{
|
||||
"win-x64",
|
||||
"linux-x64",
|
||||
"osx-x64",
|
||||
"osx-arm64"
|
||||
};
|
||||
|
||||
private static string VersionPrefix = Constants.ClientVersion.Revision == 0 ? Constants.ClientVersion.ToString(3) : Constants.ClientVersion.ToString();
|
||||
|
||||
private static bool OnlyBinaries;
|
||||
private static bool IsContinuousDelivery;
|
||||
|
||||
public static string PackagerProjectDirectory { get; } = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", ".."));
|
||||
public static string SolutionDirectory { get; } = Path.GetFullPath(Path.Combine(PackagerProjectDirectory, ".."));
|
||||
public static string DesktopProjectDirectory { get; } = Path.GetFullPath(Path.Combine(SolutionDirectory, "WalletWasabi.Fluent.Desktop"));
|
||||
public static string LibraryProjectDirectory { get; } = Path.GetFullPath(Path.Combine(SolutionDirectory, "WalletWasabi"));
|
||||
public static string WixProjectDirectory { get; } = Path.GetFullPath(Path.Combine(SolutionDirectory, "WalletWasabi.WindowsInstaller"));
|
||||
public static string BinDistDirectory { get; } = Path.GetFullPath(Path.Combine(DesktopProjectDirectory, "bin", "dist"));
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point.
|
||||
/// </summary>
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
var argsProcessor = new ArgsProcessor(args);
|
||||
|
||||
// For now this is enough. If you run it on macOS you want to sign.
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
MacSignTools.Sign(argsProcessor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argsProcessor.IsGeneratePrivateKey())
|
||||
{
|
||||
await WasabiSignerHelpers.GeneratePrivateAndPublicKeyToFileAsync(WasabiPrivateKeyFilePath, WasabiPublicKeyFilePath).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only binaries mode is for deterministic builds.
|
||||
OnlyBinaries = argsProcessor.IsOnlyBinariesMode();
|
||||
|
||||
IsContinuousDelivery = argsProcessor.IsContinuousDeliveryMode();
|
||||
|
||||
ReportStatus();
|
||||
|
||||
if (argsProcessor.IsPublish() || IsContinuousDelivery || OnlyBinaries)
|
||||
{
|
||||
await PublishAsync().ConfigureAwait(false);
|
||||
|
||||
IoHelpers.OpenFolderInFileExplorer(BinDistDirectory);
|
||||
}
|
||||
|
||||
if (argsProcessor.IsSign())
|
||||
{
|
||||
await SignAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReportStatus()
|
||||
{
|
||||
if (OnlyBinaries)
|
||||
{
|
||||
Console.WriteLine("I'll only generate binaries and disregard all other options.");
|
||||
}
|
||||
Console.WriteLine($"{nameof(VersionPrefix)}:\t\t\t{VersionPrefix}");
|
||||
Console.WriteLine($"{nameof(ExecutableName)}:\t\t\t{ExecutableName}");
|
||||
|
||||
Console.WriteLine();
|
||||
Console.Write($"{nameof(Targets)}:\t\t\t");
|
||||
foreach (var target in Targets)
|
||||
{
|
||||
if (Targets.Last() != target)
|
||||
{
|
||||
Console.Write($"{target}, ");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write(target);
|
||||
}
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private static async Task SignAsync()
|
||||
{
|
||||
foreach (string target in Targets)
|
||||
{
|
||||
if (target.StartsWith("win", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string publishedFolder = Path.Combine(BinDistDirectory, target);
|
||||
|
||||
Console.WriteLine("Move created .msi");
|
||||
var msiPath = Path.Combine(WixProjectDirectory, "bin", "Release", "Wasabi.msi");
|
||||
var msiFileName = Path.GetFileNameWithoutExtension(msiPath);
|
||||
var newMsiPath = Path.Combine(BinDistDirectory, $"{msiFileName}-{VersionPrefix}.msi");
|
||||
|
||||
if (File.Exists(newMsiPath))
|
||||
{
|
||||
Console.WriteLine("MSI file was already there, skipping code signing phase.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!File.Exists(msiPath))
|
||||
{
|
||||
throw new Exception(".msi does not exist. Expected path: Wasabi.msi.");
|
||||
}
|
||||
|
||||
File.Move(msiPath, newMsiPath);
|
||||
|
||||
Console.Write("Enter Code Signing Certificate Password: ");
|
||||
string pfxPassword = PasswordConsole.ReadPassword();
|
||||
|
||||
// Sign code with digicert.
|
||||
StartProcessAndWaitForExit("cmd", BinDistDirectory, $"signtool sign /d \"Wasabi Wallet\" /f \"{PfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit");
|
||||
|
||||
await IoHelpers.TryDeleteDirectoryAsync(publishedFolder).ConfigureAwait(false);
|
||||
Console.WriteLine($"Deleted {publishedFolder}");
|
||||
}
|
||||
else if (target.StartsWith("osx", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string dmgFileName = target.Contains("arm") ? $"Wasabi-{VersionPrefix}.dmg" : $"Wasabi-{VersionPrefix}-arm64.dmg";
|
||||
string destinationFilePath = Path.Combine(BinDistDirectory, dmgFileName);
|
||||
if (File.Exists(destinationFilePath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string dmgFilePath = Path.Combine(Tools.GetSingleUsbDrive(), dmgFileName);
|
||||
|
||||
if (!File.Exists(dmgFilePath))
|
||||
{
|
||||
throw new Exception(".dmg does not exist.");
|
||||
}
|
||||
|
||||
File.Move(dmgFilePath, destinationFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Signing final files...");
|
||||
var finalFiles = Directory.GetFiles(BinDistDirectory);
|
||||
|
||||
var sha256SumsFilePath = Path.Combine(BinDistDirectory, "SHA256SUMS");
|
||||
|
||||
foreach (var finalFile in finalFiles)
|
||||
{
|
||||
StartProcessAndWaitForExit("cmd", BinDistDirectory, $"gpg --armor --detach-sign {finalFile} && exit");
|
||||
|
||||
StartProcessAndWaitForExit("cmd", WixProjectDirectory, $"git checkout -- ComponentsGenerated.wxs && exit");
|
||||
|
||||
ExecuteBashCommands(new[] { $"sha256sum {Path.GetFileName(finalFile)} >> SHA256SUMS" });
|
||||
}
|
||||
|
||||
StartProcessAndWaitForExit("cmd", BinDistDirectory, $"gpg --sign --digest-algo sha256 -a --clearsign --armor --output SHA256SUMS.asc SHA256SUMS && exit");
|
||||
|
||||
// We do not need this file anymore SHA256SUMS.ASC contains the hashes and the signature as well.
|
||||
File.Delete(sha256SumsFilePath);
|
||||
|
||||
using var key = await WasabiSignerHelpers.GetPrivateKeyFromFileAsync(WasabiPrivateKeyFilePath).ConfigureAwait(false);
|
||||
|
||||
// We will sign the whole file with the hashes and the pgp signature.
|
||||
var sha256sumAscFilePath = Path.Combine(BinDistDirectory, "SHA256SUMS.asc");
|
||||
await WasabiSignerHelpers.SignSha256SumsFileAsync(sha256sumAscFilePath, key).ConfigureAwait(false);
|
||||
|
||||
// Verify back the signature file.
|
||||
await WasabiSignerHelpers.VerifySha256SumsFileAsync(sha256sumAscFilePath).ConfigureAwait(false);
|
||||
|
||||
// Verify back Wasabi installer's hashes
|
||||
await WasabiSignerHelpers.VerifyInstallerFileHashesAsync(finalFiles, sha256sumAscFilePath).ConfigureAwait(false);
|
||||
|
||||
IoHelpers.OpenFolderInFileExplorer(BinDistDirectory);
|
||||
}
|
||||
|
||||
private static async Task PublishAsync()
|
||||
{
|
||||
if (Directory.Exists(BinDistDirectory))
|
||||
{
|
||||
await IoHelpers.TryDeleteDirectoryAsync(BinDistDirectory).ConfigureAwait(false);
|
||||
Console.WriteLine($"# Deleted {BinDistDirectory}");
|
||||
}
|
||||
|
||||
Console.WriteLine($"# Run dotnet restore");
|
||||
StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "restore --locked-mode");
|
||||
|
||||
Console.WriteLine($"# Run dotnet clean");
|
||||
StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "clean --configuration Release");
|
||||
|
||||
string desktopBinReleaseDirectory = Path.GetFullPath(Path.Combine(DesktopProjectDirectory, "bin", "Release"));
|
||||
string libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(LibraryProjectDirectory, "bin", "Release"));
|
||||
|
||||
if (Directory.Exists(desktopBinReleaseDirectory))
|
||||
{
|
||||
await IoHelpers.TryDeleteDirectoryAsync(desktopBinReleaseDirectory).ConfigureAwait(false);
|
||||
Console.WriteLine($"# Deleted {desktopBinReleaseDirectory}");
|
||||
}
|
||||
|
||||
if (Directory.Exists(libraryBinReleaseDirectory))
|
||||
{
|
||||
await IoHelpers.TryDeleteDirectoryAsync(libraryBinReleaseDirectory).ConfigureAwait(false);
|
||||
Console.WriteLine($"# Deleted {libraryBinReleaseDirectory}");
|
||||
}
|
||||
|
||||
var deterministicFileNameTag = IsContinuousDelivery ? $"{DateTimeOffset.UtcNow:ddMMyyyy}{DateTimeOffset.UtcNow.TimeOfDay.TotalSeconds}" : VersionPrefix;
|
||||
var deliveryPath = IsContinuousDelivery ? Path.Combine(BinDistDirectory, "cdelivery") : BinDistDirectory;
|
||||
|
||||
IoHelpers.EnsureDirectoryExists(deliveryPath);
|
||||
Console.WriteLine($"# Binaries will be delivered here: {deliveryPath}");
|
||||
|
||||
string buildInfoJson = GetBuildInfoData();
|
||||
|
||||
CheckUncommittedGitChanges();
|
||||
|
||||
foreach (string target in Targets)
|
||||
{
|
||||
string publishedFolder = Path.Combine(BinDistDirectory, target);
|
||||
string currentBinDistDirectory = publishedFolder;
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"# Packaging for platform '{target}' to folder:\t{currentBinDistDirectory}");
|
||||
|
||||
Console.WriteLine();
|
||||
if (!Directory.Exists(currentBinDistDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(currentBinDistDirectory);
|
||||
Console.WriteLine($"# Created {currentBinDistDirectory}");
|
||||
}
|
||||
|
||||
string buildInfoPath = Path.Combine(currentBinDistDirectory, "BUILDINFO.json");
|
||||
File.WriteAllText(buildInfoPath, buildInfoJson);
|
||||
|
||||
StartProcessAndWaitForExit("dotnet", DesktopProjectDirectory, arguments: "clean");
|
||||
|
||||
// See https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish for details.
|
||||
string dotnetProcessArgs = string.Join(
|
||||
" ",
|
||||
$"publish",
|
||||
$"--configuration Release",
|
||||
$"--force",
|
||||
$"--output \"{currentBinDistDirectory}\"",
|
||||
$"--self-contained true",
|
||||
$"--runtime \"{target}\"",
|
||||
$"--disable-parallel",
|
||||
$"--no-cache",
|
||||
$"--no-restore",
|
||||
$"/p:VersionPrefix={VersionPrefix}",
|
||||
$"/p:DebugType=none",
|
||||
$"/p:DebugSymbols=false",
|
||||
$"/p:ErrorReport=none",
|
||||
$"/p:DocumentationFile=\"\"",
|
||||
$"/p:Deterministic=true");
|
||||
|
||||
StartProcessAndWaitForExit(
|
||||
"dotnet",
|
||||
DesktopProjectDirectory,
|
||||
arguments: dotnetProcessArgs,
|
||||
redirectStandardOutput: true);
|
||||
|
||||
Tools.ClearSha512Tags(currentBinDistDirectory);
|
||||
|
||||
// Remove Tor binaries that are not relevant to the platform.
|
||||
var toNotRemove = "";
|
||||
if (target.StartsWith("win"))
|
||||
{
|
||||
toNotRemove = "win";
|
||||
}
|
||||
else if (target.StartsWith("linux"))
|
||||
{
|
||||
toNotRemove = "lin";
|
||||
}
|
||||
else if (target.StartsWith("osx"))
|
||||
{
|
||||
toNotRemove = "osx";
|
||||
}
|
||||
|
||||
// Remove binaries that are not relevant to the platform.
|
||||
var binaryFolder = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "Microservices", "Binaries"));
|
||||
|
||||
foreach (var dir in binaryFolder.EnumerateDirectories())
|
||||
{
|
||||
if (!dir.Name.Contains(toNotRemove, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await IoHelpers.TryDeleteDirectoryAsync(dir.FullName).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Rename WalletWasabi.Fluent.Desktop(.exe) -> wassabee(.exe).
|
||||
string executableExtension = target.StartsWith("win") ? ".exe" : "";
|
||||
string oldExecutablePath = Path.Combine(currentBinDistDirectory, $"WalletWasabi.Fluent.Desktop{executableExtension}");
|
||||
string newExecutablePath = Path.Combine(currentBinDistDirectory, $"{ExecutableName}{executableExtension}");
|
||||
File.Move(oldExecutablePath, newExecutablePath);
|
||||
|
||||
// Rename WalletWasabi.Daemon(.exe) -> wassabeed(.exe).
|
||||
oldExecutablePath = Path.Combine(currentBinDistDirectory, $"WalletWasabi.Daemon{executableExtension}");
|
||||
newExecutablePath = Path.Combine(currentBinDistDirectory, $"{DaemonExecutableName}{executableExtension}");
|
||||
File.Move(oldExecutablePath, newExecutablePath);
|
||||
|
||||
// Delete unused executables.
|
||||
File.Delete(Path.Combine(currentBinDistDirectory, $"WalletWasabi.Fluent{executableExtension}"));
|
||||
|
||||
// IF IT'S IN ONLYBINARIES MODE DON'T DO ANYTHING FANCY PACKAGING AFTER THIS!!!
|
||||
if (OnlyBinaries)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
long installedSizeKb = Tools.DirSize(new DirectoryInfo(publishedFolder)) / 1000;
|
||||
|
||||
if (target.StartsWith("win"))
|
||||
{
|
||||
ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{GetPackageTargetPostfix(target)}.zip"));
|
||||
|
||||
if (IsContinuousDelivery)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (target.StartsWith("osx"))
|
||||
{
|
||||
ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{GetPackageTargetPostfix(target)}.zip"));
|
||||
|
||||
if (IsContinuousDelivery)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only add postfix to the final package if arm64, otherwise nothing.
|
||||
var postfix = target.Contains("arm64") ? "-arm64" : "";
|
||||
|
||||
// After notarization this will be the filename of the dmg file.
|
||||
var zipFileName = $"WasabiToNotarize-{deterministicFileNameTag}{postfix}.zip";
|
||||
var zipFilePath = Path.Combine(BinDistDirectory, zipFileName);
|
||||
|
||||
ZipFile.CreateFromDirectory(currentBinDistDirectory, zipFilePath);
|
||||
|
||||
await IoHelpers.TryDeleteDirectoryAsync(currentBinDistDirectory).ConfigureAwait(false);
|
||||
Console.WriteLine($"# Deleted {currentBinDistDirectory}");
|
||||
|
||||
string drive = Tools.GetSingleUsbDrive();
|
||||
string targetFilePath = Path.Combine(drive, zipFileName);
|
||||
|
||||
try
|
||||
{
|
||||
File.Move(zipFilePath, targetFilePath, overwrite: true);
|
||||
Console.WriteLine($"# Moved '{zipFilePath}' unsigned zip file to the USB disk drive ('{targetFilePath}').");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"# There was an error during moving '{zipFilePath}' file to the USB disk drive ('{targetFilePath}'): '{ex.Message}'. Ignoring.");
|
||||
}
|
||||
}
|
||||
else if (target.StartsWith("linux"))
|
||||
{
|
||||
ZipFile.CreateFromDirectory(currentBinDistDirectory, Path.Combine(deliveryPath, $"Wasabi-{deterministicFileNameTag}-{GetPackageTargetPostfix(target)}.zip"));
|
||||
|
||||
if (IsContinuousDelivery)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine("# Create Linux .tar.gz");
|
||||
|
||||
if (!Directory.Exists(publishedFolder))
|
||||
{
|
||||
throw new Exception($"{publishedFolder} does not exist.");
|
||||
}
|
||||
|
||||
var newFolderName = $"Wasabi-{VersionPrefix}";
|
||||
var newFolderPath = Path.Combine(BinDistDirectory, newFolderName);
|
||||
|
||||
Console.WriteLine($"# Move '{publishedFolder}' to '{newFolderPath}'.");
|
||||
Directory.Move(publishedFolder, newFolderPath);
|
||||
publishedFolder = newFolderPath;
|
||||
string chmodExecutablesArgs = $$"""-type f \( -name '{{ExecutableName}}' -o -name '{{DaemonExecutableName}}' -o -name 'hwi' -o -name 'bitcoind' -o -name 'tor' \) -exec chmod +x {} \;""";
|
||||
|
||||
string[] commands = new string[]
|
||||
{
|
||||
$"sudo find ./{newFolderName} -type f -exec chmod 644 {{}} \\;",
|
||||
$"sudo find ./{newFolderName} {chmodExecutablesArgs}",
|
||||
$"tar -pczvf {newFolderName}.tar.gz {newFolderName}",
|
||||
};
|
||||
|
||||
ExecuteBashCommands(commands);
|
||||
|
||||
Console.WriteLine("# Create Linux .deb");
|
||||
|
||||
var debFolderRelativePath = "deb";
|
||||
var debFolderPath = Path.Combine(BinDistDirectory, debFolderRelativePath);
|
||||
var linuxUsrLocalBinFolder = "/usr/local/bin/";
|
||||
var debUsrLocalBinFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "local", "bin");
|
||||
var debUsrLocalBinFolderPath = Path.Combine(BinDistDirectory, debUsrLocalBinFolderRelativePath);
|
||||
Directory.CreateDirectory(debUsrLocalBinFolderPath);
|
||||
var debUsrAppFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "share", "applications");
|
||||
var debUsrAppFolderPath = Path.Combine(BinDistDirectory, debUsrAppFolderRelativePath);
|
||||
Directory.CreateDirectory(debUsrAppFolderPath);
|
||||
var debUsrShareIconsFolderRelativePath = Path.Combine(debFolderRelativePath, "usr", "share", "icons", "hicolor");
|
||||
var debUsrShareIconsFolderPath = Path.Combine(BinDistDirectory, debUsrShareIconsFolderRelativePath);
|
||||
var debianFolderRelativePath = Path.Combine(debFolderRelativePath, "DEBIAN");
|
||||
var debianFolderPath = Path.Combine(BinDistDirectory, debianFolderRelativePath);
|
||||
Directory.CreateDirectory(debianFolderPath);
|
||||
newFolderName = "wasabiwallet";
|
||||
var linuxWasabiWalletFolder = Tools.LinuxPathCombine(linuxUsrLocalBinFolder, newFolderName);
|
||||
var newFolderRelativePath = Path.Combine(debUsrLocalBinFolderRelativePath, newFolderName);
|
||||
newFolderPath = Path.Combine(BinDistDirectory, newFolderRelativePath);
|
||||
Directory.Move(publishedFolder, newFolderPath);
|
||||
|
||||
var assetsFolder = Path.Combine(DesktopProjectDirectory, "Assets");
|
||||
var assetsInfo = new DirectoryInfo(assetsFolder);
|
||||
|
||||
foreach (var file in assetsInfo.EnumerateFiles())
|
||||
{
|
||||
var number = file.Name.Split(new string[] { "WasabiLogo", ".png" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (number.Length == 1 && int.TryParse(number.First(), out int size))
|
||||
{
|
||||
string destinationFolder = Path.Combine(debUsrShareIconsFolderPath, $"{size}x{size}", "apps");
|
||||
Directory.CreateDirectory(destinationFolder);
|
||||
file.CopyTo(Path.Combine(destinationFolder, $"{ExecutableName}.png"));
|
||||
}
|
||||
}
|
||||
|
||||
var controlFilePath = Path.Combine(debianFolderPath, "control");
|
||||
|
||||
// License format does not yet work, but should work in the future, it's work in progress: https://bugs.launchpad.net/ubuntu/+source/software-center/+bug/435183
|
||||
var controlFileContent = $"Package: {ExecutableName}\n" +
|
||||
$"Priority: optional\n" +
|
||||
$"Section: utils\n" +
|
||||
$"Maintainer: zkSNACKs Ltd <info@zksnacks.com>\n" +
|
||||
$"Version: {VersionPrefix}\n" +
|
||||
$"Homepage: https://wasabiwallet.io\n" +
|
||||
$"Vcs-Git: git://github.com/WalletWasabi/WalletWasabi.git\n" +
|
||||
$"Vcs-Browser: https://github.com/WalletWasabi/WalletWasabi\n" +
|
||||
$"Architecture: amd64\n" +
|
||||
$"License: Open Source (MIT)\n" +
|
||||
$"Installed-Size: {installedSizeKb}\n" +
|
||||
$"Recommends: policykit-1\n" +
|
||||
$"Description: open-source, non-custodial, privacy focused Bitcoin wallet\n" +
|
||||
$" Built-in Tor, coinjoin, payjoin and coin control features.\n";
|
||||
|
||||
File.WriteAllText(controlFilePath, controlFileContent, Encoding.ASCII);
|
||||
|
||||
string postInstScriptContent = """
|
||||
#!/bin/sh
|
||||
/usr/local/bin/wasabiwallet/Microservices/Binaries/lin64/hwi installudevrules
|
||||
exit 0
|
||||
""".ReplaceLineEndings("\n");
|
||||
|
||||
string postInstScriptPath = Path.Combine(debianFolderPath, "postinst");
|
||||
File.WriteAllText(postInstScriptPath, postInstScriptContent, Encoding.ASCII);
|
||||
|
||||
var desktopFilePath = Path.Combine(debUsrAppFolderPath, $"{ExecutableName}.desktop");
|
||||
var desktopFileContent = $"[Desktop Entry]\n" +
|
||||
$"Type=Application\n" +
|
||||
$"Name=Wasabi Wallet\n" +
|
||||
$"StartupWMClass=Wasabi Wallet\n" +
|
||||
$"GenericName=Bitcoin Wallet\n" +
|
||||
$"Comment=Privacy focused Bitcoin wallet.\n" +
|
||||
$"Icon={ExecutableName}\n" +
|
||||
$"Terminal=false\n" +
|
||||
$"Exec={ExecutableName}\n" +
|
||||
$"Categories=Office;Finance;\n" +
|
||||
$"Keywords=bitcoin;wallet;crypto;blockchain;wasabi;privacy;anon;awesome;\n";
|
||||
|
||||
File.WriteAllText(desktopFilePath, desktopFileContent, Encoding.ASCII);
|
||||
|
||||
const string Shebang = "#!/usr/bin/env sh\n";
|
||||
var wasabiStarterScriptPath = Path.Combine(debUsrLocalBinFolderPath, $"{ExecutableName}");
|
||||
var wasabiStarterScriptContent = Shebang +
|
||||
$"{linuxWasabiWalletFolder.TrimEnd('/')}/{ExecutableName} $@\n";
|
||||
var wasabiDaemonStarterScriptPath = Path.Combine(debUsrLocalBinFolderPath, $"{DaemonExecutableName}");
|
||||
var wasabiDaemonStarterScriptContent = Shebang +
|
||||
$"{linuxWasabiWalletFolder.TrimEnd('/')}/{DaemonExecutableName} $@\n";
|
||||
|
||||
File.WriteAllText(wasabiStarterScriptPath, wasabiStarterScriptContent, Encoding.ASCII);
|
||||
File.WriteAllText(wasabiDaemonStarterScriptPath, wasabiDaemonStarterScriptContent, Encoding.ASCII);
|
||||
|
||||
string debDesktopFileLinuxPath = Tools.LinuxPathCombine(debUsrAppFolderRelativePath, $"{ExecutableName}.desktop");
|
||||
|
||||
commands = new string[]
|
||||
{
|
||||
$"sudo find {Tools.LinuxPath(newFolderRelativePath)} -type f -exec chmod 644 {{}} \\;",
|
||||
$"sudo find {Tools.LinuxPath(newFolderRelativePath)} {chmodExecutablesArgs}",
|
||||
$"sudo chmod -R 0775 {Tools.LinuxPath(debianFolderRelativePath)}",
|
||||
$"sudo chmod -R 0644 {debDesktopFileLinuxPath}",
|
||||
$"dpkg --build {Tools.LinuxPath(debFolderRelativePath)} $(pwd)"
|
||||
};
|
||||
|
||||
ExecuteBashCommands(commands);
|
||||
|
||||
await IoHelpers.TryDeleteDirectoryAsync(debFolderPath).ConfigureAwait(false);
|
||||
|
||||
string oldDeb = Path.Combine(BinDistDirectory, $"{ExecutableName}_{VersionPrefix}_amd64.deb");
|
||||
string newDeb = Path.Combine(BinDistDirectory, $"Wasabi-{VersionPrefix}.deb");
|
||||
File.Move(oldDeb, newDeb);
|
||||
|
||||
await IoHelpers.TryDeleteDirectoryAsync(publishedFolder).ConfigureAwait(false);
|
||||
Console.WriteLine($"# Deleted {publishedFolder}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Checks whether there are uncommitted changes.</summary>
|
||||
/// <remarks>This is important to really release a build that corresponds with a git hash.</remarks>
|
||||
private static void CheckUncommittedGitChanges()
|
||||
{
|
||||
if (TryStartProcessAndWaitForExit("git", workingDirectory: SolutionDirectory, out var gitStatus, arguments: "status --porcelain", redirectStandardOutput: true) && !string.IsNullOrEmpty(gitStatus))
|
||||
{
|
||||
Console.WriteLine("BEWARE: There are uncommitted changes in the repository. Do you want to continue? (Y/N)");
|
||||
int i = Console.Read();
|
||||
char ch = Convert.ToChar(i);
|
||||
|
||||
if (ch != 'y' && ch != 'Y')
|
||||
{
|
||||
Console.WriteLine("\nExiting.");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about .NET SDK and .NET runtime so that deterministic build is easier to reproduce.
|
||||
/// </summary>
|
||||
/// <returns>JSON string to write to a <c>BUILDINFO.json</c> file.</returns>
|
||||
private static string GetBuildInfoData()
|
||||
{
|
||||
// .NET runtime version. We rely on the fact that this version is the same as if we run "dotnet" command. This should be a safe assumption.
|
||||
Version runtimeVersion = Environment.Version;
|
||||
|
||||
// Get .NET SDK version.
|
||||
if (!TryStartProcessAndWaitForExit("dotnet", workingDirectory: SolutionDirectory, result: out var sdkVersion, arguments: "--version", redirectStandardOutput: true))
|
||||
{
|
||||
sdkVersion = "Failed to get .NET SDK version.";
|
||||
}
|
||||
|
||||
// Get git commit ID.
|
||||
if (!TryStartProcessAndWaitForExit("git", workingDirectory: SolutionDirectory, result: out var gitCommitId, arguments: "rev-parse HEAD", redirectStandardOutput: true))
|
||||
{
|
||||
gitCommitId = "Failed to get git commit ID.";
|
||||
}
|
||||
|
||||
return JsonSerializer.Serialize(new BuildInfo(runtimeVersion.ToString(), sdkVersion, gitCommitId), new JsonSerializerOptions() { WriteIndented = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a set of commands in either WSL2 (on Windows) or Bash (on other platforms).
|
||||
/// </summary>
|
||||
/// <param name="commands">Commands to execute.</param>
|
||||
private static void ExecuteBashCommands(string[] commands)
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
// Use WSL on Windows.
|
||||
string arguments = Tools.CreateWslCommand(BinDistDirectory, commands);
|
||||
StartProcessAndWaitForExit("wsl", BinDistDirectory, arguments: arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use Bash on other platforms.
|
||||
string arguments = string.Join(" && ", commands);
|
||||
StartProcessAndWaitForExit("bash", BinDistDirectory, arguments: $"-c \"{arguments}\"");
|
||||
}
|
||||
}
|
||||
|
||||
private static string? StartProcessAndWaitForExit(string command, string workingDirectory, string? writeToStandardInput = null, string? arguments = null, bool redirectStandardOutput = false)
|
||||
{
|
||||
var isWriteToStandardInput = !string.IsNullOrWhiteSpace(writeToStandardInput);
|
||||
|
||||
using var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = command,
|
||||
Arguments = arguments ?? "",
|
||||
RedirectStandardInput = isWriteToStandardInput,
|
||||
RedirectStandardOutput = redirectStandardOutput,
|
||||
WorkingDirectory = workingDirectory
|
||||
})
|
||||
?? throw new InvalidOperationException($"Process '{command}' is invalid.");
|
||||
|
||||
if (isWriteToStandardInput)
|
||||
{
|
||||
process.StandardInput.WriteLine(writeToStandardInput);
|
||||
}
|
||||
|
||||
string? output = null;
|
||||
|
||||
if (redirectStandardOutput)
|
||||
{
|
||||
output = process.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
if (process.ExitCode is not 0)
|
||||
{
|
||||
Console.WriteLine($"Process failed:");
|
||||
Console.WriteLine($"* Command: '{command} {arguments}'");
|
||||
Console.WriteLine($"* Working directory: '{workingDirectory}'");
|
||||
Console.WriteLine($"* Exit code: '{process.ExitCode}'");
|
||||
|
||||
if (redirectStandardOutput)
|
||||
{
|
||||
string prettyPrint = string.Join(Environment.NewLine, (output ?? "").Split(Environment.NewLine).Select(line => $" > {line}"));
|
||||
Console.WriteLine($"* Output:\n{prettyPrint}");
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Process exited with unexpected exit code");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static bool TryStartProcessAndWaitForExit(string command, string workingDirectory, [NotNullWhen(true)] out string? result, string? writeToStandardInput = null, string? arguments = null, bool redirectStandardOutput = false)
|
||||
{
|
||||
result = null;
|
||||
|
||||
try
|
||||
{
|
||||
result = StartProcessAndWaitForExit(command, workingDirectory, writeToStandardInput, arguments, redirectStandardOutput)?.Trim() ?? "";
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"# Process failed: '{ex}'.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static string GetPackageTargetPostfix(string target)
|
||||
{
|
||||
if (target.StartsWith("osx"))
|
||||
{
|
||||
return target.Replace("osx", "macOS");
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WalletWasabi.Packager;
|
||||
|
||||
public static class Tools
|
||||
{
|
||||
public static void ClearSha512Tags(string pathToSearch)
|
||||
{
|
||||
var files = Directory.GetFiles(pathToSearch, "*.deps.json"); // https://natemcmaster.com/blog/2017/12/21/netcore-primitives/
|
||||
if (files is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var depsFilePath in files)
|
||||
{
|
||||
var lines = File.ReadAllLines(depsFilePath);
|
||||
|
||||
List<string> outLines = new();
|
||||
foreach (var line in lines)
|
||||
{
|
||||
// "sha512": "sha512-B0BYh5Fpeqp4GIbL5wEhde6M/dZ+s0tlXM0qMTvj4mTg9Rr4svVHGpn6dDp8pT2sB88ghxyLIpKGdx9Oj7f/pw==",
|
||||
if (line.Contains("\"sha512\": \"sha512-"))
|
||||
{
|
||||
// "sha512": "",
|
||||
var lineToAdd = " \"sha512\": \"\"";
|
||||
if (line.EndsWith(','))
|
||||
{
|
||||
lineToAdd += ',';
|
||||
}
|
||||
|
||||
outLines.Add(lineToAdd);
|
||||
}
|
||||
else
|
||||
{
|
||||
outLines.Add(line);
|
||||
}
|
||||
}
|
||||
File.Delete(depsFilePath);
|
||||
File.WriteAllLines(depsFilePath, outLines);
|
||||
}
|
||||
}
|
||||
|
||||
public static string LinuxPathCombine(params string[] paths)
|
||||
{
|
||||
return LinuxPath(Path.Combine(paths));
|
||||
}
|
||||
|
||||
public static string LinuxPath(string path)
|
||||
{
|
||||
return path.Replace(@"\", @"/");
|
||||
}
|
||||
|
||||
/// <summary>Converts a Windows path to a WSL path.</summary>
|
||||
/// <param name="windowsPath">Full Windows path (e.g. <c>C:\something\something</c>).</param>
|
||||
/// <param name="driveLetterUpper">Output parameter with capital drive letter of <paramref name="windowsPath"/>.</param>
|
||||
/// <returns>WSL path corresponding with <paramref name="windowsPath"/> (e.g. <c>/mnt/c/something/something</c>).</returns>
|
||||
/// <remarks>Supports both WSL 1 and WSL 2.</remarks>
|
||||
public static string Win2WslPath(string windowsPath, out char driveLetterUpper)
|
||||
{
|
||||
driveLetterUpper = char.ToUpper(windowsPath[0]);
|
||||
return $"/mnt/{char.ToLower(driveLetterUpper)}/{LinuxPath(windowsPath[3..])}";
|
||||
}
|
||||
|
||||
/// <summary>Builds a WSL command from <paramref name="commands"/> in a way that <c>chmod</c> command works in WSL (not true by default).</summary>
|
||||
/// <param name="windowsWorkingDirectory">Working directory where to run <paramref name="commands"/> as a Windows full path.</param>
|
||||
/// <param name="commands">Linux commands to execute in WSL folder corresponding to <paramref name="windowsWorkingDirectory"/>.</param>
|
||||
public static string CreateWslCommand(string windowsWorkingDirectory, params string[] commands)
|
||||
{
|
||||
string wslPath = Win2WslPath(windowsWorkingDirectory, out char driveLetterUpper);
|
||||
char driveLetterLower = char.ToLower(driveLetterUpper);
|
||||
|
||||
string[] allCommands = new string[]
|
||||
{
|
||||
$"cd /",
|
||||
$"sudo umount -l /mnt/{driveLetterLower}",
|
||||
$"sudo mount -t drvfs {driveLetterUpper}: /mnt/{driveLetterLower} -o metadata",
|
||||
$"cd {wslPath}",
|
||||
}.Concat(commands).ToArray();
|
||||
|
||||
return string.Join(" && ", allCommands);
|
||||
}
|
||||
|
||||
public static long DirSize(DirectoryInfo d)
|
||||
{
|
||||
long size = 0;
|
||||
|
||||
// Add file sizes.
|
||||
FileInfo[] fis = d.GetFiles();
|
||||
foreach (FileInfo fi in fis)
|
||||
{
|
||||
size += fi.Length;
|
||||
}
|
||||
|
||||
// Add subdirectory sizes.
|
||||
DirectoryInfo[] dis = d.GetDirectories();
|
||||
foreach (DirectoryInfo di in dis)
|
||||
{
|
||||
size += DirSize(di);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static string GetSingleUsbDrive()
|
||||
{
|
||||
IEnumerable<DriveInfo> driveList;
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
driveList = DriveInfo.GetDrives().Where(d => d.Name.Contains("USB")).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
driveList = DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Removable);
|
||||
}
|
||||
|
||||
return driveList.Single().Name;
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<DisableImplicitNamespaceImports>true</DisableImplicitNamespaceImports>
|
||||
<NoWarn>1701;1702;1705;1591;1573;CA1031;CA1822</NoWarn>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64;osx-arm64;</RuntimeIdentifiers>
|
||||
<PathMap>$(MSBuildProjectDirectory)\=WalletWasabi.Packager</PathMap>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DocumentationFile>bin\Debug\net8.0\WalletWasabi.Packager.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DocumentationFile></DocumentationFile>
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<ErrorReport>none</ErrorReport>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WalletWasabi\WalletWasabi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,422 +0,0 @@
|
|||
{
|
||||
"version": 2,
|
||||
"dependencies": {
|
||||
"net8.0": {
|
||||
"Microsoft.CodeAnalysis.BannedApiAnalyzers": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.3.4, )",
|
||||
"resolved": "3.3.4",
|
||||
"contentHash": "0k2Jwpc8eq0hjOtX6TxRkHm9clkJ2PAQ3heEHgqIJZcsfdFosC/iyz18nsgTVDDWpID80rC7aiYK7ripx+Qndg=="
|
||||
},
|
||||
"LinqKit.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.5",
|
||||
"contentHash": "+5UKyagtVX33TSeOGorYzDXus/ypAISfM7HFfrix4BEmuuGF+nhSjf8P9csejLQ79ny5ms33M5/lQ2SkwC0Jxw=="
|
||||
},
|
||||
"Microsoft.Bcl.AsyncInterfaces": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg=="
|
||||
},
|
||||
"Microsoft.Data.Sqlite.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "pujbzfszX7jAl7oTbHhqx7pxd9jibeyHHl8zy1gd55XMaKWjDtc5XhhNYwQnrwWYCInNdVoArbaaAvLgW7TwuA==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.6"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Configuration.Binder": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "8.0.0",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Options": "8.0.0",
|
||||
"System.Diagnostics.DiagnosticSource": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection": "8.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Options": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Configuration.Binder": "8.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Options": "8.0.0",
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
|
||||
},
|
||||
"Microsoft.Net.Http.Headers": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "YlHqL8oWBX3H1LmdKUOxEMW8cVD8nUACEnE2Fu3Ze4k7mYf8yJ1o/uLqoequQV0GDupXyCBEzYhn7Zxdz7pqYQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"NBitcoin.Secp256k1": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.4",
|
||||
"contentHash": "23N1DCusSRCx1hoNiIMl3JnMZrdY78a/WcsiN1LIAg6sq8MiC7mszDiUgHKD6txm+m9PxJBigBLH7MPBQCRCDQ=="
|
||||
},
|
||||
"Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "13.0.1",
|
||||
"contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
|
||||
},
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "BmAf6XWt4TqtowmiWe4/5rRot6GerAeklmOPfviOvwLoF5WwgxcJHAxZtySuyW9r9w+HLILnm8VfJFLCUJYW8A==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": "2.1.6",
|
||||
"SQLitePCLRaw.provider.e_sqlite3": "2.1.6"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "wO6v9GeMx9CUngAet8hbO7xdm+M42p1XeJq47ogyRoYSvNSp0NGLI+MgC0bhrMk9C17MTVFlLiN6ylyExLCc5w==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3"
|
||||
}
|
||||
},
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
|
||||
},
|
||||
"SQLitePCLRaw.provider.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "PQ2Oq3yepLY4P7ll145P3xtx2bX8xF4PzaKPRpw9jZlKvfe4LE/saAV82inND9usn1XRpmxXk7Lal3MTI+6CNg==",
|
||||
"dependencies": {
|
||||
"SQLitePCLRaw.core": "2.1.6"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.DiagnosticSource": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
|
||||
},
|
||||
"System.Interactive.Async": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.1",
|
||||
"contentHash": "f8H1O4ZWDQo344y5NQU76G4SIjWMuKDVXL9OM1dg6K5YZnLkc8iCdQDybBvMcC6ufk61jzXGVAX6UCDu0qDSjA==",
|
||||
"dependencies": {
|
||||
"System.Linq.Async": "6.0.1"
|
||||
}
|
||||
},
|
||||
"System.Linq.Async": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.1",
|
||||
"contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Bcl.AsyncInterfaces": "6.0.0"
|
||||
}
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.3",
|
||||
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
|
||||
},
|
||||
"System.Threading.Channels": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "CMaFr7v+57RW7uZfZkPExsPB6ljwzhjACWW1gfU35Y56rk72B/Wu+sTqxVmGSk4SFUlPc3cjeKND0zktziyjBA=="
|
||||
},
|
||||
"walletwasabi": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNetCore.WebUtilities": "[8.0.0, )",
|
||||
"Microsoft.Data.Sqlite": "[8.0.0, )",
|
||||
"Microsoft.Extensions.Caching.Abstractions": "[8.0.0, )",
|
||||
"Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )",
|
||||
"Microsoft.Extensions.Http": "[8.0.0, )",
|
||||
"Microsoft.Win32.SystemEvents": "[8.0.0, )",
|
||||
"NBitcoin": "[7.0.27, )",
|
||||
"NNostr.Client": "[0.0.49, )",
|
||||
"System.IO.Pipelines": "[8.0.0, )",
|
||||
"System.Text.Json": "[8.0.4, )",
|
||||
"WabiSabi": "[1.0.1.2, )"
|
||||
}
|
||||
},
|
||||
"Microsoft.AspNetCore.WebUtilities": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "z1SXKg5Bk02VmrrOab1TO2yxkZIfL4RyrS+yCpwxcLTqJwImYhEttz3LYbl1gQebkAAvx2Fm4NVXmopxXeLZgw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Net.Http.Headers": "8.0.0",
|
||||
"System.IO.Pipelines": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Data.Sqlite": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "H+iC5IvkCCKSNHXzL3JARvDn7VpkvuJM91KVB89sKjeTF/KX/BocNNh93ZJtX5MCQKb/z4yVKgkU2sVIq+xKfg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.Sqlite.Core": "8.0.0",
|
||||
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.6"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Caching.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Hosting.Abstractions": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Diagnostics": "8.0.0",
|
||||
"Microsoft.Extensions.Logging": "8.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
|
||||
"Microsoft.Extensions.Options": "8.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "9opKRyOKMCi2xJ7Bj7kxtZ1r9vbzosMvRrdEhVhDz8j8MoBGgB+WmC94yH839NPH+BclAjtQ/pyagvi/8gDLkw=="
|
||||
},
|
||||
"NBitcoin": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[7.0.27, )",
|
||||
"resolved": "7.0.27",
|
||||
"contentHash": "n2eHYJf0YVOf3ld0fhQJ8qR8TDvGZObGseOf5gHx03QpG+lq5L5qJAn5SA+MvZQLKcqhEUJ+S2AKvWkgZYS4Gw==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Logging.Abstractions": "1.0.0",
|
||||
"Newtonsoft.Json": "13.0.1"
|
||||
}
|
||||
},
|
||||
"NNostr.Client": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[0.0.49, )",
|
||||
"resolved": "0.0.49",
|
||||
"contentHash": "UqmOBSCuUxw6qTk5+3TTWWtlyetx1btEuBJIS9beidviV45iMjlgOMK0ThB1CrYuPfg4DDzMu5rpzRYnM8eHWA==",
|
||||
"dependencies": {
|
||||
"LinqKit.Core": "1.2.5",
|
||||
"NBitcoin.Secp256k1": "3.1.4",
|
||||
"System.Interactive.Async": "6.0.1",
|
||||
"System.Text.Json": "8.0.3",
|
||||
"System.Threading.Channels": "8.0.0"
|
||||
}
|
||||
},
|
||||
"System.IO.Pipelines": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
|
||||
},
|
||||
"System.Text.Json": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.4, )",
|
||||
"resolved": "8.0.4",
|
||||
"contentHash": "bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==",
|
||||
"dependencies": {
|
||||
"System.Text.Encodings.Web": "8.0.0"
|
||||
}
|
||||
},
|
||||
"WabiSabi": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[1.0.1.2, )",
|
||||
"resolved": "1.0.1.2",
|
||||
"contentHash": "e+pMZGVEfWQvkpZHAydGv6grY71urfO47lodjXC9eWtfSFvNtPWjrgqck9O24yIbXhP4K3QrJKzJQFGpAp8rqg==",
|
||||
"dependencies": {
|
||||
"NBitcoin.Secp256k1": "3.1.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"net8.0/linux-x64": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "9opKRyOKMCi2xJ7Bj7kxtZ1r9vbzosMvRrdEhVhDz8j8MoBGgB+WmC94yH839NPH+BclAjtQ/pyagvi/8gDLkw=="
|
||||
}
|
||||
},
|
||||
"net8.0/osx-arm64": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "9opKRyOKMCi2xJ7Bj7kxtZ1r9vbzosMvRrdEhVhDz8j8MoBGgB+WmC94yH839NPH+BclAjtQ/pyagvi/8gDLkw=="
|
||||
}
|
||||
},
|
||||
"net8.0/osx-x64": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "9opKRyOKMCi2xJ7Bj7kxtZ1r9vbzosMvRrdEhVhDz8j8MoBGgB+WmC94yH839NPH+BclAjtQ/pyagvi/8gDLkw=="
|
||||
}
|
||||
},
|
||||
"net8.0/win-x64": {
|
||||
"SQLitePCLRaw.lib.e_sqlite3": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.6",
|
||||
"contentHash": "2ObJJLkIUIxRpOUlZNGuD4rICpBnrBR5anjyfUFQep4hMOIeqW+XGQYzrNmHSVz5xSWZ3klSbh7sFR6UyDj68Q=="
|
||||
},
|
||||
"System.Text.Encodings.Web": {
|
||||
"type": "Transitive",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ=="
|
||||
},
|
||||
"Microsoft.Win32.SystemEvents": {
|
||||
"type": "CentralTransitive",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "9opKRyOKMCi2xJ7Bj7kxtZ1r9vbzosMvRrdEhVhDz8j8MoBGgB+WmC94yH839NPH+BclAjtQ/pyagvi/8gDLkw=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Двоичные данные
WalletWasabi.Packager/scripts/WasabiNoratize.scpt
Двоичные данные
WalletWasabi.Packager/scripts/WasabiNoratize.scpt
Двоичный файл не отображается.
|
@ -1,25 +0,0 @@
|
|||
# If you are not allowed to run this script, run the following command in your PowerShell console:
|
||||
# Set-ExecutionPolicy RemoteSigned
|
||||
|
||||
$host.UI.RawUI.ForegroundColor = "Green"
|
||||
$host.UI.RawUI.BackgroundColor = "Black"
|
||||
Read-Host -Prompt 'Releasing Wasabi Wallet - Insert a pendrive to store macOS notarization candidate files [Press ENTER]'
|
||||
Read-Host -Prompt 'Start Kleopatra!'
|
||||
|
||||
cd $env:userprofile\desktop/WalletWasabi/WalletWasabi.Packager
|
||||
dotnet run -- publish
|
||||
|
||||
$host.UI.RawUI.ForegroundColor = "Green"
|
||||
$host.UI.RawUI.BackgroundColor = "Black"
|
||||
Read-Host -Prompt 'Remove and plug the pendrive to macOS and run the packager to notarize the files.'
|
||||
|
||||
$arguments = $env:userprofile + '\Desktop\WalletWasabi\WalletWasabi.WindowsInstaller\WalletWasabi.WindowsInstaller.wixproj /Build "Release|x64"'
|
||||
Start-Process -FilePath 'C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.com' -ArgumentList $arguments # If -Wait -NoNewWindow added devenv will hang forever at the end of the build.
|
||||
|
||||
$host.UI.RawUI.ForegroundColor = "Green"
|
||||
$host.UI.RawUI.BackgroundColor = "Black"
|
||||
Read-Host -Prompt 'Wait until WiX building the MSI installer, then [Press ENTER]'
|
||||
Read-Host -Prompt 'Wait until macOS notarization is done and insert the pendrive to this PC [Press ENTER]'
|
||||
dotnet run -- sign
|
||||
|
||||
Read-Host -Prompt 'Release finished [Press ENTER]'
|
|
@ -1,22 +0,0 @@
|
|||
using WalletWasabi.Packager;
|
||||
using Xunit;
|
||||
|
||||
namespace WalletWasabi.Tests.UnitTests.Packager;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="ArgsProcessor"/> class.
|
||||
/// </summary>
|
||||
public class ArgsProcessorTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(new string[] { "-onlybinaries" }, true)]
|
||||
[InlineData(new string[] { "-onlyBinaries" }, true)]
|
||||
[InlineData(new string[] { "-OnlyBinaries" }, true)]
|
||||
[InlineData(new string[] { "---OnlyBinaries" }, true)]
|
||||
[InlineData(new string[] { "---0nlyBinaries" }, false)]
|
||||
public void IsOnlyBinariesModeTest(string[] input, bool expectedResult)
|
||||
{
|
||||
var argsProcessor = new ArgsProcessor(input);
|
||||
Assert.Equal(expectedResult, argsProcessor.IsOnlyBinariesMode());
|
||||
}
|
||||
}
|
|
@ -36,7 +36,6 @@
|
|||
<ProjectReference Include="..\WalletWasabi.Backend\WalletWasabi.Backend.csproj" />
|
||||
<ProjectReference Include="..\WalletWasabi.Fluent.Generators\WalletWasabi.Fluent.Generators.csproj" />
|
||||
<ProjectReference Include="..\WalletWasabi.Fluent\WalletWasabi.Fluent.csproj" />
|
||||
<ProjectReference Include="..\WalletWasabi.Packager\WalletWasabi.Packager.csproj" />
|
||||
<ProjectReference Include="..\WalletWasabi\WalletWasabi.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
flake.nix = flake.nix
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WalletWasabi.Packager", "WalletWasabi.Packager\WalletWasabi.Packager.csproj", "{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}"
|
||||
EndProject
|
||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "WalletWasabi.WindowsInstaller", "WalletWasabi.WindowsInstaller\WalletWasabi.WindowsInstaller.wixproj", "{54654468-4F58-4253-84BD-6F53A8D3D2C4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WalletWasabi.Fluent.Desktop", "WalletWasabi.Fluent.Desktop\WalletWasabi.Fluent.Desktop.csproj", "{177A8AC0-7879-4719-A8A9-49E1D75B3A2B}"
|
||||
|
@ -71,14 +69,6 @@ Global
|
|||
{526AC796-6CC0-4ADA-9A7E-C12267719A1A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{526AC796-6CC0-4ADA-9A7E-C12267719A1A}.Release|x64.ActiveCfg = Debug|Any CPU
|
||||
{526AC796-6CC0-4ADA-9A7E-C12267719A1A}.Release|x64.Build.0 = Debug|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Release|x64.ActiveCfg = Debug|Any CPU
|
||||
{8BE916A0-1F3F-4757-BAD9-BFBAB8EAC3C2}.Release|x64.Build.0 = Debug|Any CPU
|
||||
{54654468-4F58-4253-84BD-6F53A8D3D2C4}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{54654468-4F58-4253-84BD-6F53A8D3D2C4}.Debug|x64.ActiveCfg = Release|x64
|
||||
{54654468-4F58-4253-84BD-6F53A8D3D2C4}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
|
|
|
@ -80,7 +80,7 @@ public class TerminateService
|
|||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
// This event will only be triggered if you run Wasabi from the published package. Use the packager with the --OnlyBinaries option.
|
||||
// This event will only be triggered if you run Wasabi from the published package.
|
||||
Logger.LogInfo($"Process termination was requested by the OS, reason '{e.Reason}'.");
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче