Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
886 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#OS junk files | ||
Thumbs.db | ||
*.DS_Store | ||
|
||
#Visual Studio files | ||
*.obj | ||
*.exe | ||
*.pdb | ||
*.user | ||
*.aps | ||
*.pch | ||
*.vspscc | ||
*.vssscc | ||
*_i.c | ||
*_p.c | ||
*.ncb | ||
*.suo | ||
*.tlb | ||
*.tlh | ||
*.bak | ||
*.cache | ||
*.ilk | ||
*.log* | ||
*.lib | ||
*.sbr | ||
*.sdf | ||
ipch/ | ||
obj/ | ||
[Bb]in | ||
[Dd]ebug*/ | ||
[Rr]elease*/ | ||
|
||
#upgrade from 2010 | ||
Backup/* | ||
_UpgradeReport_Files/* | ||
UpgradeLog.* | ||
|
||
#Tooling | ||
_ReSharper*/ | ||
[Tt]est[Rr]esult* | ||
*.dotCover | ||
|
||
#StyleCop | ||
StyleCop.Cache | ||
|
||
#Project files | ||
[Bb]uild/ | ||
|
||
#Nuget Files | ||
*.nupkg | ||
#MA: using nuget package restore! | ||
packages/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2014 Michael Adelson | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
this software and associated documentation files (the "Software"), to deal in | ||
the Software without restriction, including without limitation the rights to | ||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
the Software, and to permit persons to whom the Software is furnished to do so, | ||
subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Express 2013 for Windows Desktop | ||
VisualStudioVersion = 12.0.21005.1 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MedallionShell", "MedallionShell\MedallionShell.csproj", "{15AF2EC0-F7B2-4206-B92A-DD1F3DC25F30}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{15AF2EC0-F7B2-4206-B92A-DD1F3DC25F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{15AF2EC0-F7B2-4206-B92A-DD1F3DC25F30}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{15AF2EC0-F7B2-4206-B92A-DD1F3DC25F30}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{15AF2EC0-F7B2-4206-B92A-DD1F3DC25F30}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Shell.Async | ||
{ | ||
// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx | ||
internal sealed class AsyncLock | ||
{ | ||
private readonly AsyncSemaphore semaphore = new AsyncSemaphore(initialCount: 1, maxCount: 1); | ||
private readonly Task<Releaser> cachedReleaserTask; | ||
|
||
public AsyncLock() | ||
{ | ||
this.cachedReleaserTask = Task.FromResult(new Releaser(this)); | ||
} | ||
|
||
public Task<Releaser> AcquireAsync() | ||
{ | ||
var wait = this.semaphore.WaitAsync(); | ||
return wait.IsCompleted | ||
? this.cachedReleaserTask | ||
: wait.ContinueWith( | ||
CreateReleaserFunc, | ||
this, | ||
CancellationToken.None, | ||
TaskContinuationOptions.ExecuteSynchronously, | ||
TaskScheduler.Default | ||
); | ||
} | ||
|
||
private static Releaser CreateReleaser(Task ignored, object asyncLock) | ||
{ | ||
return new Releaser((AsyncLock)asyncLock); | ||
} | ||
private static Func<Task, object, Releaser> CreateReleaserFunc = CreateReleaser; | ||
|
||
public struct Releaser : IDisposable | ||
{ | ||
private readonly AsyncLock @lock; | ||
|
||
internal Releaser(AsyncLock @lock) | ||
{ | ||
this.@lock = @lock; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
this.@lock.semaphore.Release(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Shell.Async | ||
{ | ||
// based on http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx | ||
internal sealed class AsyncSemaphore | ||
{ | ||
private static readonly Task CachedCompletedTask = Task.FromResult(true); | ||
private readonly Queue<TaskCompletionSource<bool>> waiters = new Queue<TaskCompletionSource<bool>>(); | ||
private readonly int? maxCount; | ||
private int count; | ||
|
||
public AsyncSemaphore(int initialCount, int? maxCount = null) | ||
{ | ||
Throw.IfOutOfRange(initialCount, "initialCount", min: 0); | ||
if (maxCount.HasValue) | ||
{ | ||
Throw.IfOutOfRange(maxCount.Value, "maxCount", min: 0); | ||
Throw.IfOutOfRange(initialCount, "initialCount", max: maxCount); | ||
this.maxCount = maxCount; | ||
} | ||
this.count = initialCount; | ||
} | ||
|
||
public Task WaitAsync() | ||
{ | ||
lock (this.waiters) | ||
{ | ||
if (this.count > 0) | ||
{ | ||
--this.count; | ||
return CachedCompletedTask; | ||
} | ||
else | ||
{ | ||
var waiter = new TaskCompletionSource<bool>(); | ||
this.waiters.Enqueue(waiter); | ||
return waiter.Task; | ||
} | ||
} | ||
} | ||
|
||
public void Release() | ||
{ | ||
TaskCompletionSource<bool> toRelease = null; | ||
lock (this.waiters) | ||
{ | ||
if (this.waiters.Count > 0) | ||
{ | ||
toRelease = this.waiters.Dequeue(); | ||
} | ||
else if (this.maxCount.HasValue && this.count == this.maxCount) | ||
{ | ||
throw new InvalidOperationException("Max count value exceeded on the semaphore"); | ||
} | ||
else | ||
{ | ||
++this.count; | ||
} | ||
} | ||
if (toRelease != null) | ||
{ | ||
toRelease.SetResult(true); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Shell | ||
{ | ||
public abstract partial class Command | ||
{ | ||
// TODO do we want this in the base class? | ||
public abstract Process Process { get; } | ||
public abstract IReadOnlyList<Process> Processes { get; } | ||
|
||
public abstract Stream StandardInputStream { get; } | ||
public abstract Stream StandardOutputStream { get; } | ||
public abstract Stream StandardErrorStream { get; } | ||
|
||
public abstract Task<CommandResult> Task { get; } | ||
|
||
public Command PipeTo(Command command) | ||
{ | ||
return this | command; | ||
} | ||
|
||
public Command PipeStandardOutputTo(Stream stream) | ||
{ | ||
return this > stream; | ||
} | ||
|
||
public Command PipeStandardErrorTo(Stream stream) | ||
{ | ||
Throw.IfNull(stream, "stream"); | ||
// TODO | ||
return this; | ||
} | ||
|
||
public Command PipeStandardInputFrom(Stream stream) | ||
{ | ||
return this < stream; | ||
} | ||
|
||
#region ---- Operator overloads ---- | ||
public static Command operator |(Command first, Command second) | ||
{ | ||
return new PipedCommand(first, second); | ||
} | ||
|
||
public static Command operator >(Command command, Stream stream) | ||
{ | ||
Throw.IfNull(command, "command"); | ||
Throw.IfNull(stream, "stream"); | ||
|
||
// TODO | ||
|
||
return command; | ||
} | ||
|
||
public static Command operator <(Command command, Stream stream) | ||
{ | ||
Throw.IfNull(command, "command"); | ||
Throw.IfNull(stream, "stream"); | ||
|
||
// TODO | ||
|
||
return command; | ||
} | ||
|
||
public static Command operator >(Command command, string path) | ||
{ | ||
Throw.IfNull(command, "command"); | ||
Throw.IfNull(path, "path"); | ||
|
||
// used over File.OpenWrite to get read file share, which seems potentially useful and | ||
// not that harmful | ||
var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); | ||
return command > stream; | ||
} | ||
|
||
public static Command operator <(Command command, string path) | ||
{ | ||
Throw.IfNull(command, "command"); | ||
Throw.IfNull(path, "path"); | ||
|
||
return command > File.OpenRead(path); | ||
} | ||
|
||
public static bool operator true(Command command) | ||
{ | ||
Throw.IfNull(command, "command"); | ||
|
||
return command.Task.Result.Success; | ||
} | ||
|
||
public static bool operator false(Command command) | ||
{ | ||
Throw.IfNull(command, "command"); | ||
|
||
return !command.Task.Result.Success; | ||
} | ||
|
||
public static Command operator &(Command @this, Command that) | ||
{ | ||
throw new NotSupportedException("Bitwise & is not supported. It exists only to enable '&&'") | ||
} | ||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace Medallion.Shell | ||
{ | ||
public sealed class CommandResult | ||
{ | ||
internal CommandResult(int exitCode) | ||
{ | ||
this.exitCode = exitCode; | ||
} | ||
|
||
private readonly int exitCode; | ||
public int ExitCode { get; } | ||
|
||
/// <summary> | ||
/// Returns true iff the exit code is 0 (indicating success) | ||
/// </summary> | ||
public bool Success { get { return this.ExitCode == 0; } } | ||
} | ||
} |
Oops, something went wrong.