Files
Blueberry/BlueberryUpdater/Program.cs
2025-12-10 10:59:48 +01:00

196 lines
7.0 KiB
C#

using System.Diagnostics;
using System.IO.Compression;
using System.Reflection;
namespace BlueberryUpdater
{
internal class Program
{
static string appName = "Blueberry";
static string updaterName = appName + "Updater";
static string installPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), appName);
static void Main(string[] args)
{
if (Directory.Exists(installPath) && File.Exists(Path.Combine(installPath, appName + ".exe")))
Uninstall();
else
Install();
}
private static void Uninstall()
{
Console.WriteLine("Would you like to uninstall Blueberry? [y/N]");
var key = Console.ReadLine();
if (key == null ||key.ToLower() != "y")
return;
var appdata = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), appName);
Console.WriteLine("Removing Blueberry...");
var dirs = Directory.GetDirectories(installPath);
var files = Directory.GetFiles(installPath);
var total = dirs.Length + files.Length;
var i = 0;
foreach (var dir in dirs)
{
i++;
Directory.Delete(dir, true);
DrawProgressBar((int)((double)i / total * 100), dir.Split('\\').Last());
}
foreach (var file in files)
{
i++;
if (file.Split('\\').Last() == updaterName + ".exe")
continue;
File.Delete(file);
i++;
DrawProgressBar((int)((double)i / total * 100), file.Split('\\').Last());
}
Directory.Delete(appdata, true);
DrawProgressBar(100, "Done");
Console.WriteLine();
Console.WriteLine("Uninstall Complete!");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
SelfDelete();
}
private static void Install()
{
try
{
string resourceName = "BlueberryUpdater.AppPayload.zip"; // Format: Namespace.Filename
Console.WriteLine($"Installing to {installPath}...");
// 1. Clean existing install if necessary
if (Directory.Exists(installPath))
{
Directory.Delete(installPath, true);
}
Directory.CreateDirectory(installPath);
// 2. Extract Embedded Resource
var assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
if (stream == null)
{
throw new Exception($"Resource '{resourceName}' not found. Check Embedded Resource settings.");
}
using (ZipArchive archive = new(stream))
{
int totalEntries = archive.Entries.Count;
int currentEntry = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
{
currentEntry++;
// Calculate percentage
int percent = (int)((double)currentEntry / totalEntries * 100);
// Draw Progress Bar
DrawProgressBar(percent, entry.Name);
// Create the full path
string destinationPath = Path.GetFullPath(Path.Combine(installPath, entry.FullName));
// Security check: prevent ZipSlip (writing outside target folder)
if (!destinationPath.StartsWith(installPath, StringComparison.OrdinalIgnoreCase))
continue;
// Handle folders vs files
if (string.IsNullOrEmpty(entry.Name)) // It's a directory
{
Directory.CreateDirectory(destinationPath);
}
else // It's a file
{
// Ensure the directory exists (zipped files might not list their dir first)
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
entry.ExtractToFile(destinationPath, overwrite: true);
}
}
}
}
MoveUpdater();
DrawProgressBar(100, "Done");
Console.WriteLine();
Console.WriteLine("Installation Complete!");
// Optional: Create Shortcut logic here
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error: {ex.Message}");
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
public static void SelfDelete()
{
string exePath = Process.GetCurrentProcess().MainModule.FileName;
string directoryToDelete = Path.GetDirectoryName(exePath);
string args = $"/C timeout /t 2 /nobreak > Nul & del \"{exePath}\" & rmdir /q \"{directoryToDelete}\"";
ProcessStartInfo psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = args,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false
};
Process.Start(psi);
Environment.Exit(0);
}
public static void MoveUpdater()
{
string currentExe = Process.GetCurrentProcess().MainModule.FileName;
var updaterPath = Path.Combine(installPath, updaterName + ".exe");
Directory.CreateDirectory(Path.GetDirectoryName(updaterPath));
File.Copy(currentExe, updaterPath, overwrite: true);
}
static void DrawProgressBar(int percent, string filename)
{
// Move cursor to start of line
Console.CursorLeft = 0;
// Limit filename length for clean display
string shortName = filename.Length > 20 ? filename.Substring(0, 17) + "..." : filename.PadRight(20);
Console.Write("[");
int width = Console.WindowWidth - 1; // Width of the bar
int progress = (int)((percent / 100.0) * width);
// Draw filled part
Console.Write(new string('#', progress));
// Draw empty part
Console.Write(new string('-', width - progress));
Console.Write($"] {percent}% {shortName}");
}
}
}