mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Cut up Core into something we can use
This commit is contained in:
BIN
ext/Ionic.Zip.dll
Normal file
BIN
ext/Ionic.Zip.dll
Normal file
Binary file not shown.
18151
ext/Ionic.Zip.xml
Normal file
18151
ext/Ionic.Zip.xml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ using Ionic.BZip2;
|
|||||||
|
|
||||||
// Adapted from https://github.com/LogosBible/bsdiff.net/blob/master/src/bsdiff/BinaryPatchUtility.cs
|
// Adapted from https://github.com/LogosBible/bsdiff.net/blob/master/src/bsdiff/BinaryPatchUtility.cs
|
||||||
|
|
||||||
namespace Squirrel.Core
|
namespace Squirrel
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
The original bsdiff.c source code (http://www.daemonology.net/bsdiff/) is
|
The original bsdiff.c source code (http://www.daemonology.net/bsdiff/) is
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
|
||||||
namespace Squirrel.Core
|
namespace Squirrel
|
||||||
{
|
{
|
||||||
internal static class ContentType
|
internal static class ContentType
|
||||||
{
|
{
|
||||||
@@ -25,16 +25,21 @@ namespace Squirrel.Core
|
|||||||
k.GetAttribute("Extension").ToLowerInvariant(),
|
k.GetAttribute("Extension").ToLowerInvariant(),
|
||||||
k.GetAttribute("ContentType").ToLowerInvariant()));
|
k.GetAttribute("ContentType").ToLowerInvariant()));
|
||||||
|
|
||||||
elements
|
var toAdd = elements
|
||||||
.Where(x => existingTypes.All(t => t.Item2 != x.Item2.ToLowerInvariant()))
|
.Where(x => existingTypes.All(t => t.Item2 != x.Item2.ToLowerInvariant()))
|
||||||
.Select(element => {
|
.Select(element => {
|
||||||
var ret = doc.CreateElement(element.Item1, typesElement.NamespaceURI);
|
var ret = doc.CreateElement(element.Item1, typesElement.NamespaceURI);
|
||||||
|
|
||||||
var ext = doc.CreateAttribute("Extension"); ext.Value = element.Item2;
|
var ext = doc.CreateAttribute("Extension"); ext.Value = element.Item2;
|
||||||
var ct = doc.CreateAttribute("ContentType"); ct.Value = element.Item3;
|
var ct = doc.CreateAttribute("ContentType"); ct.Value = element.Item3;
|
||||||
new[] { ext, ct }.ForEach(x => ret.Attributes.Append(x));
|
|
||||||
|
ret.Attributes.Append(ext);
|
||||||
|
ret.Attributes.Append(ct);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}).ForEach(x => typesElement.AppendChild(x));
|
});
|
||||||
|
|
||||||
|
foreach (var v in toAdd) typesElement.AppendChild(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Ionic.Zip;
|
using Ionic.Zip;
|
||||||
using ReactiveUIMicro;
|
using Splat;
|
||||||
|
|
||||||
namespace Squirrel.Core
|
namespace Squirrel
|
||||||
{
|
{
|
||||||
public interface IDeltaPackageBuilder
|
public interface IDeltaPackageBuilder
|
||||||
{
|
{
|
||||||
@@ -69,8 +69,9 @@ namespace Squirrel.Core
|
|||||||
|
|
||||||
var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == "lib");
|
var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == "lib");
|
||||||
|
|
||||||
newLibDir.GetAllFilesRecursively()
|
foreach (var libFile in newLibDir.GetAllFilesRecursively()) {
|
||||||
.ForEach(libFile => createDeltaForSingleFile(libFile, tempInfo, baseLibFiles));
|
createDeltaForSingleFile(libFile, tempInfo, baseLibFiles);
|
||||||
|
}
|
||||||
|
|
||||||
ReleasePackage.addDeltaFilesToContentTypes(tempInfo.FullName);
|
ReleasePackage.addDeltaFilesToContentTypes(tempInfo.FullName);
|
||||||
|
|
||||||
|
|||||||
281
src/EnumerableExtensions.cs
Normal file
281
src/EnumerableExtensions.cs
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace System.Linq
|
||||||
|
{
|
||||||
|
internal static class EnumerableExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates the sequence and invokes the given action for each value in the sequence.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="onNext">Action to invoke for each element.</param>
|
||||||
|
public static void ForEach<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (onNext == null)
|
||||||
|
throw new ArgumentNullException("onNext");
|
||||||
|
|
||||||
|
foreach (var item in source) onNext(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the elements with the maximum key value by using the default comparer to compare key values.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <typeparam name="TKey">Key type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
|
||||||
|
/// <returns>List with the elements that share the same maximum key value.</returns>
|
||||||
|
public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (keySelector == null)
|
||||||
|
throw new ArgumentNullException("keySelector");
|
||||||
|
|
||||||
|
return MaxBy(source, keySelector, Comparer<TKey>.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the elements with the minimum key value by using the specified comparer to compare key values.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <typeparam name="TKey">Key type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
|
||||||
|
/// <param name="comparer">Comparer used to determine the maximum key value.</param>
|
||||||
|
/// <returns>List with the elements that share the same maximum key value.</returns>
|
||||||
|
public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (keySelector == null)
|
||||||
|
throw new ArgumentNullException("keySelector");
|
||||||
|
if (comparer == null)
|
||||||
|
throw new ArgumentNullException("comparer");
|
||||||
|
|
||||||
|
return ExtremaBy(source, keySelector, (key, minValue) => comparer.Compare(key, minValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IList<TSource> ExtremaBy<TSource, TKey>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, TKey, int> compare)
|
||||||
|
{
|
||||||
|
var result = new List<TSource>();
|
||||||
|
|
||||||
|
using (var e = source.GetEnumerator())
|
||||||
|
{
|
||||||
|
if (!e.MoveNext())
|
||||||
|
throw new InvalidOperationException("Source sequence doesn't contain any elements.");
|
||||||
|
|
||||||
|
var current = e.Current;
|
||||||
|
var resKey = keySelector(current);
|
||||||
|
result.Add(current);
|
||||||
|
|
||||||
|
while (e.MoveNext())
|
||||||
|
{
|
||||||
|
var cur = e.Current;
|
||||||
|
var key = keySelector(cur);
|
||||||
|
|
||||||
|
var cmp = compare(key, resKey);
|
||||||
|
if (cmp == 0)
|
||||||
|
{
|
||||||
|
result.Add(cur);
|
||||||
|
}
|
||||||
|
else if (cmp > 0)
|
||||||
|
{
|
||||||
|
result = new List<TSource> { cur };
|
||||||
|
resKey = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lazily invokes an action for each value in the sequence.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="onNext">Action to invoke for each element.</param>
|
||||||
|
/// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
|
||||||
|
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (onNext == null)
|
||||||
|
throw new ArgumentNullException("onNext");
|
||||||
|
|
||||||
|
return DoHelper(source, onNext, _ => { }, () => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lazily invokes an action for each value in the sequence, and executes an action for successful termination.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="onNext">Action to invoke for each element.</param>
|
||||||
|
/// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
|
||||||
|
/// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
|
||||||
|
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (onNext == null)
|
||||||
|
throw new ArgumentNullException("onNext");
|
||||||
|
if (onCompleted == null)
|
||||||
|
throw new ArgumentNullException("onCompleted");
|
||||||
|
|
||||||
|
return DoHelper(source, onNext, _ => { }, onCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lazily invokes an action for each value in the sequence, and executes an action upon exceptional termination.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="onNext">Action to invoke for each element.</param>
|
||||||
|
/// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
|
||||||
|
/// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
|
||||||
|
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (onNext == null)
|
||||||
|
throw new ArgumentNullException("onNext");
|
||||||
|
if (onError == null)
|
||||||
|
throw new ArgumentNullException("onError");
|
||||||
|
|
||||||
|
return DoHelper(source, onNext, onError, () => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lazily invokes an action for each value in the sequence, and executes an action upon successful or exceptional termination.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="onNext">Action to invoke for each element.</param>
|
||||||
|
/// <param name="onError">Action to invoke on exceptional termination of the sequence.</param>
|
||||||
|
/// <param name="onCompleted">Action to invoke on successful termination of the sequence.</param>
|
||||||
|
/// <returns>Sequence exhibiting the specified side-effects upon enumeration.</returns>
|
||||||
|
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (onNext == null)
|
||||||
|
throw new ArgumentNullException("onNext");
|
||||||
|
if (onError == null)
|
||||||
|
throw new ArgumentNullException("onError");
|
||||||
|
if (onCompleted == null)
|
||||||
|
throw new ArgumentNullException("onCompleted");
|
||||||
|
|
||||||
|
return DoHelper(source, onNext, onError, onCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TSource> DoHelper<TSource>(this IEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted)
|
||||||
|
{
|
||||||
|
using (var e = source.GetEnumerator())
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var current = default(TSource);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!e.MoveNext())
|
||||||
|
break;
|
||||||
|
|
||||||
|
current = e.Current;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
onError(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
onNext(current);
|
||||||
|
yield return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
onCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the source sequence prefixed with the specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="values">Values to prefix the sequence with.</param>
|
||||||
|
/// <returns>Sequence starting with the specified prefix value, followed by the source sequence.</returns>
|
||||||
|
public static IEnumerable<TSource> StartWith<TSource>(this IEnumerable<TSource> source, params TSource[] values)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
|
||||||
|
return source.StartWith_(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IEnumerable<TSource> StartWith_<TSource>(this IEnumerable<TSource> source, params TSource[] values)
|
||||||
|
{
|
||||||
|
foreach (var x in values)
|
||||||
|
yield return x;
|
||||||
|
|
||||||
|
foreach (var item in source)
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns elements with a distinct key value by using the default equality comparer to compare key values.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <typeparam name="TKey">Key type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="keySelector">Key selector.</param>
|
||||||
|
/// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>
|
||||||
|
public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (keySelector == null)
|
||||||
|
throw new ArgumentNullException("keySelector");
|
||||||
|
|
||||||
|
return source.Distinct_(keySelector, EqualityComparer<TKey>.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns elements with a distinct key value by using the specified equality comparer to compare key values.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSource">Source sequence element type.</typeparam>
|
||||||
|
/// <typeparam name="TKey">Key type.</typeparam>
|
||||||
|
/// <param name="source">Source sequence.</param>
|
||||||
|
/// <param name="keySelector">Key selector.</param>
|
||||||
|
/// <param name="comparer">Comparer used to compare key values.</param>
|
||||||
|
/// <returns>Sequence that contains the elements from the source sequence with distinct key values.</returns>
|
||||||
|
public static IEnumerable<TSource> Distinct<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||||
|
{
|
||||||
|
if (source == null)
|
||||||
|
throw new ArgumentNullException("source");
|
||||||
|
if (keySelector == null)
|
||||||
|
throw new ArgumentNullException("keySelector");
|
||||||
|
if (comparer == null)
|
||||||
|
throw new ArgumentNullException("comparer");
|
||||||
|
|
||||||
|
return source.Distinct_(keySelector, comparer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static IEnumerable<TSource> Distinct_<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
||||||
|
{
|
||||||
|
var set = new HashSet<TKey>(comparer);
|
||||||
|
|
||||||
|
foreach (var item in source)
|
||||||
|
{
|
||||||
|
var key = keySelector(item);
|
||||||
|
if (set.Add(key))
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/PackageExtensions.cs
Normal file
17
src/PackageExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using NuGet;
|
||||||
|
|
||||||
|
namespace Squirrel
|
||||||
|
{
|
||||||
|
public static class PackageExtensions
|
||||||
|
{
|
||||||
|
public static string ExtractTitle(this IPackage package)
|
||||||
|
{
|
||||||
|
if (package == null)
|
||||||
|
return String.Empty;
|
||||||
|
|
||||||
|
var title = package.Title;
|
||||||
|
return !String.IsNullOrWhiteSpace(title) ? title : package.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,15 +3,15 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using NuGet;
|
using NuGet;
|
||||||
using ReactiveUIMicro;
|
using Splat;
|
||||||
using Squirrel.Core.Extensions;
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace Squirrel.Core
|
namespace Squirrel
|
||||||
{
|
{
|
||||||
public interface IReleaseEntry
|
public interface IReleaseEntry
|
||||||
{
|
{
|
||||||
@@ -150,25 +150,24 @@ namespace Squirrel.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void BuildReleasesFile(string releasePackagesDir, IFileSystemFactory fileSystemFactory = null)
|
public static void BuildReleasesFile(string releasePackagesDir)
|
||||||
{
|
{
|
||||||
fileSystemFactory = fileSystemFactory ?? AnonFileSystem.Default;
|
var packagesDir = new DirectoryInfo(releasePackagesDir);
|
||||||
var packagesDir = fileSystemFactory.GetDirectoryInfo(releasePackagesDir);
|
|
||||||
|
|
||||||
// Generate release entries for all of the local packages
|
// Generate release entries for all of the local packages
|
||||||
var entries = packagesDir.GetFiles("*.nupkg").MapReduce(x => Observable.Start(() => {
|
var entriesQueue = new ConcurrentQueue<ReleaseEntry>();
|
||||||
|
Parallel.ForEach(packagesDir.GetFiles("*.nupkg"), x => {
|
||||||
using (var file = x.OpenRead()) {
|
using (var file = x.OpenRead()) {
|
||||||
return GenerateFromFile(file, x.Name);
|
entriesQueue.Enqueue(GenerateFromFile(file, x.Name));
|
||||||
}
|
}
|
||||||
}, RxApp.TaskpoolScheduler)).First();
|
});
|
||||||
|
|
||||||
// Write the new RELEASES file to a temp file then move it into
|
// Write the new RELEASES file to a temp file then move it into
|
||||||
// place
|
// place
|
||||||
var tempFile = fileSystemFactory.CreateTempFile();
|
var entries = entriesQueue.ToList();
|
||||||
try {
|
var tempFile = Path.GetTempFileName();
|
||||||
if (entries.Count > 0) WriteReleaseFile(entries, tempFile.Item2);
|
using (var of = File.OpenWrite(tempFile)) {
|
||||||
} finally {
|
if (entries.Count > 0) WriteReleaseFile(entries, of);
|
||||||
tempFile.Item2.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var target = Path.Combine(packagesDir.FullName, "RELEASES");
|
var target = Path.Combine(packagesDir.FullName, "RELEASES");
|
||||||
@@ -176,7 +175,7 @@ namespace Squirrel.Core
|
|||||||
File.Delete(target);
|
File.Delete(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
fileSystemFactory.GetFileInfo(tempFile.Item1).MoveTo(target);
|
File.Move(tempFile, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool filenameIsDeltaFile(string filename)
|
static bool filenameIsDeltaFile(string filename)
|
||||||
|
|||||||
49
src/ReleaseExtensions.cs
Normal file
49
src/ReleaseExtensions.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Squirrel
|
||||||
|
{
|
||||||
|
public static class VersionExtensions
|
||||||
|
{
|
||||||
|
public static Version ToVersion(this IReleasePackage package)
|
||||||
|
{
|
||||||
|
return package.InputPackageFile.ToVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Version ToVersion(this string fileName)
|
||||||
|
{
|
||||||
|
var parts = (new FileInfo(fileName)).Name
|
||||||
|
.Replace(".nupkg", "").Replace("-delta", "")
|
||||||
|
.Split('.', '-').Reverse();
|
||||||
|
|
||||||
|
var numberRegex = new Regex(@"^\d+$");
|
||||||
|
|
||||||
|
var versionFields = parts
|
||||||
|
.Where(x => numberRegex.IsMatch(x))
|
||||||
|
.Select(Int32.Parse)
|
||||||
|
.Reverse()
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (versionFields.Length < 2 || versionFields.Length > 4)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (versionFields.Length)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
return new Version(versionFields[0], versionFields[1]);
|
||||||
|
case 3:
|
||||||
|
return new Version(versionFields[0], versionFields[1], versionFields[2]);
|
||||||
|
case 4:
|
||||||
|
return new Version(versionFields[0], versionFields[1], versionFields[2], versionFields[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,10 +11,9 @@ using System.Text.RegularExpressions;
|
|||||||
using System.Xml;
|
using System.Xml;
|
||||||
using Ionic.Zip;
|
using Ionic.Zip;
|
||||||
using NuGet;
|
using NuGet;
|
||||||
using ReactiveUIMicro;
|
using Splat;
|
||||||
using Squirrel.Core.Extensions;
|
|
||||||
|
|
||||||
namespace Squirrel.Core
|
namespace Squirrel
|
||||||
{
|
{
|
||||||
internal static class FrameworkTargetVersion
|
internal static class FrameworkTargetVersion
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,21 +4,18 @@ using System.ComponentModel;
|
|||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive;
|
|
||||||
using System.Reactive.Concurrency;
|
|
||||||
using System.Reactive.Disposables;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using System.Reactive.Subjects;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using ReactiveUIMicro;
|
using Splat;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace Squirrel.Core
|
namespace Squirrel
|
||||||
{
|
{
|
||||||
public static class Utility
|
public static class Utility
|
||||||
{
|
{
|
||||||
@@ -58,7 +55,7 @@ namespace Squirrel.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IObservable<Unit> CopyToAsync(string from, string to)
|
public static async Task CopyToAsync(string from, string to)
|
||||||
{
|
{
|
||||||
Contract.Requires(!String.IsNullOrEmpty(from) && File.Exists(from));
|
Contract.Requires(!String.IsNullOrEmpty(from) && File.Exists(from));
|
||||||
Contract.Requires(!String.IsNullOrEmpty(to));
|
Contract.Requires(!String.IsNullOrEmpty(to));
|
||||||
@@ -67,11 +64,11 @@ namespace Squirrel.Core
|
|||||||
Log().Warn("The file {0} does not exist", from);
|
Log().Warn("The file {0} does not exist", from);
|
||||||
|
|
||||||
// TODO: should we fail this operation?
|
// TODO: should we fail this operation?
|
||||||
return Observable.Return(Unit.Default);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: SafeCopy
|
// XXX: SafeCopy
|
||||||
return Observable.Start(() => File.Copy(from, to, true), RxApp.TaskpoolScheduler);
|
await Task.Run(() => File.Copy(from, to, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Retry(this Action block, int retries = 2)
|
public static void Retry(this Action block, int retries = 2)
|
||||||
@@ -105,14 +102,20 @@ namespace Squirrel.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IObservable<IList<TRet>> MapReduce<T, TRet>(this IObservable<T> This, Func<T, IObservable<TRet>> selector, int degreeOfParallelism = 4)
|
public static Task ForEachAsync<T>(this IEnumerable<T> source, Action<T> body, int degreeOfParallelism = 4)
|
||||||
{
|
{
|
||||||
return This.Select(x => Observable.Defer(() => selector(x))).Merge(degreeOfParallelism).ToList();
|
return ForEachAsync(source, x => Task.Run(() => body(x)), degreeOfParallelism);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IObservable<IList<TRet>> MapReduce<T, TRet>(this IEnumerable<T> This, Func<T, IObservable<TRet>> selector, int degreeOfParallelism = 4)
|
public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> body, int degreeOfParallelism = 4)
|
||||||
{
|
{
|
||||||
return This.ToObservable().Select(x => Observable.Defer(() => selector(x))).Merge(degreeOfParallelism).ToList();
|
return Task.WhenAll(
|
||||||
|
from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism)
|
||||||
|
select Task.Run(async () => {
|
||||||
|
using (partition)
|
||||||
|
while (partition.MoveNext())
|
||||||
|
await body(partition.Current);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
static string directoryChars;
|
static string directoryChars;
|
||||||
@@ -147,17 +150,15 @@ namespace Squirrel.Core
|
|||||||
DeleteDirectory(tempDir.FullName).Wait());
|
DeleteDirectory(tempDir.FullName).Wait());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IObservable<Unit> DeleteDirectory(string directoryPath, IScheduler scheduler = null)
|
public static async Task DeleteDirectory(string directoryPath)
|
||||||
{
|
{
|
||||||
Contract.Requires(!String.IsNullOrEmpty(directoryPath));
|
Contract.Requires(!String.IsNullOrEmpty(directoryPath));
|
||||||
|
|
||||||
scheduler = scheduler ?? RxApp.TaskpoolScheduler;
|
|
||||||
|
|
||||||
Log().Info("Starting to delete folder: {0}", directoryPath);
|
Log().Info("Starting to delete folder: {0}", directoryPath);
|
||||||
|
|
||||||
if (!Directory.Exists(directoryPath)) {
|
if (!Directory.Exists(directoryPath)) {
|
||||||
Log().Warn("DeleteDirectory: does not exist - {0}", directoryPath);
|
Log().Warn("DeleteDirectory: does not exist - {0}", directoryPath);
|
||||||
return Observable.Return(Unit.Default);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true/329502#329502
|
// From http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true/329502#329502
|
||||||
@@ -177,23 +178,16 @@ namespace Squirrel.Core
|
|||||||
Log().Warn(message, ex);
|
Log().Warn(message, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileOperations = files.MapReduce(file =>
|
var fileOperations = files.ForEachAsync(file => {
|
||||||
Observable.Start(() => {
|
|
||||||
Log().Debug("Now deleting file: {0}", file);
|
|
||||||
File.SetAttributes(file, FileAttributes.Normal);
|
File.SetAttributes(file, FileAttributes.Normal);
|
||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}, scheduler))
|
});
|
||||||
.Select(_ => Unit.Default);
|
|
||||||
|
|
||||||
var directoryOperations =
|
var directoryOperations =
|
||||||
dirs.MapReduce(dir => DeleteDirectory(dir, scheduler)
|
dirs.ForEachAsync(async dir => await DeleteDirectory(dir));
|
||||||
.Retry(3))
|
|
||||||
.Select(_ => Unit.Default);
|
await Task.WhenAll(fileOperations, directoryOperations);
|
||||||
|
|
||||||
return fileOperations
|
|
||||||
.Merge(directoryOperations, scheduler)
|
|
||||||
.ToList() // still feeling a bit icky
|
|
||||||
.Select(_ => {
|
|
||||||
Log().Debug("Now deleting folder: {0}", directoryPath);
|
Log().Debug("Now deleting folder: {0}", directoryPath);
|
||||||
File.SetAttributes(directoryPath, FileAttributes.Normal);
|
File.SetAttributes(directoryPath, FileAttributes.Normal);
|
||||||
|
|
||||||
@@ -203,8 +197,6 @@ namespace Squirrel.Core
|
|||||||
var message = String.Format("DeleteDirectory: could not delete - {0}", directoryPath);
|
var message = String.Format("DeleteDirectory: could not delete - {0}", directoryPath);
|
||||||
Log().ErrorException(message, ex);
|
Log().ErrorException(message, ex);
|
||||||
}
|
}
|
||||||
return Unit.Default;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Tuple<string, Stream> CreateTempFile()
|
public static Tuple<string, Stream> CreateTempFile()
|
||||||
@@ -251,9 +243,11 @@ namespace Squirrel.Core
|
|||||||
Log().Error("safeDeleteFileAtNextReboot: failed - {0} - {1}", name, lastError);
|
Log().Error("safeDeleteFileAtNextReboot: failed - {0} - {1}", name, lastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
static IRxUIFullLogger Log()
|
static IFullLogger logger;
|
||||||
|
static IFullLogger Log()
|
||||||
{
|
{
|
||||||
return LogManager.GetLogger(typeof(Utility));
|
return logger ??
|
||||||
|
(logger = Locator.CurrentMutable.GetService<ILogManager>().GetLogger(typeof(Utility)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
@@ -271,6 +265,7 @@ namespace Squirrel.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public sealed class SingleGlobalInstance : IDisposable
|
public sealed class SingleGlobalInstance : IDisposable
|
||||||
{
|
{
|
||||||
readonly static object gate = 42;
|
readonly static object gate = 42;
|
||||||
@@ -331,4 +326,29 @@ namespace Squirrel.Core
|
|||||||
lockScheduler.Dispose();
|
lockScheduler.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static class Disposable
|
||||||
|
{
|
||||||
|
public static IDisposable Create(Action action)
|
||||||
|
{
|
||||||
|
return new AnonDisposable(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnonDisposable : IDisposable
|
||||||
|
{
|
||||||
|
static readonly Action dummyBlock = (() => { });
|
||||||
|
Action block;
|
||||||
|
|
||||||
|
public AnonDisposable(Action b)
|
||||||
|
{
|
||||||
|
block = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Interlocked.Exchange(ref block, dummyBlock)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,4 +2,5 @@
|
|||||||
<packages>
|
<packages>
|
||||||
<package id="Microsoft.Web.Xdt" version="2.1.1" targetFramework="net45" />
|
<package id="Microsoft.Web.Xdt" version="2.1.1" targetFramework="net45" />
|
||||||
<package id="NuGet.Core" version="2.8.2" targetFramework="net45" />
|
<package id="NuGet.Core" version="2.8.2" targetFramework="net45" />
|
||||||
|
<package id="Splat" version="1.4.0" targetFramework="net45" />
|
||||||
</packages>
|
</packages>
|
||||||
Reference in New Issue
Block a user