/// <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; } // 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 Main(string[] args) { // Only binaries mode is for deterministic builds. OnlyBinaries = IsOnlyBinariesMode(args); ReportStatus(); if (DoPublish || OnlyBinaries) { Publish(); if (OnlyBinaries) { IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); } } if (DoSign && !OnlyBinaries) { Sign(); } if (DoRestoreProgramCs && !OnlyBinaries) { RestoreProgramCs(); } }
private static void Main(string[] args) { // Start with digest creation and return if only digest creation. CreateDigests(); OnlyCreateDigests = IsOnlyCreateDigestsMode(args); if (OnlyCreateDigests) { return; } // Only binaries mode is for deterministic builds. OnlyBinaries = IsOnlyBinariesMode(args); ReportStatus(); if (DoPublish || OnlyBinaries) { Publish(); if (OnlyBinaries) { IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); } } if (DoSign && !OnlyBinaries) { Sign(); } if (DoRestoreProgramCs && !OnlyBinaries) { RestoreProgramCs(); } }
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(); return; } // If I want a list of up to date onions run it with '--getonions'. if (argsProcessor.IsGetOnionsMode()) { var api = new BitnodesApi(Console.Out); await api.PrintOnionsAsync(); return; } // If I want a list of up to date onions run it with '--reduceonions'. if (argsProcessor.IsReduceOnionsMode()) { string onionFilePath = Path.Combine(LibraryProjectDirectory, "Tor", "OnionSeeds", "MainOnionSeeds.txt"); var currentOnions = File.ReadAllLines(onionFilePath).ToHashSet(); var api = new BitnodesApi(Console.Out); await api.PrintOnionsAsync(currentOnions); return; } // Only binaries mode is for deterministic builds. OnlyBinaries = argsProcessor.IsOnlyBinariesMode(); IsContinuousDelivery = argsProcessor.IsContinuousDeliveryMode(); ReportStatus(); if (DoPublish || OnlyBinaries) { Publish(); IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); } if (!OnlyBinaries) { if (DoSign) { Sign(); } if (DoRestoreProgramCs) { RestoreProgramCs(); } } }
private static void Main(string[] args) { if (MacSignTools.IsMacSignMode()) { MacSignTools.Sign(); return; } // If I want a list of up to date onions run it with '--getonions'. if (IsGetOnionsMode(args)) { GetOnions(); return; } // If I want a list of up to date onions run it with '--getonions'. if (IsReduceOnionsMode(args)) { ReduceOnions(); return; } // Start with digest creation and return if only digest creation. CreateDigests(); OnlyCreateDigests = IsOnlyCreateDigestsMode(args); if (OnlyCreateDigests) { return; } // Only binaries mode is for deterministic builds. OnlyBinaries = IsOnlyBinariesMode(args); ReportStatus(); if (DoPublish || OnlyBinaries) { Publish(); IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); } if (!OnlyBinaries) { if (DoSign) { Sign(); } if (DoRestoreProgramCs) { RestoreProgramCs(); } } }
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"); if (!File.Exists(msiPath)) { throw new Exception(".msi does not exist. Expected path: Wasabi.msi."); } var msiFileName = Path.GetFileNameWithoutExtension(msiPath); var newMsiPath = Path.Combine(BinDistDirectory, $"{msiFileName}-{VersionPrefix}.msi"); File.Copy(msiPath, newMsiPath); Console.Write("Enter Code Signing Certificate Password: "******"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 dmgFilePath = Path.Combine(BinDistDirectory, $"Wasabi-{VersionPrefix}.dmg"); if (!File.Exists(dmgFilePath)) { throw new Exception(".dmg does not exist."); } string zipFilePath = Path.Combine(BinDistDirectory, $"Wasabi-osx-{VersionPrefix}.zip"); if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } } } Console.WriteLine("Signing final files..."); var finalFiles = Directory.GetFiles(BinDistDirectory); foreach (var finalFile in finalFiles) { StartProcessAndWaitForExit("cmd", BinDistDirectory, $"gpg --armor --detach-sign {finalFile} && exit"); StartProcessAndWaitForExit("cmd", WixProjectDirectory, $"git checkout -- ComponentsGenerated.wxs && exit"); } IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); }
public HomePageViewModel(IScreen screen, WalletManagerViewModel walletManager, AddWalletPageViewModel addWalletPage) : base(screen) { Title = "Home"; var list = new SourceList <NavBarItemViewModel>(); list.Add(addWalletPage); walletManager.Items.ToObservableChangeSet() .Cast(x => x as NavBarItemViewModel) .Sort(SortExpressionComparer <NavBarItemViewModel> .Ascending(i => i.Title)) .Merge(list.Connect()) .ObserveOn(RxApp.MainThreadScheduler) .Bind(out _items) .AsObservableList(); OpenWalletsFolderCommand = ReactiveCommand.Create(() => IoHelpers.OpenFolderInFileExplorer(walletManager.Model.WalletDirectories.WalletsDir)); }
/// <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(); return; } // Only binaries mode is for deterministic builds. OnlyBinaries = argsProcessor.IsOnlyBinariesMode(); IsContinuousDelivery = argsProcessor.IsContinuousDeliveryMode(); ReportStatus(); if (DoPublish || OnlyBinaries) { await PublishAsync().ConfigureAwait(false); IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); } #pragma warning disable CS0162 // Unreachable code detected if (!OnlyBinaries) { if (DoSign) { await SignAsync().ConfigureAwait(false); } if (DoRestoreProgramCs) { RestoreProgramCs(); } } #pragma warning restore CS0162 // Unreachable code detected }
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(); return; } // Only binaries mode is for deterministic builds. OnlyBinaries = argsProcessor.IsOnlyBinariesMode(); IsContinuousDelivery = argsProcessor.IsContinuousDeliveryMode(); ReportStatus(); if (DoPublish || OnlyBinaries) { Publish(); IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); } if (!OnlyBinaries) { if (DoSign) { Sign(); } if (DoRestoreProgramCs) { RestoreProgramCs(); } } }
public OpenWalletsFolderViewModel(string walletDir) { TargetCommand = ReactiveCommand.Create( () => IoHelpers.OpenFolderInFileExplorer(walletDir)); }
private static void Main(string[] args) { // 0. Dump Client version (or else wrong .msi will be created) - Helpers.Constants.ClientVersion // 1. Publish with Packager. // 2. Build WIX project with Release and x64 configuration. // 3. Sign with Packager. bool doPublish = true; bool doSign = false; string packagerProjectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\")); string solutionDirectory = Path.GetFullPath(Path.Combine(packagerProjectDirectory, "..\\")); string guiProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.Gui\\")); string libraryProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi\\")); string wixProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.WindowsInstaller\\")); string binDistDirectory = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\dist")); Console.WriteLine($"{nameof(solutionDirectory)}:\t\t{solutionDirectory}"); Console.WriteLine($"{nameof(packagerProjectDirectory)}:\t{packagerProjectDirectory}"); Console.WriteLine($"{nameof(guiProjectDirectory)}:\t\t{guiProjectDirectory}"); Console.WriteLine($"{nameof(libraryProjectDirectory)}:\t\t{libraryProjectDirectory}"); Console.WriteLine($"{nameof(wixProjectDirectory)}:\t\t{wixProjectDirectory}"); Console.WriteLine($"{nameof(binDistDirectory)}:\t\t{binDistDirectory}"); string versionPrefix = Helpers.Constants.ClientVersion.ToString(); string executableName = "wassabee"; Console.WriteLine(); Console.WriteLine($"{nameof(versionPrefix)}:\t\t\t{versionPrefix}"); Console.WriteLine($"{nameof(executableName)}:\t\t\t{executableName}"); // https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog // BOTTLENECKS: // Tor - win-32, linux-32, osx-64 // .NET Core - win-32, linux-64, osx-64 // Avalonia - win7-32, linux-64, osx-64 // We'll only support x64, if someone complains, we can come back to it. // For 32 bit Windows there needs to be a lot of WIX configuration to be done. var targets = new List <string> { "win7-x64", "linux-x64", "osx-x64" }; Console.WriteLine(); Console.Write($"{nameof(targets)}:\t\t\t"); targets.ForEach(x => { if (targets.Last() != x) { Console.Write($"{x}, "); } else { Console.Write(x); } }); Console.WriteLine(); if (doPublish) { if (Directory.Exists(binDistDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(binDistDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {binDistDirectory}"); } var psiBuild = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = guiProjectDirectory }; var pBuild = Process.Start(psiBuild); pBuild.StandardInput.WriteLine("dotnet clean --configuration Release && exit"); pBuild.WaitForExit(); var guiBinReleaseDirectory = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\Release")); var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(libraryProjectDirectory, "bin\\Release")); if (Directory.Exists(guiBinReleaseDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {guiBinReleaseDirectory}"); } if (Directory.Exists(libraryBinReleaseDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {libraryBinReleaseDirectory}"); } foreach (string target in targets) { string currentBinDistDirectory = Path.GetFullPath(Path.Combine(binDistDirectory, target)); Console.WriteLine(); Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}"); Console.WriteLine(); if (!Directory.Exists(currentBinDistDirectory)) { Directory.CreateDirectory(currentBinDistDirectory); Console.WriteLine($"Created {currentBinDistDirectory}"); } // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21 // -c|--configuration {Debug|Release} // Defines the build configuration. The default value is Debug. // --force // Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file. // -o|--output <OUTPUT_DIRECTORY> // Specifies the path for the output directory. // If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or // ./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment. // If the path is relative, the output directory generated is relative to the project file location, not to the current working directory. // --self-contained // Publishes the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine. // If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment. // -r|--runtime <RUNTIME_IDENTIFIER> // Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD). // For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD). // --version-suffix <VERSION_SUFFIX> // Defines the version suffix to replace the asterisk (*) in the version field of the project file. // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x // --disable-parallel // Disables restoring multiple projects in parallel. // --no-cache // Specifies to not cache packages and HTTP requests. // https://github.com/dotnet/docs/issues/7568 // /p:Version=1.2.3.4 // "dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4 var psiPublish = new ProcessStartInfo { FileName = "dotnet", Arguments = $"publish --configuration Release --force --output {currentBinDistDirectory} --self-contained true --runtime {target} /p:VersionPrefix={versionPrefix} --disable-parallel --no-cache", WorkingDirectory = guiProjectDirectory }; var pPublish = Process.Start(psiPublish); pPublish.WaitForExit(); // Rename the final exe. string oldExecutablePath; string newExecutablePath; if (target.StartsWith("win")) { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe"); newExecutablePath = Path.Combine(currentBinDistDirectory, $"{executableName}.exe"); } else // Linux & OSX { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui"); newExecutablePath = Path.Combine(currentBinDistDirectory, executableName); } File.Move(oldExecutablePath, newExecutablePath); if (target.StartsWith("win")) { var psiEditbin = new ProcessStartInfo { FileName = "editbin", Arguments = $"\"{newExecutablePath}\" /SUBSYSTEM:WINDOWS", WorkingDirectory = currentBinDistDirectory }; var pEditbin = Process.Start(psiEditbin); pEditbin.WaitForExit(); var icoPath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.ico"); var psiRcedit = new ProcessStartInfo { FileName = "rcedit", Arguments = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{versionPrefix}\" --set-product-version \"{versionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"", WorkingDirectory = currentBinDistDirectory }; var pRcedit = Process.Start(psiRcedit); pRcedit.WaitForExit(); } } } if (doSign is true) { foreach (string target in targets) { var publishedFolder = Path.Combine(binDistDirectory, $"{target}"); if (target.StartsWith("win", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("Move created .msi"); var msiPath = Path.Combine(wixProjectDirectory, @"bin\Release\WasabiInstaller.msi"); if (!File.Exists(msiPath)) { throw new Exception(".msi doesn't exist. Expected path: WasabiInstaller.msi."); } var msiFileName = Path.GetFileName(msiPath); var newMsiPath = Path.Combine(binDistDirectory, msiFileName); File.Move(msiPath, newMsiPath); } else if (target.StartsWith("linux", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("Create Linux .tar.gz"); if (!Directory.Exists(publishedFolder)) { throw new Exception($"{publishedFolder} doesn't exist."); } var newFolderName = "WasabiLinux"; var newFolderPath = Path.Combine(binDistDirectory, newFolderName); Directory.Move(publishedFolder, newFolderPath); publishedFolder = newFolderPath; var psiTar = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; var tarProcess = Process.Start(psiTar); tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit"); tarProcess.WaitForExit(); } else // if (target.StartsWith("osx", StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("Create OSX .tar.gz"); if (!Directory.Exists(publishedFolder)) { throw new Exception($"{publishedFolder} doesn't exist."); } var newFolderName = "WasabiOsx"; var newFolderPath = Path.Combine(binDistDirectory, newFolderName); Directory.Move(publishedFolder, newFolderPath); publishedFolder = newFolderPath; var psiTar = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; var tarProcess = Process.Start(psiTar); tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit"); tarProcess.WaitForExit(); } if (Directory.Exists(publishedFolder)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } } Console.WriteLine("Signing final files..."); var finalFiles = Directory.GetFiles(binDistDirectory); foreach (var finalFile in finalFiles) { var psiSignProcess = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; var signProcess = Process.Start(psiSignProcess); signProcess.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit"); signProcess.WaitForExit(); var psiRestoreHeat = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = wixProjectDirectory }; var restoreHeatProcess = Process.Start(psiRestoreHeat); restoreHeatProcess.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit"); restoreHeatProcess.WaitForExit(); } IoHelpers.OpenFolderInFileExplorer(binDistDirectory); } Console.WriteLine(); Console.WriteLine("FINISHED! Press key to exit..."); Console.ReadKey(); }
private static void Main(string[] args) { // 0. Dump Client version (or else wrong .msi will be created) - Helpers.Constants.ClientVersion // 1. Publish with Packager. // 2. Build WIX project with Release and x64 configuration. // 3. Sign with Packager, set restore true so the password won't be kept. var doPublish = true; var doSign = false; var doRestoreThisFile = false; var pfxPassword = "******"; string pfxPath = "C:\\digicert.pfx"; string packagerProjectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\")); string solutionDirectory = Path.GetFullPath(Path.Combine(packagerProjectDirectory, "..\\")); string guiProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.Gui\\")); string libraryProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi\\")); string wixProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.WindowsInstaller\\")); string binDistDirectory = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\dist")); Console.WriteLine($"{nameof(solutionDirectory)}:\t\t{solutionDirectory}"); Console.WriteLine($"{nameof(packagerProjectDirectory)}:\t{packagerProjectDirectory}"); Console.WriteLine($"{nameof(guiProjectDirectory)}:\t\t{guiProjectDirectory}"); Console.WriteLine($"{nameof(libraryProjectDirectory)}:\t\t{libraryProjectDirectory}"); Console.WriteLine($"{nameof(wixProjectDirectory)}:\t\t{wixProjectDirectory}"); Console.WriteLine($"{nameof(binDistDirectory)}:\t\t{binDistDirectory}"); string versionPrefix = Helpers.Constants.ClientVersion.ToString(); string executableName = "wassabee"; Console.WriteLine(); Console.WriteLine($"{nameof(versionPrefix)}:\t\t\t{versionPrefix}"); Console.WriteLine($"{nameof(executableName)}:\t\t\t{executableName}"); // https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog // BOTTLENECKS: // Tor - win-32, linux-32, osx-64 // .NET Core - win-32, linux-64, osx-64 // Avalonia - win7-32, linux-64, osx-64 // We'll only support x64, if someone complains, we can come back to it. // For 32 bit Windows there needs to be a lot of WIX configuration to be done. var targets = new List <string> { "win7-x64", "linux-x64", "osx-x64" }; Console.WriteLine(); Console.Write($"{nameof(targets)}:\t\t\t"); targets.ForEach(x => { if (targets.Last() != x) { Console.Write($"{x}, "); } else { Console.Write(x); } }); Console.WriteLine(); if (doPublish) { if (Directory.Exists(binDistDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(binDistDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {binDistDirectory}"); } var psiBuild = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = guiProjectDirectory }; using (var pBuild = Process.Start(psiBuild)) { pBuild.StandardInput.WriteLine("dotnet clean --configuration Release && exit"); pBuild.WaitForExit(); } var guiBinReleaseDirectory = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\Release")); var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(libraryProjectDirectory, "bin\\Release")); if (Directory.Exists(guiBinReleaseDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {guiBinReleaseDirectory}"); } if (Directory.Exists(libraryBinReleaseDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {libraryBinReleaseDirectory}"); } foreach (string target in targets) { string currentBinDistDirectory; string publishedFolder = Path.Combine(binDistDirectory, target); string macWasabiAppDir = Path.Combine(publishedFolder, "Wasabi Wallet.App"); // This should be lowercase .app, but MAC will prevent people from upgrading if we change it. string macContentsDir = Path.Combine(macWasabiAppDir, "Contents"); if (target.StartsWith("osx")) { currentBinDistDirectory = Path.GetFullPath(Path.Combine(macContentsDir, "MacOS")); } else { currentBinDistDirectory = publishedFolder; } Console.WriteLine(); Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}"); Console.WriteLine(); if (!Directory.Exists(currentBinDistDirectory)) { Directory.CreateDirectory(currentBinDistDirectory); Console.WriteLine($"Created {currentBinDistDirectory}"); } var psiClean = new ProcessStartInfo { FileName = "dotnet", Arguments = $"clean", WorkingDirectory = guiProjectDirectory }; using (var pClean = Process.Start(psiClean)) { pClean.WaitForExit(); } // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21 // -c|--configuration {Debug|Release} // Defines the build configuration. The default value is Debug. // --force // Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file. // -o|--output <OUTPUT_DIRECTORY> // Specifies the path for the output directory. // If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or // ./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment. // If the path is relative, the output directory generated is relative to the project file location, not to the current working directory. // --self-contained // Publishes the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine. // If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment. // -r|--runtime <RUNTIME_IDENTIFIER> // Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD). // For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD). // --version-suffix <VERSION_SUFFIX> // Defines the version suffix to replace the asterisk (*) in the version field of the project file. // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x // --disable-parallel // Disables restoring multiple projects in parallel. // --no-cache // Specifies to not cache packages and HTTP requests. // https://github.com/dotnet/docs/issues/7568 // /p:Version=1.2.3.4 // "dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4 var psiPublish = new ProcessStartInfo { FileName = "dotnet", Arguments = $"publish --configuration Release --force --output \"{currentBinDistDirectory}\" --self-contained true --runtime \"{target}\" /p:VersionPrefix={versionPrefix} --disable-parallel --no-cache", WorkingDirectory = guiProjectDirectory }; using (var pPublish = Process.Start(psiPublish)) { pPublish.WaitForExit(); } // Remove Tor binaries those are not relevant to the platform. var torFolder = new DirectoryInfo(Path.Combine(currentBinDistDirectory, "TorDaemons")); var toNotremove = ""; if (target.StartsWith("win")) { toNotremove = "win"; } else if (target.StartsWith("linux")) { toNotremove = "linux"; } else if (target.StartsWith("osx")) { toNotremove = "osx"; } foreach (var file in torFolder.EnumerateFiles()) { if (!file.Name.Contains("data", StringComparison.OrdinalIgnoreCase) && !file.Name.Contains(toNotremove, StringComparison.OrdinalIgnoreCase)) { File.Delete(file.FullName); } } // Rename the final exe. string oldExecutablePath; string newExecutablePath; if (target.StartsWith("win")) { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe"); newExecutablePath = Path.Combine(currentBinDistDirectory, $"{executableName}.exe"); } else // Linux & OSX { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui"); newExecutablePath = Path.Combine(currentBinDistDirectory, executableName); } File.Move(oldExecutablePath, newExecutablePath); long installedSizeKb = DirSize(new DirectoryInfo(publishedFolder)) / 1000; if (target.StartsWith("win")) { var psiEditbin = new ProcessStartInfo { FileName = "editbin", Arguments = $"\"{newExecutablePath}\" /SUBSYSTEM:WINDOWS", WorkingDirectory = currentBinDistDirectory }; using (var pEditbin = Process.Start(psiEditbin)) { pEditbin.WaitForExit(); } var icoPath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.ico"); var psiRcedit = new ProcessStartInfo { FileName = "rcedit", Arguments = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{versionPrefix}\" --set-product-version \"{versionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"", WorkingDirectory = currentBinDistDirectory }; using (var pRcedit = Process.Start(psiRcedit)) { pRcedit.WaitForExit(); } } else if (target.StartsWith("osx")) { string resourcesDir = Path.Combine(macContentsDir, "Resources"); string infoFilePath = Path.Combine(macContentsDir, "Info.plist"); Directory.CreateDirectory(resourcesDir); var iconpath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.icns"); File.Copy(iconpath, Path.Combine(resourcesDir, "WasabiLogo.icns")); string infoContent = $@"<?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>LSMinimumSystemVersion</key> <string>10.12</string> <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>{versionPrefix}</string> <key>CFBundleVersion</key> <string>{versionPrefix}</string> <key>CFBundleExecutable</key> <string>{executableName}</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> "; File.WriteAllText(infoFilePath, infoContent); var psiCreateSymLink = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = publishedFolder }; using (var createSymLinkProcess = Process.Start(psiCreateSymLink)) { createSymLinkProcess.StandardInput.WriteLine($"wsl ln -s /Applications && exit"); createSymLinkProcess.WaitForExit(); } //how to generate .DS_Store file - https://github.com/zkSNACKs/WalletWasabi/pull/928/commits/e38ed672dee25f6e45a3eb16584887cc6d48c4e6 var dmgContentDir = Path.Combine(packagerProjectDirectory, "Content", "Osx"); IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentDir), new DirectoryInfo(publishedFolder)); var psiGenIsoImage = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; string uncompressedDmgFileName = $"Wasabi-uncompressed.dmg"; string uncompressedDmgFilePath = Path.Combine(binDistDirectory, uncompressedDmgFileName); string dmgFileName = $"Wasabi-{versionPrefix}.dmg"; using (var genIsoImageProcess = Process.Start(psiGenIsoImage)) { // http://www.nathancoulson.com/proj_cross_tools.php // -D: Do not use deep directory relocation, and instead just pack them in the way we see them // -V: Volume Label // -no-pad: Do not pad the end by 150 sectors (300kb). As it is not a cd image, not required // -apple -r: Creates a .dmg image genIsoImageProcess.StandardInput.WriteLine($"wsl genisoimage -D -V \"Wasabi Wallet\" -no-pad -apple -r -dir-mode 755 -o \"{uncompressedDmgFileName}\" \"{new DirectoryInfo(publishedFolder).Name}\" && exit"); genIsoImageProcess.WaitForExit(); } // cd ~ // git clone https://github.com/planetbeing/libdmg-hfsplus.git && cd libdmg-hfsplus // https://github.com/planetbeing/libdmg-hfsplus/issues/14 // mkdir build && cd build // sudo apt-get install zlib1g-dev // cmake .. // cd build // sudo apt-get install libssl1.0-dev // cmake .. // cd ~/libdmg-hfsplus/build/ // make var psiDmg = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var dmgProcess = Process.Start(psiDmg)) { dmgProcess.StandardInput.WriteLine($"wsl ~/libdmg-hfsplus/build/dmg/./dmg dmg \"{uncompressedDmgFileName}\" \"{dmgFileName}\" && exit"); dmgProcess.WaitForExit(); } // In case compression above doesn't work: //var psiBzip = new ProcessStartInfo //{ // FileName = "cmd", // RedirectStandardInput = true, // WorkingDirectory = binDistDirectory //}; //var bzipProcess = Process.Start(psiBzip); //bzipProcess.StandardInput.WriteLine($"wsl bzip2 \"{uncompressedDmgFileName}\" && exit"); //bzipProcess.WaitForExit(); IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); File.Delete(uncompressedDmgFilePath); IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } else if (target.StartsWith("linux")) { Console.WriteLine("Create Linux .tar.gz"); if (!Directory.Exists(publishedFolder)) { throw new Exception($"{publishedFolder} doesn't exist."); } var newFolderName = $"WasabiLinux-{versionPrefix}"; var newFolderPath = Path.Combine(binDistDirectory, newFolderName); Directory.Move(publishedFolder, newFolderPath); publishedFolder = newFolderPath; var psiTar = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var tarProcess = Process.Start(psiTar)) { tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit"); tarProcess.WaitForExit(); } 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 = LinuxPathCombine(linuxUsrLocalBinFolder, newFolderName); var newFolderRelativePath = Path.Combine(debUsrLocalBinFolderRelativePath, newFolderName); newFolderPath = Path.Combine(binDistDirectory, newFolderRelativePath); Directory.Move(publishedFolder, newFolderPath); var assetsFolder = Path.Combine(guiProjectDirectory, "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.Count() == 1 && int.TryParse(number.First(), out int size)) { string destFolder = Path.Combine(debUsrShareIconsFolderPath, $"{size}x{size}", "apps"); Directory.CreateDirectory(destFolder); file.CopyTo(Path.Combine(destFolder, $"{executableName}.png")); } } var controlFilePath = Path.Combine(debianFolderPath, "control"); // License format doesn't 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: nopara73 <*****@*****.**>\n" + $"Version: {versionPrefix}\n" + $"Homepage: http://wasabiwallet.io\n" + $"Vcs-Git: git://github.com/zkSNACKs/WalletWasabi.git\n" + $"Vcs-Browser: https://github.com/zkSNACKs/WalletWasabi\n" + $"Architecture: amd64\n" + $"License: Open Source (MIT)\n" + $"Installed-Size: {installedSizeKb}\n" + $"Description: open-source, non-custodial, privacy focused Bitcoin wallet\n" + $" Built-in Tor, CoinJoin and Coin Control features.\n"; File.WriteAllText(controlFilePath, controlFileContent, Encoding.ASCII); var desktopFilePath = Path.Combine(debUsrAppFolderPath, $"{executableName}.desktop"); var desktopFileContent = $"[Desktop Entry]\n" + $"Type=Application\n" + $"Name=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;qwe;asd;\n"; File.WriteAllText(desktopFilePath, desktopFileContent, Encoding.ASCII); var wasabiStarterScriptPath = Path.Combine(debUsrLocalBinFolderPath, $"{executableName}"); var wasabiStarterScriptContent = $"#!/bin/sh\n" + $"{ linuxWasabiWalletFolder.TrimEnd('/')}/./{executableName}\n"; File.WriteAllText(wasabiStarterScriptPath, wasabiStarterScriptContent, Encoding.ASCII); string debExeLinuxPath = LinuxPathCombine(newFolderRelativePath, executableName); string debDestopFileLinuxPath = LinuxPathCombine(debUsrAppFolderRelativePath, $"{executableName}.desktop"); var wasabiStarterScriptLinuxPath = LinuxPathCombine(debUsrLocalBinFolderRelativePath, $"{executableName}"); var psi = new ProcessStartInfo { FileName = "wsl", Arguments = $"cd ~ && sudo umount /mnt/c && sudo mount -t drvfs C: /mnt/c -o metadata && cd /mnt/c/Users/user/Desktop/WalletWasabi/WalletWasabi.Gui/bin/dist && sudo chmod +x {debExeLinuxPath} && sudo chmod +x {wasabiStarterScriptLinuxPath} && sudo chmod -R 0644 {debDestopFileLinuxPath} && sudo chmod -R 0775 {LinuxPath(debianFolderRelativePath)} && dpkg --build {LinuxPath(debFolderRelativePath)} $(pwd)", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var p = Process.Start(psi)) { p.WaitForExit(); } IoHelpers.DeleteRecursivelyWithMagicDustAsync(debFolderPath).GetAwaiter().GetResult(); string oldDeb = Path.Combine(binDistDirectory, $"{executableName}_{versionPrefix}_amd64.deb"); string newDeb = Path.Combine(binDistDirectory, $"Wasabi-{versionPrefix}.deb"); File.Move(oldDeb, newDeb); IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } } } if (doSign is true) { 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"); if (!File.Exists(msiPath)) { throw new Exception(".msi doesn't exist. Expected path: Wasabi.msi."); } var msiFileName = Path.GetFileNameWithoutExtension(msiPath); var newMsiPath = Path.Combine(binDistDirectory, $"{msiFileName}-{versionPrefix}.msi"); File.Move(msiPath, newMsiPath); // Sign code with digicert. var psiSigntool = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var signToolProcess = Process.Start(psiSigntool)) { signToolProcess.StandardInput.WriteLine($"signtool sign /d \"Wasabi Wallet\" /f \"{pfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit"); signToolProcess.WaitForExit(); } IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } } Console.WriteLine("Signing final files..."); var finalFiles = Directory.GetFiles(binDistDirectory); foreach (var finalFile in finalFiles) { var psiSignProcess = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var signProcess = Process.Start(psiSignProcess)) { signProcess.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit"); signProcess.WaitForExit(); } var psiRestoreHeat = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = wixProjectDirectory }; using (var restoreHeatProcess = Process.Start(psiRestoreHeat)) { restoreHeatProcess.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit"); restoreHeatProcess.WaitForExit(); } if (doRestoreThisFile) { var psiRestoreThisFile = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = packagerProjectDirectory }; using (var restoreThisFileProcess = Process.Start(psiRestoreThisFile)) { restoreThisFileProcess.StandardInput.WriteLine($"git checkout -- Program.cs && exit"); restoreThisFileProcess.WaitForExit(); } } } IoHelpers.OpenFolderInFileExplorer(binDistDirectory); return; // No need for readkey here. } }
public void OpenWalletsFolder() { var path = Global.WalletsDir; IoHelpers.OpenFolderInFileExplorer(path); }
private void OnOpenWalletsFolder() { var global = Locator.Current.GetService <Global>(); IoHelpers.OpenFolderInFileExplorer(global.WalletManager.WalletDirectories.WalletsDir); }
public OpenDataFolderViewModel(string dataDir) { TargetCommand = ReactiveCommand.Create(() => IoHelpers.OpenFolderInFileExplorer(dataDir)); }
private static void Main(string[] args) { // 0. Dump Client version (or else wrong .msi will be created) - Helpers.Constants.ClientVersion // 1. Publish with Packager. // 2. Build WIX project with Release and x64 configuration. // 3. Sign with Packager, set restore true so the password won't be kept. var doPublish = true; var doSign = false; var doRestoreThisFile = false; var pfxPassword = "******"; string pfxPath = "C:\\digicert.pfx"; string packagerProjectDirectory = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\")); string solutionDirectory = Path.GetFullPath(Path.Combine(packagerProjectDirectory, "..\\")); string guiProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.Gui\\")); string libraryProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi\\")); string wixProjectDirectory = Path.GetFullPath(Path.Combine(solutionDirectory, "WalletWasabi.WindowsInstaller\\")); string binDistDirectory = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\dist")); Console.WriteLine($"{nameof(solutionDirectory)}:\t\t{solutionDirectory}"); Console.WriteLine($"{nameof(packagerProjectDirectory)}:\t{packagerProjectDirectory}"); Console.WriteLine($"{nameof(guiProjectDirectory)}:\t\t{guiProjectDirectory}"); Console.WriteLine($"{nameof(libraryProjectDirectory)}:\t\t{libraryProjectDirectory}"); Console.WriteLine($"{nameof(wixProjectDirectory)}:\t\t{wixProjectDirectory}"); Console.WriteLine($"{nameof(binDistDirectory)}:\t\t{binDistDirectory}"); string versionPrefix = Helpers.Constants.ClientVersion.ToString(); string executableName = "wassabee"; Console.WriteLine(); Console.WriteLine($"{nameof(versionPrefix)}:\t\t\t{versionPrefix}"); Console.WriteLine($"{nameof(executableName)}:\t\t\t{executableName}"); // https://docs.microsoft.com/en-us/dotnet/articles/core/rid-catalog // BOTTLENECKS: // Tor - win-32, linux-32, osx-64 // .NET Core - win-32, linux-64, osx-64 // Avalonia - win7-32, linux-64, osx-64 // We'll only support x64, if someone complains, we can come back to it. // For 32 bit Windows there needs to be a lot of WIX configuration to be done. var targets = new List <string> { "win7-x64", "linux-x64", "osx-x64" }; Console.WriteLine(); Console.Write($"{nameof(targets)}:\t\t\t"); targets.ForEach(x => { if (targets.Last() != x) { Console.Write($"{x}, "); } else { Console.Write(x); } }); Console.WriteLine(); if (doPublish) { if (Directory.Exists(binDistDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(binDistDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {binDistDirectory}"); } var psiBuild = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = guiProjectDirectory }; using (var pBuild = Process.Start(psiBuild)) { pBuild.StandardInput.WriteLine("dotnet clean --configuration Release && exit"); pBuild.WaitForExit(); } var guiBinReleaseDirectory = Path.GetFullPath(Path.Combine(guiProjectDirectory, "bin\\Release")); var libraryBinReleaseDirectory = Path.GetFullPath(Path.Combine(libraryProjectDirectory, "bin\\Release")); if (Directory.Exists(guiBinReleaseDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(guiBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {guiBinReleaseDirectory}"); } if (Directory.Exists(libraryBinReleaseDirectory)) { IoHelpers.DeleteRecursivelyWithMagicDustAsync(libraryBinReleaseDirectory).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {libraryBinReleaseDirectory}"); } foreach (string target in targets) { string currentBinDistDirectory; string publishedFolder = Path.Combine(binDistDirectory, target); string macWasabiAppDir = Path.Combine(publishedFolder, "Wasabi Wallet.App"); string macContentsDir = Path.Combine(macWasabiAppDir, "Contents"); if (target.StartsWith("osx")) { currentBinDistDirectory = Path.GetFullPath(Path.Combine(macContentsDir, "MacOS")); } else { currentBinDistDirectory = publishedFolder; } Console.WriteLine(); Console.WriteLine($"{nameof(currentBinDistDirectory)}:\t{currentBinDistDirectory}"); Console.WriteLine(); if (!Directory.Exists(currentBinDistDirectory)) { Directory.CreateDirectory(currentBinDistDirectory); Console.WriteLine($"Created {currentBinDistDirectory}"); } var psiClean = new ProcessStartInfo { FileName = "dotnet", Arguments = $"clean", WorkingDirectory = guiProjectDirectory }; using (var pClean = Process.Start(psiClean)) { pClean.WaitForExit(); } // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21 // -c|--configuration {Debug|Release} // Defines the build configuration. The default value is Debug. // --force // Forces all dependencies to be resolved even if the last restore was successful. Specifying this flag is the same as deleting the project.assets.json file. // -o|--output <OUTPUT_DIRECTORY> // Specifies the path for the output directory. // If not specified, it defaults to ./bin/[configuration]/[framework]/publish/ for a framework-dependent deployment or // ./bin/[configuration]/[framework]/[runtime]/publish/ for a self-contained deployment. // If the path is relative, the output directory generated is relative to the project file location, not to the current working directory. // --self-contained // Publishes the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine. // If a runtime identifier is specified, its default value is true. For more information about the different deployment types, see .NET Core application deployment. // -r|--runtime <RUNTIME_IDENTIFIER> // Publishes the application for a given runtime. This is used when creating a self-contained deployment (SCD). // For a list of Runtime Identifiers (RIDs), see the RID catalog. Default is to publish a framework-dependent deployment (FDD). // --version-suffix <VERSION_SUFFIX> // Defines the version suffix to replace the asterisk (*) in the version field of the project file. // https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x // --disable-parallel // Disables restoring multiple projects in parallel. // --no-cache // Specifies to not cache packages and HTTP requests. // https://github.com/dotnet/docs/issues/7568 // /p:Version=1.2.3.4 // "dotnet publish" supports msbuild command line options like /p:Version=1.2.3.4 var psiPublish = new ProcessStartInfo { FileName = "dotnet", Arguments = $"publish --configuration Release --force --output \"{currentBinDistDirectory}\" --self-contained true --runtime \"{target}\" /p:VersionPrefix={versionPrefix} --disable-parallel --no-cache", WorkingDirectory = guiProjectDirectory }; using (var pPublish = Process.Start(psiPublish)) { pPublish.WaitForExit(); } // Rename the final exe. string oldExecutablePath; string newExecutablePath; if (target.StartsWith("win")) { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui.exe"); newExecutablePath = Path.Combine(currentBinDistDirectory, $"{executableName}.exe"); } else // Linux & OSX { oldExecutablePath = Path.Combine(currentBinDistDirectory, "WalletWasabi.Gui"); newExecutablePath = Path.Combine(currentBinDistDirectory, executableName); } File.Move(oldExecutablePath, newExecutablePath); if (target.StartsWith("win")) { var psiEditbin = new ProcessStartInfo { FileName = "editbin", Arguments = $"\"{newExecutablePath}\" /SUBSYSTEM:WINDOWS", WorkingDirectory = currentBinDistDirectory }; using (var pEditbin = Process.Start(psiEditbin)) { pEditbin.WaitForExit(); } var icoPath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.ico"); var psiRcedit = new ProcessStartInfo { FileName = "rcedit", Arguments = $"\"{newExecutablePath}\" --set-icon \"{icoPath}\" --set-file-version \"{versionPrefix}\" --set-product-version \"{versionPrefix}\" --set-version-string \"LegalCopyright\" \"MIT\" --set-version-string \"CompanyName\" \"zkSNACKs\" --set-version-string \"FileDescription\" \"Privacy focused, ZeroLink compliant Bitcoin wallet.\" --set-version-string \"ProductName\" \"Wasabi Wallet\"", WorkingDirectory = currentBinDistDirectory }; using (var pRcedit = Process.Start(psiRcedit)) { pRcedit.WaitForExit(); } } else if (target.StartsWith("osx")) { string resourcesDir = Path.Combine(macContentsDir, "Resources"); string infoFilePath = Path.Combine(macContentsDir, "Info.plist"); Directory.CreateDirectory(resourcesDir); var iconpath = Path.Combine(guiProjectDirectory, "Assets", "WasabiLogo.icns"); File.Copy(iconpath, Path.Combine(resourcesDir, "WasabiLogo.icns")); string infoContent = $@"<?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>LSMinimumSystemVersion</key> <string>10.12</string> <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>{versionPrefix}</string> <key>CFBundleVersion</key> <string>{versionPrefix}</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> "; File.WriteAllText(infoFilePath, infoContent); var psiCreateSymLink = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = publishedFolder }; using (var createSymLinkProcess = Process.Start(psiCreateSymLink)) { createSymLinkProcess.StandardInput.WriteLine($"wsl ln -s /Applications && exit"); createSymLinkProcess.WaitForExit(); } //how to generate .DS_Store file - https://github.com/zkSNACKs/WalletWasabi/pull/928/commits/e38ed672dee25f6e45a3eb16584887cc6d48c4e6 var dmgContentDir = Path.Combine(packagerProjectDirectory, "Content", "Osx"); IoHelpers.CopyFilesRecursively(new DirectoryInfo(dmgContentDir), new DirectoryInfo(publishedFolder)); var psiGenIsoImage = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; string uncompressedDmgFileName = $"Wasabi-uncompressed.dmg"; string uncompressedDmgFilePath = Path.Combine(binDistDirectory, uncompressedDmgFileName); string dmgFileName = $"Wasabi-{versionPrefix}.dmg"; using (var genIsoImageProcess = Process.Start(psiGenIsoImage)) { // http://www.nathancoulson.com/proj_cross_tools.php // -D: Do not use deep directory relocation, and instead just pack them in the way we see them // -V: Volume Label // -no-pad: Do not pad the end by 150 sectors (300kb). As it is not a cd image, not required // -apple -r: Creates a .dmg image genIsoImageProcess.StandardInput.WriteLine($"wsl genisoimage -D -V \"Wasabi Wallet\" -no-pad -apple -r -o \"{uncompressedDmgFileName}\" \"{new DirectoryInfo(publishedFolder).Name}\" && exit"); genIsoImageProcess.WaitForExit(); } // cd ~ // git clone https://github.com/planetbeing/libdmg-hfsplus.git && cd libdmg-hfsplus // https://github.com/planetbeing/libdmg-hfsplus/issues/14 // mkdir build && cd build // sudo apt-get install zlib1g-dev // cmake .. // cd build // sudo apt-get install libssl1.0-dev // cmake .. // cd ~/libdmg-hfsplus/build/ // make var psiDmg = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var dmgProcess = Process.Start(psiDmg)) { dmgProcess.StandardInput.WriteLine($"wsl ~/libdmg-hfsplus/build/dmg/./dmg dmg \"{uncompressedDmgFileName}\" \"{dmgFileName}\" && exit"); dmgProcess.WaitForExit(); } // In case compression above doesn't work: //var psiBzip = new ProcessStartInfo //{ // FileName = "cmd", // RedirectStandardInput = true, // WorkingDirectory = binDistDirectory //}; //var bzipProcess = Process.Start(psiBzip); //bzipProcess.StandardInput.WriteLine($"wsl bzip2 \"{uncompressedDmgFileName}\" && exit"); //bzipProcess.WaitForExit(); IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); File.Delete(uncompressedDmgFilePath); IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } else if (target.StartsWith("linux")) { Console.WriteLine("Create Linux .tar.gz"); if (!Directory.Exists(publishedFolder)) { throw new Exception($"{publishedFolder} doesn't exist."); } var newFolderName = $"WasabiLinux-{versionPrefix}"; var newFolderPath = Path.Combine(binDistDirectory, newFolderName); Directory.Move(publishedFolder, newFolderPath); publishedFolder = newFolderPath; var psiTar = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var tarProcess = Process.Start(psiTar)) { tarProcess.StandardInput.WriteLine($"wsl tar -pczvf {newFolderName}.tar.gz {newFolderName} && exit"); tarProcess.WaitForExit(); } IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } } } if (doSign is true) { 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"); if (!File.Exists(msiPath)) { throw new Exception(".msi doesn't exist. Expected path: Wasabi.msi."); } var msiFileName = Path.GetFileNameWithoutExtension(msiPath); var newMsiPath = Path.Combine(binDistDirectory, $"{msiFileName}-{versionPrefix}.msi"); File.Move(msiPath, newMsiPath); // Sign code with digicert. var psiSigntool = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var signToolProcess = Process.Start(psiSigntool)) { signToolProcess.StandardInput.WriteLine($"signtool sign /d \"Wasabi Wallet\" /f \"{pfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit"); signToolProcess.WaitForExit(); } IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } } Console.WriteLine("Signing final files..."); var finalFiles = Directory.GetFiles(binDistDirectory); foreach (var finalFile in finalFiles) { var psiSignProcess = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = binDistDirectory }; using (var signProcess = Process.Start(psiSignProcess)) { signProcess.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit"); signProcess.WaitForExit(); } var psiRestoreHeat = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = wixProjectDirectory }; using (var restoreHeatProcess = Process.Start(psiRestoreHeat)) { restoreHeatProcess.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit"); restoreHeatProcess.WaitForExit(); } if (doRestoreThisFile) { var psiRestoreThisFile = new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = packagerProjectDirectory }; using (var restoreThisFileProcess = Process.Start(psiRestoreThisFile)) { restoreThisFileProcess.StandardInput.WriteLine($"git checkout -- Program.cs && exit"); restoreThisFileProcess.WaitForExit(); } } } IoHelpers.OpenFolderInFileExplorer(binDistDirectory); return; // No need for readkey here. } }
public HelpCommands(CommandIconService commandIconService) { AboutCommand = new CommandDefinition( "About", commandIconService.GetCompletionKindImage("About"), ReactiveCommand.Create(() => { IoC.Get <IShell>().AddOrSelectDocument(() => new AboutViewModel()); })); DataFolderCommand = new CommandDefinition( "Data Folder", commandIconService.GetCompletionKindImage("DataFolder"), ReactiveCommand.Create(() => { IoHelpers.OpenFolderInFileExplorer(Global.DataDir); })); CustomerSupportCommand = new CommandDefinition( "Customer Support", commandIconService.GetCompletionKindImage("CustomerSupport"), ReactiveCommand.Create(() => { IoC.Get <IShell>().AddOrSelectDocument(() => new CustomerSupportViewModel()); })); ReportBugCommand = new CommandDefinition( "Report Bug", commandIconService.GetCompletionKindImage("ReportBug"), ReactiveCommand.Create(() => { IoC.Get <IShell>().AddOrSelectDocument(() => new ReportBugViewModel()); })); PrivacyPolicyCommand = new CommandDefinition( "Privacy Policy", commandIconService.GetCompletionKindImage("PrivacyPolicy"), ReactiveCommand.Create(() => { IoC.Get <IShell>().AddOrSelectDocument(() => new PrivacyPolicyViewModel()); })); TermsAndConditionsCommand = new CommandDefinition( "Terms and Conditions", commandIconService.GetCompletionKindImage("TermsAndConditions"), ReactiveCommand.Create(() => { IoC.Get <IShell>().AddOrSelectDocument(() => new TermsAndConditionsViewModel()); })); LegalIssuesCommand = new CommandDefinition( "Legal Issues", commandIconService.GetCompletionKindImage("LegalIssues"), ReactiveCommand.Create(() => { IoC.Get <IShell>().AddOrSelectDocument(() => new LegalIssuesViewModel()); })); #if DEBUG DevToolsCommand = new CommandDefinition( "Dev Tools", commandIconService.GetCompletionKindImage("DevTools"), ReactiveCommand.Create(() => { var devTools = new DevTools(Application.Current.Windows.FirstOrDefault()); var devToolsWindow = new Window { Width = 1024, Height = 512, Content = devTools, DataTemplates = { new ViewLocator <Avalonia.Diagnostics.ViewModels.ViewModelBase>(), } }; devToolsWindow.Show(); })); #endif }
private void OnOpenDataFolder() { IoHelpers.OpenFolderInFileExplorer(Global.DataDir); }
private void OnOpenDataFolder() { var global = Locator.Current.GetService <Global>(); IoHelpers.OpenFolderInFileExplorer(global.DataDir); }
private void OnOpenWalletsFolder() { IoHelpers.OpenFolderInFileExplorer(Global.WalletsDir); }
private static void Sign() { 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"); if (!File.Exists(msiPath)) { throw new Exception(".msi does not exist. Expected path: Wasabi.msi."); } var msiFileName = Path.GetFileNameWithoutExtension(msiPath); var newMsiPath = Path.Combine(BinDistDirectory, $"{msiFileName}-{VersionPrefix}.msi"); File.Move(msiPath, newMsiPath); Console.Write("Enter Code Signing Certificate Password: "******"cmd", RedirectStandardInput = true, WorkingDirectory = BinDistDirectory })) { process.StandardInput.WriteLine($"signtool sign /d \"Wasabi Wallet\" /f \"{PfxPath}\" /p {pfxPassword} /t http://timestamp.digicert.com /a \"{newMsiPath}\" && exit"); process.WaitForExit(); } IoHelpers.DeleteRecursivelyWithMagicDustAsync(publishedFolder).GetAwaiter().GetResult(); Console.WriteLine($"Deleted {publishedFolder}"); } } Console.WriteLine("Signing final files..."); var finalFiles = Directory.GetFiles(BinDistDirectory); foreach (var finalFile in finalFiles) { using (var process = Process.Start(new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = BinDistDirectory })) { process.StandardInput.WriteLine($"gpg --armor --detach-sign {finalFile} && exit"); process.WaitForExit(); } using (var process = Process.Start(new ProcessStartInfo { FileName = "cmd", RedirectStandardInput = true, WorkingDirectory = WixProjectDirectory })) { process.StandardInput.WriteLine($"git checkout -- ComponentsGenerated.wxs && exit"); process.WaitForExit(); } } IoHelpers.OpenFolderInFileExplorer(BinDistDirectory); }
public OpenWalletsFolderViewModel() { TargetCommand = ReactiveCommand.Create( () => IoHelpers.OpenFolderInFileExplorer(Services.WalletManager.WalletDirectories.WalletsDir)); }