diff --git a/Creator/ApplicationArguments.cs b/Creator/ApplicationArguments.cs index 9887437..de8e933 100644 --- a/Creator/ApplicationArguments.cs +++ b/Creator/ApplicationArguments.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.ComponentModel; using System.IO; diff --git a/Katteker.Test/testdata/squirrelHelperInfo.json b/Katteker.Test/testdata/squirrelHelperInfo.json index d1428ad..9e26dfe 100644 --- a/Katteker.Test/testdata/squirrelHelperInfo.json +++ b/Katteker.Test/testdata/squirrelHelperInfo.json @@ -1,6 +1 @@ - - - - - - +{} \ No newline at end of file diff --git a/Katteker/Katteker.csproj b/Katteker/Katteker.csproj index 6666e5f..4aa8f77 100644 --- a/Katteker/Katteker.csproj +++ b/Katteker/Katteker.csproj @@ -43,6 +43,7 @@ + diff --git a/Katteker/KattekerUpdateException.cs b/Katteker/KattekerUpdateException.cs new file mode 100644 index 0000000..5e383fb --- /dev/null +++ b/Katteker/KattekerUpdateException.cs @@ -0,0 +1,24 @@ +using System; + +namespace Katteker +{ + /// + /// Represent an error message in the Katteker update process. + /// + public class KattekerUpdateException : Exception + { + /// + /// Creates a new instance of the class with the error message. + /// + public KattekerUpdateException(string message) : base(message) + { + } + + /// + /// Creates a new instance of the with the error message and inner exception. + /// + public KattekerUpdateException(string message, Exception innerException) : base(message, innerException) + { + } + } +} \ No newline at end of file diff --git a/Katteker/ReleaseEntry.cs b/Katteker/ReleaseEntry.cs index 1797cae..4c9e687 100644 --- a/Katteker/ReleaseEntry.cs +++ b/Katteker/ReleaseEntry.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; namespace Katteker { + /// /// /// Entry of a Release. /// @@ -16,7 +17,7 @@ namespace Katteker private const char Seperator = '|'; /// - /// Construct a new release entry. + /// Creat an instance of . /// public ReleaseEntry(string filename, SemVersion version, long fileSize, bool isDelta, string sha1) { @@ -28,18 +29,25 @@ namespace Katteker } /// - /// Construct release entry from string. + /// Create an instance of from string. /// - /// + /// Argument 'line' has not the right format. + /// Argument 'line' is null. + /// Filename is not compliant. public ReleaseEntry(string line) { - var elements = line?.Split(Seperator); - if (elements?.Length != 3) return; + if (line == null) throw new ArgumentNullException(nameof(line)); + var elements = line.Split(Seperator); + if (elements.Length != 3) + { + throw new ArgumentOutOfRangeException(nameof(line), elements.Length, "The release entry has not the right format."); + } + SHA1 = elements[0]; Filename = elements[1]; Filesize = long.Parse(elements[2]); var fileSegments = Regex.Match(Filename, FilenameRegex); - if (fileSegments.Groups.Count < 3) throw new FileLoadException("Filename not compilant."); + if (fileSegments.Groups.Count < 3) throw new FileLoadException("Filename is not compilant."); ApplicationName = fileSegments.Groups[1].Value; Version = SemVersion.Parse(fileSegments.Groups[2].Value); IsDelta = fileSegments.Groups[3].Value != "full"; diff --git a/Katteker/Releases.cs b/Katteker/Releases.cs index 668274b..3019011 100644 --- a/Katteker/Releases.cs +++ b/Katteker/Releases.cs @@ -13,11 +13,11 @@ namespace Katteker { private readonly string _filePath; - private SortedList ReleaseEntries { get; } + private SortedDictionary ReleaseEntries { get; } private Releases() { - ReleaseEntries = new SortedList(); + ReleaseEntries = new SortedDictionary(); } /// @@ -52,7 +52,7 @@ namespace Katteker /// public void WriteReleaseFile() { - File.WriteAllLines(_filePath, ReleaseEntries.Select(x => x.Value.EntryAsString)); + File.WriteAllLines(_filePath, ReleaseEntries.Values.Select(x => x.EntryAsString)); } /// @@ -67,16 +67,8 @@ namespace Katteker var setupFile = new FileInfo(setupFilePath); var entry = new ReleaseEntry(setupFile.Name, version, setupFile.Length, false, sha1); - if (!ReleaseEntries.ContainsValue(entry)) - { - if (ReleaseEntries.ContainsKey(version)) - { - ReleaseEntries.Remove(version); - } - - ReleaseEntries.Add(version, entry); - } - + if (ReleaseEntries.ContainsValue(entry)) return entry; + ReleaseEntries[version] = entry; return entry; } diff --git a/Katteker/UpdateManager.cs b/Katteker/UpdateManager.cs index 43795e6..d0cf4a9 100644 --- a/Katteker/UpdateManager.cs +++ b/Katteker/UpdateManager.cs @@ -20,12 +20,11 @@ namespace Katteker private readonly string _applicationName; private readonly string _packageDir; private readonly string _rootAppDirectory; - private readonly string _urlOrPath; private Releases _releases; private UpdateManager(string urlOrPath, string applicationName, string rootDirectory) { - _urlOrPath = urlOrPath; + UrlOrPath = urlOrPath; _applicationName = applicationName; _rootAppDirectory = rootDirectory; var packageDir = Path.Combine(rootDirectory, Constants.PackageFolder); @@ -41,7 +40,7 @@ namespace Katteker /// /// Url or path where the update files are located. /// - public string UrlOrPath => _urlOrPath; + public string UrlOrPath { get; } /// /// Create the update manager. @@ -50,7 +49,8 @@ namespace Katteker /// name of the application to update. /// root directory. /// the update manager. - public static UpdateManager Create(string urlOrPath = null, string applicationName = null, string rootDirectory = null) + public static UpdateManager Create(string urlOrPath = null, string applicationName = null, + string rootDirectory = null) { _config = ReadConfigFile(); urlOrPath = urlOrPath ?? _config.Publish; @@ -67,7 +67,8 @@ namespace Katteker /// name of the application to update. /// root directory. /// true if the creation success, false otherwise. - public static bool TryCreate(out UpdateManager manager, string urlOrPath = null, string applicationName = null, string rootDirectory = null) + public static bool TryCreate(out UpdateManager manager, string urlOrPath = null, string applicationName = null, + string rootDirectory = null) { try { @@ -87,7 +88,21 @@ namespace Katteker /// public async Task> CheckForUpdateAsync() { - _releases = Utility.IsWebUrl(_urlOrPath) ? await DownloadIndexAsync(_urlOrPath).ConfigureAwait(false) : GetFromFilesystem(_urlOrPath); + try + { + return await CheckForUpdateImplAsync().ConfigureAwait(false); + } + catch (Exception e) + { + throw new KattekerUpdateException("Error at checking for available update.", e); + } + } + + private async Task> CheckForUpdateImplAsync() + { + _releases = Utility.IsWebUrl(UrlOrPath) + ? await DownloadIndexAsync(UrlOrPath).ConfigureAwait(false) + : GetFromFilesystem(UrlOrPath); var updateInfo = new UpdateInfo(_applicationName, _releases); return updateInfo.ReleasesToApply; } @@ -114,12 +129,19 @@ namespace Katteker /// public async Task UpdateAppAsync(IProgress progress = null) { - progress?.Report(0); - var updateEntries = (await CheckForUpdateAsync().ConfigureAwait(false)).ToArray(); - var update = updateEntries.LastOrDefault(); - if (update == null) return false; - progress?.Report(30); - return await UpdateAppImplAsync(update, progress).ConfigureAwait(false); + try + { + progress?.Report(0); + var updateEntries = (await CheckForUpdateAsync().ConfigureAwait(false)).ToArray(); + var update = updateEntries.LastOrDefault(); + if (update == null) return false; + progress?.Report(30); + return await UpdateAppImplAsync(update, progress).ConfigureAwait(false); + } + catch (Exception e) + { + throw new KattekerUpdateException("Error at updating application.", e); + } } private static async Task DownloadIndexAsync(string urlOrPath) @@ -151,11 +173,9 @@ namespace Katteker foreach (var process in Process.GetProcessesByName(_applicationName)) { var path = Path.GetDirectoryName(process.MainModule.FileName); - if (_rootAppDirectory.Equals(path)) - { - process.Kill(); - return Task.Delay(500); - } + if (!_rootAppDirectory.Equals(path)) continue; + process.Kill(); + return Task.Delay(100); } return Task.FromResult(true); @@ -165,42 +185,39 @@ namespace Katteker { var targetFile = Path.Combine(_packageDir, filename); File.Delete(targetFile); - if (Utility.IsWebUrl(_urlOrPath)) + if (Utility.IsWebUrl(UrlOrPath)) { - var url = _urlOrPath.TrimEnd('/'); + var url = UrlOrPath.TrimEnd('/'); url += "/" + filename; await new WebClient().DownloadFileTaskAsync(new Uri(url), targetFile).ConfigureAwait(false); } else { - File.Copy(Path.Combine(_urlOrPath, filename), targetFile); + File.Copy(Path.Combine(UrlOrPath, filename), targetFile); } } private async Task UpdateAppImplAsync(ReleaseEntry lastEntry, IProgress progress) { - + if (lastEntry == null) throw new ArgumentNullException(nameof(lastEntry)); var targetFile = Path.Combine(_packageDir, lastEntry.Filename); //download file. await PutFileInPackageFolderAsync(lastEntry.Filename).ConfigureAwait(false); progress?.Report(60); - if (!VerifyFileChecksum(targetFile, lastEntry.SHA1)) throw new FileLoadException(); + if (!VerifyFileChecksum(targetFile, lastEntry.SHA1)) throw new FileLoadException("Checksum missmatch."); progress?.Report(70); await KillAppStubAsync().ConfigureAwait(false); progress?.Report(80); - using (var updater = new Process()) + using (var updater = Process.Start(targetFile, "/S")) { - updater.StartInfo = new ProcessStartInfo(targetFile, "/S"); - updater.Start(); - updater.WaitForExit(); + updater?.WaitForExit(); } progress?.Report(100); - return true; } } -} +} \ No newline at end of file