diff --git a/csharp/app/VenusFirmwareCiDaemon/FirmwareCiDaemon.csproj b/csharp/app/VenusFirmwareCiDaemon/FirmwareCiDaemon.csproj deleted file mode 100644 index ab56dceed..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/FirmwareCiDaemon.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - - InnovEnergy.Server.FirmwareCiDaemon - - - - - - - - - - - - diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Branch.cs b/csharp/app/VenusFirmwareCiDaemon/src/Branch.cs deleted file mode 100644 index e0954371b..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Branch.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public enum Branch -{ - Release, - Develop, - Victron, -} - -public static class BranchExtensions -{ - public static String GetName(this Branch branch) => branch switch - { - Branch.Victron => "venus.victron", - Branch.Release => "venus.release", - Branch.Develop => "venus", - _ => throw new Exception($"Unsupported branch: {branch}") - }; - - -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Build.cs b/csharp/app/VenusFirmwareCiDaemon/src/Build.cs deleted file mode 100644 index bf93a7008..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Build.cs +++ /dev/null @@ -1,295 +0,0 @@ -using System.Text.RegularExpressions; -using CliWrap; -using InnovEnergy.Lib.Utils; -using static InnovEnergy.Server.FirmwareCiDaemon.Logger; -using static InnovEnergy.Server.FirmwareCiDaemon.ExitException; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public record Build -{ - private static readonly Regex RxTimestamp = new Regex(@"\d{14}"); - private static readonly Regex RxVersion = new Regex(@"v\d+\.\d+(~\w+)?"); - - private const Int32 MaxPublishedSwus = 12; - - public Device Device { get; init; } - public String VeVersion { get; init; } - public Branch Branch { get; init; } - public String Comment { get; init; } - public String Hash { get; init; } - - public String ShortHash => Hash[..6]; - - public Channel Channel => Branch switch - { - Branch.Victron => Channel.Testing, - Branch.Release => Channel.Release, - Branch.Develop => Channel.Develop, - _ => throw new Exception($"Unsupported branch: {Branch}") - }; - - public String VersionId => Branch switch - { - Branch.Victron => $"{VeVersion}~victron", - Branch.Release => $"{VeVersion}~{Comment}", - Branch.Develop => $"{VeVersion}~{ShortHash}", - _ => throw new Exception($"Unsupported branch: {Branch}") - }; - - public static Build Prepare(CommitInfo ie, (Device device, String veVersion) ve) - { - return new Build - { - Device = ve.device, - VeVersion = ve.veVersion, - Branch = ie.Branch, - Comment = ie.Comment, - Hash = ie.Hash - }; - } - - - public void Execute() - { - Log(); - Log("======================================================"); - Log("Starting build"); - Log("======================================================"); - Log(); - Log($"VE Version: {VeVersion}"); - Log($"Channel : {Channel}"); - Log($"Device : {Device}"); - Log($"Branch : {Branch}"); - Log($"Comment : {Comment}"); - Log($"Version ID: {VersionId}"); - Log($"SWU Name : {Device.SwuName()}"); - Log($"Hash : {Hash}"); - Log(); - Log("======================================================"); - Log(); - - using var veBaseSwuFile = FwSource.Victron.GetLatestSwuPath(Channel.Release, Device).Apply(DownloadFile); - using var ieRepo = Fossil.Checkout(Branch); - using var releaseSwu = MergeSwu(veBaseSwuFile, ieRepo.FirmwareDirectory, Device, VersionId); - - var publishedSwu = PublishSwu(Device, Channel, releaseSwu); - - RemoveOldFiles(Device, Channel); - - var zipPath = Channel.ZipPath(); - var removeGlob = Device.SwuBase() + "*"; - - if (zipPath is null) - return; - - Log($"Updating {zipPath[Program.IeBasePath.Length..]}"); - - zipPath.RemoveFromZip(removeGlob); - zipPath.AddToZip(publishedSwu); - } - - public static Disposable DownloadFile(String url) - { - var fileName = Path.GetFileName(url); - - var downloadedFile = FileSystem.CreateTempFile(fileName); - - Log($"downloading {url}"); - - var curl = Cli - .Wrap("curl") - .WithArguments(url) - .PipeToFile(downloadedFile); - - if (curl.exitCode != 0) - Exit("Failed to download " + url); - - return downloadedFile; - } - - private static void UpdateVersionFile(String fwDir, String version, String timestamp, String file) - { - Log($"updating {file}"); - - var fwFile = fwDir.AppendPath(file); - - if (!FileSystem.Local.FileExists(fwFile)) - Exit($"Cannot find {fwFile}"); - - var contents = File.ReadAllText(fwFile); - - contents = RxTimestamp.Replace(contents, timestamp); - contents = RxVersion.Replace(contents, version); - - try - { - File.WriteAllText(fwFile, contents); - } - catch - { - Exit($"Failed to write to {fwFile}"); - } - } - - private static void PatchIeFiles(String fossilDir, String mountDir) - { - Log("applying changes"); - - var (exitCode, stdOut, stdErr) = Cli - .Wrap("rsync") - .WithArguments($"-r -t -v -l -i -u -I {fossilDir}/ {mountDir}") // that / is important! - .ExecuteSync(); - - if (exitCode != 0) - Exit($"Failed to apply changes!\n{stdErr}\n{stdOut}"); - } - - - - private static Disposable Unzip(String ext4GzFile) - { - var ext4GzFileName = Path.GetFileName(ext4GzFile); - Log($"extracting {ext4GzFileName}"); - - var ext4File = ext4GzFileName - .RemoveSuffix(".gz") - .Apply(FileSystem.CreateTempFile); - - var zcat = Cli - .Wrap("zcat") - .WithArguments(ext4GzFile) - .PipeToFile(ext4File); - - if (zcat.exitCode != 0) - { - ext4File.Dispose(); - Exit("Failed to extract " + ext4GzFile); - } - - return ext4File; - } - - private static Disposable Mount(String ext4File) - { - var ext4FileName = Path.GetFileName(ext4File); - Log($"mounting {ext4FileName}"); - - var mountDir = FileSystem.CreateTmpDir(); - - var mount = Cli - .Wrap("mount") - .WithArguments($"-o loop -t ext4 {ext4File} {mountDir}") - .ExecuteSync(); - - if (mount.exitCode != 0) - { - Log($"\nFailed to mount {ext4File} on {mountDir}:\n{mount.stdErr}"); - - mountDir.Dispose(); - Exit($"\nFailed to mount {ext4File}:\n{mount.stdErr}"); - } - - return mountDir.BeforeDisposeDo(Unmount); - - void Unmount() - { - Log($"unmounting {ext4FileName}"); - - var umount = Cli - .Wrap("umount") - .WithArguments(mountDir) - .ExecuteSync(); - - if (umount.exitCode != 0) - Exit($"Failed to unmount {mountDir}\n{umount.stdErr}"); - } - } - - private static void ApplyChanges(String ieFirmwareDir, - String ext4File, - String timestamp, - String version) - { - using var mountDir = Mount(ext4File); // IMPORTANT: must unmount (dispose) before zipping ext4 file again! - - PatchIeFiles(ieFirmwareDir, mountDir); - - UpdateVersionFile(mountDir, version, timestamp, "/etc/issue"); - UpdateVersionFile(mountDir, version, timestamp, "/etc/issue.net"); - UpdateVersionFile(mountDir, version, timestamp, "/etc/version"); - UpdateVersionFile(mountDir, version, timestamp, "/opt/victronenergy/version"); - } - - - private static void UpdateSymlink(String newSwuFile, String newSwuLink) - { - var ln = Cli - .Wrap("ln") - .WithArguments($"-sfn {newSwuFile} {newSwuLink}") - .ExecuteSync(); - - if (ln.exitCode != 0) - Exit($"failed to update symlink {newSwuLink}"); - } - - - private static void RemoveOldFiles(Device device, Channel channel) - { - var oldFiles = Directory - .GetFiles(FwSource.InnovEnergy.GetDirectory(channel, device)) - .Where(f => f.EndsWith(".swu")) - .OrderByDescending(File.GetCreationTimeUtc) - .Skip(MaxPublishedSwus); - - foreach (var file in oldFiles) - { - Log($"Deleting old swu file {file.Substring(Program.IeBasePath.Length)}"); - File.Delete(file); - } - } - - private static String PublishSwu(Device device, Channel channel, String releaseSwu) - { - var swuFileName = Path.GetFileName(releaseSwu); - var newSwuFile = FwSource.InnovEnergy.GetDirectory(channel, device).AppendPath(swuFileName); - var newSwuLink = FwSource.InnovEnergy.GetLatestSwuPath(channel, device); - - Log($"publishing {newSwuFile[Program.IeBasePath.Length..]}"); - - new FileInfo(newSwuFile).Directory?.Create(); // create dir if not exits - File.Move(releaseSwu, newSwuFile); - - UpdateSymlink(newSwuFile, newSwuLink); - - return newSwuFile; - } - - - private static Disposable MergeSwu(String victronBaseSwuFile, - String ieFirmwareDir, - Device device, - String version) - { - var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); - - using var cpioDir = Cpio.Extract(victronBaseSwuFile); - - var ext4GzFile = cpioDir.Value.AppendPath(device.ExtGzFileName()); - - using var ext4File = Unzip(ext4GzFile); - - UpdateVersionFile(cpioDir, version, timestamp, "/sw-description"); - ApplyChanges(ieFirmwareDir, ext4File, timestamp, version); - - Zip.GZip(ext4File, ext4GzFile); - - var mergedSwuFile = device - .LongSwuFileName(timestamp, version) - .Apply(FileSystem.CreateTempFile); - - Cpio.Write(cpioDir, mergedSwuFile); - - return mergedSwuFile; - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Channel.cs b/csharp/app/VenusFirmwareCiDaemon/src/Channel.cs deleted file mode 100644 index c59edfe63..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Channel.cs +++ /dev/null @@ -1,31 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public enum Channel -{ - Release, - Candidate, - Testing, - Develop -} - -public static class ChannelExtensions -{ - public static String GetName(this Channel channel) - { - return Enum.GetName(typeof(Channel), channel)?.ToLower()!; - } - - public static String? ZipPath(this Channel channel) - { - if (channel is Channel.Candidate or Channel.Develop) - return null; - - var fileName = channel is Channel.Release - ? "release.zip" - : "victron.zip"; - - return Program.IeBasePath.AppendPath("venus").AppendPath(fileName); - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/CliExtensions.cs b/csharp/app/VenusFirmwareCiDaemon/src/CliExtensions.cs deleted file mode 100644 index 8fe61f3b1..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/CliExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Text; -using CliWrap; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public static class CliExtensions -{ - - // TODO: obsolete, use ExecuteBufferedAsync - public static (Int32 exitCode, String stdOut, String stdErr) ExecuteSync(this Command cmd) - { - var stdErr = new StringBuilder(); - var stdOut = new StringBuilder(); - - var r = cmd - .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdOut)) - .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErr)) - .WithValidation(CommandResultValidation.None) - .ExecuteAsync() - .Task - .Result; - - return (r.ExitCode, stdOut.ToString(), stdErr.ToString()); - } - - public static (Int32 exitCode, String stdErr) PipeToFile(this Command cmd, String file) - { - var stdErr = new StringBuilder(); - - var r = cmd - .WithStandardOutputPipe(PipeTarget.ToFile(file)) - .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErr)) - .WithValidation(CommandResultValidation.None) - .ExecuteAsync() - .Task - .Result; - - return (r.ExitCode, stdErr.ToString()); - } - -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Commit.cs b/csharp/app/VenusFirmwareCiDaemon/src/Commit.cs deleted file mode 100644 index c45e467b8..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Commit.cs +++ /dev/null @@ -1,15 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public class Commit : Disposable -{ - public String Directory { get; } - public String FirmwareDirectory => Directory.AppendPath("firmware"); - - public Commit(Disposable directory) : base(directory.Dispose) - { - Directory = directory; - } - -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/CommitInfo.cs b/csharp/app/VenusFirmwareCiDaemon/src/CommitInfo.cs deleted file mode 100644 index f4938f723..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/CommitInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public record CommitInfo -{ - public String Hash { get; init; } - public String Comment { get; init; } - public Branch Branch { get; init; } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Cpio.cs b/csharp/app/VenusFirmwareCiDaemon/src/Cpio.cs deleted file mode 100644 index 262d4028e..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Cpio.cs +++ /dev/null @@ -1,55 +0,0 @@ -using CliWrap; -using InnovEnergy.Lib.Utils; -using static InnovEnergy.Server.FirmwareCiDaemon.ExitException; -using static InnovEnergy.Server.FirmwareCiDaemon.Logger; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public static class Cpio -{ - public static void Write(String cpioDir, String swuFile) - { - var swuFileName = Path.GetFileName(swuFile); - - Log($"writing {swuFileName}"); - - // ls | cpio -o -H crc > "../$swu" 2>/dev/null - - var ls = Cli - .Wrap("ls") - .WithWorkingDirectory(cpioDir); - - var cpio = Cli - .Wrap("cpio") - .WithArguments("-o -H crc") - .WithStandardOutputPipe(PipeTarget.ToFile(swuFile)) - .WithWorkingDirectory(cpioDir); - - var lsCpio = (ls | cpio).ExecuteAsync().Task.Result; - - if (lsCpio.ExitCode != 0) - Exit($"Failed to write {swuFileName}"); - } - - public static Disposable Extract(String swuFile) - { - Log($"extracting {Path.GetFileName(swuFile)}"); - - var cpioDir = FileSystem.CreateTmpDir(); - - var cpio = Cli - .Wrap("cpio") - .WithArguments("-id") - .WithStandardInputPipe(PipeSource.FromFile(swuFile)) - .WithWorkingDirectory(cpioDir) - .ExecuteSync(); - - if (cpio.exitCode != 0) - { - cpioDir.Dispose(); - Exit("Failed to extract swu"); - } - - return cpioDir; - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Device.cs b/csharp/app/VenusFirmwareCiDaemon/src/Device.cs deleted file mode 100644 index 5f3aeeb23..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Device.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -[SuppressMessage("ReSharper", "InconsistentNaming")] -public enum Device -{ - BeagleBone, - BeagleBone2, - NanoPi, - Einstein, - RaspberryPi2 -} - -public static class DeviceExtensions -{ - public static String GetName(this Device device) - { - if (device == Device.BeagleBone2) - device = Device.BeagleBone; - - var name = Enum.GetName(device)?.ToLower(); - if (name is null) - throw new ArgumentException(nameof(device)); - - return name; - } - - public static String SwuName(this Device device) - { - return device switch - { - Device.BeagleBone2 => "venus-swu-2", - _ => "venus-swu" - }; - } - - - public static String SwuBase(this Device device) - { - var deviceName = device.GetName(); - var swuName = device.SwuName(); - return $"{swuName}-{deviceName}"; - } - - public static String ShortSwuFileName(this Device device) - { - var swuBase = device.SwuBase(); - return $"{swuBase}.swu"; - } - - public static String ExtFileName(this Device device) - { - var deviceName = device.GetName(); - return $"venus-image-{deviceName}.ext4"; - } - - public static String ExtGzFileName(this Device device) - { - return device.ExtFileName() + ".gz"; - } - - public static String LongSwuFileName(this Device device, String timestamp, String version) - { - var swuBase = device.SwuBase(); - return $"{swuBase}-{timestamp}-{version}.swu"; - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/ExitException.cs b/csharp/app/VenusFirmwareCiDaemon/src/ExitException.cs deleted file mode 100644 index 4921438c3..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/ExitException.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public class ExitException : Exception -{ - public Int32 ExitCode { get; } - - public ExitException(Int32 exitCode = 1): base("") - { - ExitCode = exitCode; - } - - public ExitException(String message, Int32 exitCode = 1) : base(message) - { - ExitCode = exitCode; - } - - public static void Exit(String msg) => throw new ExitException(msg); - public static void Exit(Int32 exitCode) => throw new ExitException(exitCode); -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Fossil.cs b/csharp/app/VenusFirmwareCiDaemon/src/Fossil.cs deleted file mode 100644 index e23fe0c2b..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Fossil.cs +++ /dev/null @@ -1,83 +0,0 @@ -using CliWrap; -using InnovEnergy.Lib.Utils; -using static System.StringSplitOptions; -using static InnovEnergy.Server.FirmwareCiDaemon.ExitException; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public static class Fossil -{ - public static String FossilFile { get; set; } - public static String FossilUser { get; set; } - - // TODO: get commit/branch without checkout - - public static Commit Checkout(this Branch branch) - { - var fossilDir = Open(); - Update(fossilDir, branch, FossilUser); - return new Commit(fossilDir); - } - - public static CommitInfo GetLatestCommitInfo(this Branch branch) - { - using var fossilDir = Open(); - var (hash, comment) = Update(fossilDir, branch, FossilUser); - return new CommitInfo { Hash = hash, Comment = comment, Branch = branch}; - } - - private static Disposable Open() - { - var fossilDir = FileSystem.CreateTmpDir(); - var fossilCmd = Cli - .Wrap("fossil") - .WithWorkingDirectory(fossilDir); - - var open = fossilCmd - .WithArguments($"open {FossilFile} --empty") - .ExecuteSync(); - - if (open.exitCode != 0) - { - fossilDir.Dispose(); - Exit("failed to open " + Path.GetFileName(FossilFile) + "\n" + open.stdOut + "\n" + open.stdErr); - } - - return fossilDir.BeforeDisposeDo(Close); - - void Close() => fossilCmd.WithArguments("close").ExecuteSync(); - } - - public static (String hash, String comment) Update(String fossilDir, Branch branch, String fossilUser) - { - var fossil = Cli - .Wrap("fossil") - .WithArguments($"update --user {fossilUser} {branch.GetName()}") - .WithWorkingDirectory(fossilDir) - .WithValidation(CommandResultValidation.None) - .ExecuteSync(); - - if (fossil.exitCode != 0) - Exit($"failed to update!\n{fossil.stdOut}"); - - var fossilOutLines = fossil.stdOut.SplitLines(); - - const String checkoutPrefix = "updated-to:"; - const String commentPrefix = "comment:"; - - var hash = fossilOutLines - .Single(l => l.StartsWith(checkoutPrefix)) - .Split(" ", RemoveEmptyEntries) - .ElementAt(1); - - var comment = fossilOutLines - .Single(l => l.StartsWith(commentPrefix)) - .Substring(commentPrefix.Length) - .SkipWhile(c => c == ' ') - .TakeWhile(c => c != '(') // there is a (user: ig) at the end, stops at the first (, but whatever - .Apply(String.Concat) - .Trim(); - - return (hash, comment); - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/FwSource.cs b/csharp/app/VenusFirmwareCiDaemon/src/FwSource.cs deleted file mode 100644 index a3007b629..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/FwSource.cs +++ /dev/null @@ -1,33 +0,0 @@ -using InnovEnergy.Lib.Utils; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public enum FwSource -{ - InnovEnergy, - Victron -} - -public static class FwSourceExtensions -{ - public static String GetLatestSwuPath(this FwSource source, Channel channel, Device device) - { - var path = source.GetDirectory(channel, device); - var file = device.ShortSwuFileName(); - - return path.AppendPath(file); - } - - public static String GetDirectory(this FwSource source, Channel channel, Device device) - { - var basePath = source == FwSource.InnovEnergy - ? Program.IeBasePath - : Program.VeBasePath; - - return basePath - .AppendPath("venus") - .AppendPath(channel.GetName()) - .AppendPath("images") - .AppendPath(device.GetName()) + '/'; - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Logger.cs b/csharp/app/VenusFirmwareCiDaemon/src/Logger.cs deleted file mode 100644 index 3e5deaab6..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Logger.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public static class Logger -{ - public static void Log(String s = "") - { - Console.WriteLine($"{DateTime.Now:yyyy'-'MM'-'dd' 'HH':'mm':'ss} {s}"); - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Program.cs b/csharp/app/VenusFirmwareCiDaemon/src/Program.cs deleted file mode 100644 index 4d2803902..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Program.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System.Reactive.Concurrency; -using System.Reactive.Linq; -using System.Reactive.Subjects; -using System.Text.RegularExpressions; -using CliWrap; -using InnovEnergy.Lib.Utils; -using static InnovEnergy.Server.FirmwareCiDaemon.Logger; -using static InnovEnergy.Server.FirmwareCiDaemon.ExitException; - -namespace InnovEnergy.Server.FirmwareCiDaemon; -// dotnet publish FirmwareCiDaemon.csproj -c Release -r linux-x64 -p:PublishSingleFile=true --self-contained true && scp ./bin/Release/netcoreapp5.0/linux-x64/publish/FirmwareCiDaemon ig@salidomo.innovenergy.ch:/home/ig/firmware - -public static class Program -{ - - // use the following scheduler to run everything on a single thread - // Fossil cannot deal with the async introduced by multiple threads/tasks - private static readonly IScheduler Scheduler = new EventLoopScheduler();//NewThreadScheduler(); - - private static readonly IEnumerable SupportedDevices = Enum.GetValues(); - private static readonly IEnumerable Branches = Enum.GetValues(); - - public static String IeBasePath { get; set; } - public static String VeBasePath => "https://updates.victronenergy.com/feeds/"; - - public static void Main(String[] args) - { - try - { - Run(args); - } - catch (Exception e) - { - PrintExceptionAndExit(e); - } - //Environment.Exit(0); - } - - // runcmd: program - - private static void Run(String[] args) - { - if (!IsRoot) Exit("This program must be run as root"); - - Fossil.FossilFile = ParseFossilFileArg(args); // TODO: get rid of global vars? - Fossil.FossilUser = ParseFossilUserArg(args); - IeBasePath = ParseIePublishDirArg(args); - - var veVersions = SupportedDevices.Select(ObserveVeVersion).ToList(); - var branches = Branches.Select(ObserveFossilBranch).ToList(); - - var buildInfos = from veVersion in veVersions - from branch in branches - select Observable.CombineLatest(branch, veVersion, Build.Prepare); - - buildInfos.Merge() - .ObserveOn(Scheduler) // fossil is not thread safe! - .Subscribe(build => build.Execute(), PrintExceptionAndExit); - - foreach (var veVersion in veVersions) - veVersion.Connect(); - - foreach (var branch in branches) - branch.Connect(); - - while (true) Console.ReadLine(); - - // ReSharper disable once FunctionNeverReturns - } - - private static IConnectableObservable ObserveFossilBranch(Branch branch) - { - return Observable - .Interval(TimeSpan.FromMinutes(1)) - .StartWith(0) - .ObserveOn(Scheduler) // fossil is not thread safe! - .Select(_ => Fossil.GetLatestCommitInfo(branch)) - .DistinctUntilChanged() - .Do(c => Log($"Found new commit '{c.Comment}' on branch {c.Branch} ({c.Hash[..6]})")) - .Publish(); - } - - private static IConnectableObservable<(Device device, String veVersion)> ObserveVeVersion(Device device) - { - return Observable - .Interval(TimeSpan.FromHours(1)) - .StartWith(0) - .Select(_ => device) - .Select(GetLatestVictronVersion) - .DistinctUntilChanged() - .Select(veVersion => (device, veVersion)) - .Do(vd => Log($"Found new Victron version '{vd.veVersion}' for {vd.device}")) - .Publish(); - } - - public static String GetLatestVictronVersion(Device device) - { - var url = FwSource.Victron.GetDirectory(Channel.Release, device); - - var curl = Cli - .Wrap("curl") - .WithArguments(url) - .ExecuteSync() - .stdOut; - - var deviceName = device.GetName(); - var swuName = device.SwuName(); - - const String timeStampPattern = "[0-9]{14}"; - const String releasePattern = @"v[0-9]+\.[0-9]+"; - const String extension = ".swu"; - const String extensionPattern = @"\" + extension; // escape . - - var rxVersion = new Regex($"{swuName}-{deviceName}-{timeStampPattern}-{releasePattern}{extensionPattern}"); - - return rxVersion - .Matches(curl) - .Select(m => m.Value) - .OrderBy(m => m) - .Last() - .Split("-") - .Last() - .RemoveSuffix(extension); - } - - private static Boolean IsRoot - { - get - { - var (exitCode, stdOut, stdErr) = Cli - .Wrap("id") - .WithArguments("-u") - .ExecuteSync(); - - return exitCode == 0 && - stdOut.Trim() == "0" && - String.IsNullOrWhiteSpace(stdErr); - } - } - - - private static String ParseFossilFileArg(IReadOnlyList args) - { - if (args.Count < 1) - Exit("Missing argument "); - - var fossilFile = Path.GetFullPath(args[0]); - - if (!FileSystem.Local.FileExists(fossilFile)) - Exit($"Cannot find fossil file {fossilFile}"); - - return fossilFile; - } - - private static String ParseIePublishDirArg(IReadOnlyList args) - { - if (args.Count < 2) - Exit("Missing argument "); - - var iePublishDir = Path.GetFullPath(args[1]); - - if (!FileSystem.Local.DirectoryExists(iePublishDir)) - Exit($"Cannot find directory {iePublishDir}"); - - return iePublishDir; - } - - private static String ParseFossilUserArg(IReadOnlyList args) - { - if (args.Count < 3) - Exit("Missing argument "); - - return args[2]; - } - - private static void PrintExceptionAndExit(Exception e) - { - if (!String.IsNullOrWhiteSpace(e.Message)) - { - Console.WriteLine(); - - var color = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; - Log(e.Message); - Console.ForegroundColor = color; - } - - if (!String.IsNullOrWhiteSpace(e.StackTrace)) - Log(e.StackTrace); - - Environment.Exit(1); - } -} \ No newline at end of file diff --git a/csharp/app/VenusFirmwareCiDaemon/src/Zip.cs b/csharp/app/VenusFirmwareCiDaemon/src/Zip.cs deleted file mode 100644 index 49f3f8acc..000000000 --- a/csharp/app/VenusFirmwareCiDaemon/src/Zip.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CliWrap; -using static InnovEnergy.Server.FirmwareCiDaemon.Logger; -using static InnovEnergy.Server.FirmwareCiDaemon.ExitException; - -namespace InnovEnergy.Server.FirmwareCiDaemon; - -public static class Zip -{ - public static void RemoveFromZip(this String zipFilePath, String zipInternalPathGlob) - { - var zip = Cli - .Wrap("zip") - .WithArguments($"-q -d {zipFilePath} {zipInternalPathGlob}") - .ExecuteSync(); - - if (zip.exitCode != 0) - Log($"Warning: failed to remove {zipInternalPathGlob} from {zipFilePath}"); - } - - public static void AddToZip(this String zipFilePath, String filePath) - { - var zip = Cli - .Wrap("zip") - .WithArguments($"-q -j {zipFilePath} {filePath}") - .ExecuteSync(); - - if (zip.exitCode != 0) - Exit($"failed to add {filePath} to {zipFilePath}"); - } - - public static void GZip(this String sourceFile, String targetGzFile) - { - // TODO: datetime log - - Log($"compressing {Path.GetFileName(sourceFile)}"); - - var gzip = Cli - .Wrap("gzip") - .WithArguments($"-c {sourceFile}") - .PipeToFile(targetGzFile); - - if (gzip.exitCode != 0) - Exit($"Failed to gzip {sourceFile}"); - } -} \ No newline at end of file