Little refactoring and improved error handling.
This commit is contained in:
parent
0ed81d68c8
commit
aa70a24a26
@ -1,4 +1,3 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
@ -1,6 +1 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
{}
|
||||||
<configuration>
|
|
||||||
<startup>
|
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
|
|
||||||
</startup>
|
|
||||||
</configuration>
|
|
@ -43,6 +43,7 @@
|
|||||||
<Compile Include="Constants.cs" />
|
<Compile Include="Constants.cs" />
|
||||||
<Compile Include="KattekerConfig.cs" />
|
<Compile Include="KattekerConfig.cs" />
|
||||||
<Compile Include="Common\MarkdownSharp.cs" />
|
<Compile Include="Common\MarkdownSharp.cs" />
|
||||||
|
<Compile Include="KattekerUpdateException.cs" />
|
||||||
<Compile Include="UpdateInfo.cs" />
|
<Compile Include="UpdateInfo.cs" />
|
||||||
<Compile Include="UpdateManager.cs" />
|
<Compile Include="UpdateManager.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
24
Katteker/KattekerUpdateException.cs
Normal file
24
Katteker/KattekerUpdateException.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Katteker
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represent an error message in the Katteker update process.
|
||||||
|
/// </summary>
|
||||||
|
public class KattekerUpdateException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="KattekerUpdateException"/> class with the error message.
|
||||||
|
/// </summary>
|
||||||
|
public KattekerUpdateException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="KattekerUpdateException"/> with the error message and inner exception.
|
||||||
|
/// </summary>
|
||||||
|
public KattekerUpdateException(string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
|
|||||||
|
|
||||||
namespace Katteker
|
namespace Katteker
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc cref="IComparable" />
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Entry of a Release.
|
/// Entry of a Release.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -16,7 +17,7 @@ namespace Katteker
|
|||||||
private const char Seperator = '|';
|
private const char Seperator = '|';
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a new release entry.
|
/// Creat an instance of <see cref="ReleaseEntry"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReleaseEntry(string filename, SemVersion version, long fileSize, bool isDelta, string sha1)
|
public ReleaseEntry(string filename, SemVersion version, long fileSize, bool isDelta, string sha1)
|
||||||
{
|
{
|
||||||
@ -28,18 +29,25 @@ namespace Katteker
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct release entry from string.
|
/// Create an instance of <see cref="ReleaseEntry"/> from string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="FileLoadException"></exception>
|
/// <exception cref="ArgumentOutOfRangeException">Argument 'line' has not the right format.</exception>
|
||||||
|
/// <exception cref="ArgumentNullException">Argument 'line' is null.</exception>
|
||||||
|
/// <exception cref="FileLoadException">Filename is not compliant.</exception>
|
||||||
public ReleaseEntry(string line)
|
public ReleaseEntry(string line)
|
||||||
{
|
{
|
||||||
var elements = line?.Split(Seperator);
|
if (line == null) throw new ArgumentNullException(nameof(line));
|
||||||
if (elements?.Length != 3) return;
|
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];
|
SHA1 = elements[0];
|
||||||
Filename = elements[1];
|
Filename = elements[1];
|
||||||
Filesize = long.Parse(elements[2]);
|
Filesize = long.Parse(elements[2]);
|
||||||
var fileSegments = Regex.Match(Filename, FilenameRegex);
|
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;
|
ApplicationName = fileSegments.Groups[1].Value;
|
||||||
Version = SemVersion.Parse(fileSegments.Groups[2].Value);
|
Version = SemVersion.Parse(fileSegments.Groups[2].Value);
|
||||||
IsDelta = fileSegments.Groups[3].Value != "full";
|
IsDelta = fileSegments.Groups[3].Value != "full";
|
||||||
|
@ -13,11 +13,11 @@ namespace Katteker
|
|||||||
{
|
{
|
||||||
private readonly string _filePath;
|
private readonly string _filePath;
|
||||||
|
|
||||||
private SortedList<SemVersion, ReleaseEntry> ReleaseEntries { get; }
|
private SortedDictionary<SemVersion, ReleaseEntry> ReleaseEntries { get; }
|
||||||
|
|
||||||
private Releases()
|
private Releases()
|
||||||
{
|
{
|
||||||
ReleaseEntries = new SortedList<SemVersion, ReleaseEntry>();
|
ReleaseEntries = new SortedDictionary<SemVersion, ReleaseEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -52,7 +52,7 @@ namespace Katteker
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void WriteReleaseFile()
|
public void WriteReleaseFile()
|
||||||
{
|
{
|
||||||
File.WriteAllLines(_filePath, ReleaseEntries.Select(x => x.Value.EntryAsString));
|
File.WriteAllLines(_filePath, ReleaseEntries.Values.Select(x => x.EntryAsString));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -67,16 +67,8 @@ namespace Katteker
|
|||||||
var setupFile = new FileInfo(setupFilePath);
|
var setupFile = new FileInfo(setupFilePath);
|
||||||
var entry = new ReleaseEntry(setupFile.Name, version, setupFile.Length, false, sha1);
|
var entry = new ReleaseEntry(setupFile.Name, version, setupFile.Length, false, sha1);
|
||||||
|
|
||||||
if (!ReleaseEntries.ContainsValue(entry))
|
if (ReleaseEntries.ContainsValue(entry)) return entry;
|
||||||
{
|
ReleaseEntries[version] = entry;
|
||||||
if (ReleaseEntries.ContainsKey(version))
|
|
||||||
{
|
|
||||||
ReleaseEntries.Remove(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseEntries.Add(version, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,12 +20,11 @@ namespace Katteker
|
|||||||
private readonly string _applicationName;
|
private readonly string _applicationName;
|
||||||
private readonly string _packageDir;
|
private readonly string _packageDir;
|
||||||
private readonly string _rootAppDirectory;
|
private readonly string _rootAppDirectory;
|
||||||
private readonly string _urlOrPath;
|
|
||||||
private Releases _releases;
|
private Releases _releases;
|
||||||
|
|
||||||
private UpdateManager(string urlOrPath, string applicationName, string rootDirectory)
|
private UpdateManager(string urlOrPath, string applicationName, string rootDirectory)
|
||||||
{
|
{
|
||||||
_urlOrPath = urlOrPath;
|
UrlOrPath = urlOrPath;
|
||||||
_applicationName = applicationName;
|
_applicationName = applicationName;
|
||||||
_rootAppDirectory = rootDirectory;
|
_rootAppDirectory = rootDirectory;
|
||||||
var packageDir = Path.Combine(rootDirectory, Constants.PackageFolder);
|
var packageDir = Path.Combine(rootDirectory, Constants.PackageFolder);
|
||||||
@ -41,7 +40,7 @@ namespace Katteker
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Url or path where the update files are located.
|
/// Url or path where the update files are located.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string UrlOrPath => _urlOrPath;
|
public string UrlOrPath { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create the update manager.
|
/// Create the update manager.
|
||||||
@ -50,7 +49,8 @@ namespace Katteker
|
|||||||
/// <param name="applicationName">name of the application to update.</param>
|
/// <param name="applicationName">name of the application to update.</param>
|
||||||
/// <param name="rootDirectory">root directory.</param>
|
/// <param name="rootDirectory">root directory.</param>
|
||||||
/// <returns>the update manager.</returns>
|
/// <returns>the update manager.</returns>
|
||||||
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();
|
_config = ReadConfigFile();
|
||||||
urlOrPath = urlOrPath ?? _config.Publish;
|
urlOrPath = urlOrPath ?? _config.Publish;
|
||||||
@ -67,7 +67,8 @@ namespace Katteker
|
|||||||
/// <param name="applicationName">name of the application to update.</param>
|
/// <param name="applicationName">name of the application to update.</param>
|
||||||
/// <param name="rootDirectory">root directory.</param>
|
/// <param name="rootDirectory">root directory.</param>
|
||||||
/// <returns>true if the creation success, false otherwise.</returns>
|
/// <returns>true if the creation success, false otherwise.</returns>
|
||||||
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
|
try
|
||||||
{
|
{
|
||||||
@ -87,7 +88,21 @@ namespace Katteker
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IEnumerable<ReleaseEntry>> CheckForUpdateAsync()
|
public async Task<IEnumerable<ReleaseEntry>> 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<IEnumerable<ReleaseEntry>> CheckForUpdateImplAsync()
|
||||||
|
{
|
||||||
|
_releases = Utility.IsWebUrl(UrlOrPath)
|
||||||
|
? await DownloadIndexAsync(UrlOrPath).ConfigureAwait(false)
|
||||||
|
: GetFromFilesystem(UrlOrPath);
|
||||||
var updateInfo = new UpdateInfo(_applicationName, _releases);
|
var updateInfo = new UpdateInfo(_applicationName, _releases);
|
||||||
return updateInfo.ReleasesToApply;
|
return updateInfo.ReleasesToApply;
|
||||||
}
|
}
|
||||||
@ -114,12 +129,19 @@ namespace Katteker
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<bool> UpdateAppAsync(IProgress<int> progress = null)
|
public async Task<bool> UpdateAppAsync(IProgress<int> progress = null)
|
||||||
{
|
{
|
||||||
progress?.Report(0);
|
try
|
||||||
var updateEntries = (await CheckForUpdateAsync().ConfigureAwait(false)).ToArray();
|
{
|
||||||
var update = updateEntries.LastOrDefault();
|
progress?.Report(0);
|
||||||
if (update == null) return false;
|
var updateEntries = (await CheckForUpdateAsync().ConfigureAwait(false)).ToArray();
|
||||||
progress?.Report(30);
|
var update = updateEntries.LastOrDefault();
|
||||||
return await UpdateAppImplAsync(update, progress).ConfigureAwait(false);
|
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<Releases> DownloadIndexAsync(string urlOrPath)
|
private static async Task<Releases> DownloadIndexAsync(string urlOrPath)
|
||||||
@ -151,11 +173,9 @@ namespace Katteker
|
|||||||
foreach (var process in Process.GetProcessesByName(_applicationName))
|
foreach (var process in Process.GetProcessesByName(_applicationName))
|
||||||
{
|
{
|
||||||
var path = Path.GetDirectoryName(process.MainModule.FileName);
|
var path = Path.GetDirectoryName(process.MainModule.FileName);
|
||||||
if (_rootAppDirectory.Equals(path))
|
if (!_rootAppDirectory.Equals(path)) continue;
|
||||||
{
|
process.Kill();
|
||||||
process.Kill();
|
return Task.Delay(100);
|
||||||
return Task.Delay(500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
@ -165,41 +185,38 @@ namespace Katteker
|
|||||||
{
|
{
|
||||||
var targetFile = Path.Combine(_packageDir, filename);
|
var targetFile = Path.Combine(_packageDir, filename);
|
||||||
File.Delete(targetFile);
|
File.Delete(targetFile);
|
||||||
if (Utility.IsWebUrl(_urlOrPath))
|
if (Utility.IsWebUrl(UrlOrPath))
|
||||||
{
|
{
|
||||||
var url = _urlOrPath.TrimEnd('/');
|
var url = UrlOrPath.TrimEnd('/');
|
||||||
url += "/" + filename;
|
url += "/" + filename;
|
||||||
await new WebClient().DownloadFileTaskAsync(new Uri(url), targetFile).ConfigureAwait(false);
|
await new WebClient().DownloadFileTaskAsync(new Uri(url), targetFile).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
File.Copy(Path.Combine(_urlOrPath, filename), targetFile);
|
File.Copy(Path.Combine(UrlOrPath, filename), targetFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> UpdateAppImplAsync(ReleaseEntry lastEntry, IProgress<int> progress)
|
private async Task<bool> UpdateAppImplAsync(ReleaseEntry lastEntry, IProgress<int> progress)
|
||||||
{
|
{
|
||||||
|
if (lastEntry == null) throw new ArgumentNullException(nameof(lastEntry));
|
||||||
var targetFile = Path.Combine(_packageDir, lastEntry.Filename);
|
var targetFile = Path.Combine(_packageDir, lastEntry.Filename);
|
||||||
//download file.
|
//download file.
|
||||||
await PutFileInPackageFolderAsync(lastEntry.Filename).ConfigureAwait(false);
|
await PutFileInPackageFolderAsync(lastEntry.Filename).ConfigureAwait(false);
|
||||||
progress?.Report(60);
|
progress?.Report(60);
|
||||||
|
|
||||||
if (!VerifyFileChecksum(targetFile, lastEntry.SHA1)) throw new FileLoadException();
|
if (!VerifyFileChecksum(targetFile, lastEntry.SHA1)) throw new FileLoadException("Checksum missmatch.");
|
||||||
progress?.Report(70);
|
progress?.Report(70);
|
||||||
|
|
||||||
await KillAppStubAsync().ConfigureAwait(false);
|
await KillAppStubAsync().ConfigureAwait(false);
|
||||||
progress?.Report(80);
|
progress?.Report(80);
|
||||||
|
|
||||||
using (var updater = new Process())
|
using (var updater = Process.Start(targetFile, "/S"))
|
||||||
{
|
{
|
||||||
updater.StartInfo = new ProcessStartInfo(targetFile, "/S");
|
updater?.WaitForExit();
|
||||||
updater.Start();
|
|
||||||
updater.WaitForExit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progress?.Report(100);
|
progress?.Report(100);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user