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
|
||||
|
||||
namespace Squirrel.Core
|
||||
namespace Squirrel
|
||||
{
|
||||
/*
|
||||
The original bsdiff.c source code (http://www.daemonology.net/bsdiff/) is
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
|
||||
namespace Squirrel.Core
|
||||
namespace Squirrel
|
||||
{
|
||||
internal static class ContentType
|
||||
{
|
||||
@@ -25,16 +25,21 @@ namespace Squirrel.Core
|
||||
k.GetAttribute("Extension").ToLowerInvariant(),
|
||||
k.GetAttribute("ContentType").ToLowerInvariant()));
|
||||
|
||||
elements
|
||||
var toAdd = elements
|
||||
.Where(x => existingTypes.All(t => t.Item2 != x.Item2.ToLowerInvariant()))
|
||||
.Select(element => {
|
||||
var ret = doc.CreateElement(element.Item1, typesElement.NamespaceURI);
|
||||
|
||||
var ext = doc.CreateAttribute("Extension"); ext.Value = element.Item2;
|
||||
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;
|
||||
}).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.RegularExpressions;
|
||||
using Ionic.Zip;
|
||||
using ReactiveUIMicro;
|
||||
using Splat;
|
||||
|
||||
namespace Squirrel.Core
|
||||
namespace Squirrel
|
||||
{
|
||||
public interface IDeltaPackageBuilder
|
||||
{
|
||||
@@ -69,8 +69,9 @@ namespace Squirrel.Core
|
||||
|
||||
var newLibDir = tempInfo.GetDirectories().First(x => x.Name.ToLowerInvariant() == "lib");
|
||||
|
||||
newLibDir.GetAllFilesRecursively()
|
||||
.ForEach(libFile => createDeltaForSingleFile(libFile, tempInfo, baseLibFiles));
|
||||
foreach (var libFile in newLibDir.GetAllFilesRecursively()) {
|
||||
createDeltaForSingleFile(libFile, tempInfo, baseLibFiles);
|
||||
}
|
||||
|
||||
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.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using NuGet;
|
||||
using ReactiveUIMicro;
|
||||
using Squirrel.Core.Extensions;
|
||||
using Splat;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Squirrel.Core
|
||||
namespace Squirrel
|
||||
{
|
||||
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 = fileSystemFactory.GetDirectoryInfo(releasePackagesDir);
|
||||
var packagesDir = new DirectoryInfo(releasePackagesDir);
|
||||
|
||||
// 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()) {
|
||||
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
|
||||
// place
|
||||
var tempFile = fileSystemFactory.CreateTempFile();
|
||||
try {
|
||||
if (entries.Count > 0) WriteReleaseFile(entries, tempFile.Item2);
|
||||
} finally {
|
||||
tempFile.Item2.Dispose();
|
||||
var entries = entriesQueue.ToList();
|
||||
var tempFile = Path.GetTempFileName();
|
||||
using (var of = File.OpenWrite(tempFile)) {
|
||||
if (entries.Count > 0) WriteReleaseFile(entries, of);
|
||||
}
|
||||
|
||||
var target = Path.Combine(packagesDir.FullName, "RELEASES");
|
||||
@@ -176,7 +175,7 @@ namespace Squirrel.Core
|
||||
File.Delete(target);
|
||||
}
|
||||
|
||||
fileSystemFactory.GetFileInfo(tempFile.Item1).MoveTo(target);
|
||||
File.Move(tempFile, target);
|
||||
}
|
||||
|
||||
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 Ionic.Zip;
|
||||
using NuGet;
|
||||
using ReactiveUIMicro;
|
||||
using Squirrel.Core.Extensions;
|
||||
using Splat;
|
||||
|
||||
namespace Squirrel.Core
|
||||
namespace Squirrel
|
||||
{
|
||||
internal static class FrameworkTargetVersion
|
||||
{
|
||||
|
||||
@@ -4,21 +4,18 @@ using System.ComponentModel;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.IO;
|
||||
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.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using ReactiveUIMicro;
|
||||
using Splat;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Squirrel.Core
|
||||
namespace Squirrel
|
||||
{
|
||||
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(to));
|
||||
@@ -67,11 +64,11 @@ namespace Squirrel.Core
|
||||
Log().Warn("The file {0} does not exist", from);
|
||||
|
||||
// TODO: should we fail this operation?
|
||||
return Observable.Return(Unit.Default);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -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;
|
||||
@@ -147,17 +150,15 @@ namespace Squirrel.Core
|
||||
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));
|
||||
|
||||
scheduler = scheduler ?? RxApp.TaskpoolScheduler;
|
||||
|
||||
Log().Info("Starting to delete folder: {0}", directoryPath);
|
||||
|
||||
if (!Directory.Exists(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
|
||||
@@ -177,23 +178,16 @@ namespace Squirrel.Core
|
||||
Log().Warn(message, ex);
|
||||
}
|
||||
|
||||
var fileOperations = files.MapReduce(file =>
|
||||
Observable.Start(() => {
|
||||
Log().Debug("Now deleting file: {0}", file);
|
||||
var fileOperations = files.ForEachAsync(file => {
|
||||
File.SetAttributes(file, FileAttributes.Normal);
|
||||
File.Delete(file);
|
||||
}, scheduler))
|
||||
.Select(_ => Unit.Default);
|
||||
});
|
||||
|
||||
var directoryOperations =
|
||||
dirs.MapReduce(dir => DeleteDirectory(dir, scheduler)
|
||||
.Retry(3))
|
||||
.Select(_ => Unit.Default);
|
||||
dirs.ForEachAsync(async dir => await DeleteDirectory(dir));
|
||||
|
||||
await Task.WhenAll(fileOperations, directoryOperations);
|
||||
|
||||
return fileOperations
|
||||
.Merge(directoryOperations, scheduler)
|
||||
.ToList() // still feeling a bit icky
|
||||
.Select(_ => {
|
||||
Log().Debug("Now deleting folder: {0}", directoryPath);
|
||||
File.SetAttributes(directoryPath, FileAttributes.Normal);
|
||||
|
||||
@@ -203,8 +197,6 @@ namespace Squirrel.Core
|
||||
var message = String.Format("DeleteDirectory: could not delete - {0}", directoryPath);
|
||||
Log().ErrorException(message, ex);
|
||||
}
|
||||
return Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static Tuple<string, Stream> CreateTempFile()
|
||||
@@ -251,9 +243,11 @@ namespace Squirrel.Core
|
||||
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)]
|
||||
@@ -271,6 +265,7 @@ namespace Squirrel.Core
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public sealed class SingleGlobalInstance : IDisposable
|
||||
{
|
||||
readonly static object gate = 42;
|
||||
@@ -331,4 +326,29 @@ namespace Squirrel.Core
|
||||
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>
|
||||
<package id="Microsoft.Web.Xdt" version="2.1.1" targetFramework="net45" />
|
||||
<package id="NuGet.Core" version="2.8.2" targetFramework="net45" />
|
||||
<package id="Splat" version="1.4.0" targetFramework="net45" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user