Skip to content

Commit

Permalink
Merge pull request #53 from peters/issue-48
Browse files Browse the repository at this point in the history
Add support for overriding repository url, version and uploading multiple packages simultaneously using a glob pattern (wildcards)
  • Loading branch information
jcansdale authored Jun 17, 2020
2 parents 88f89c1 + 0294e2c commit 7467f0d
Show file tree
Hide file tree
Showing 14 changed files with 1,530 additions and 189 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
**/.vs/
**/.vs/
**/bin/
**/obj/
*.user
*.nupkg
_NCrunch_*/
*.ncrunchsolution
publish/
nupkgs/
src/GprTool/nupkg/
**/TestResults/TestResults.xml
31 changes: 25 additions & 6 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning">
<Version>3.0.50</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<IsRunningTests Condition="'$(IsRunningTests)' == ''">false</IsRunningTests>
<PackageOutputPath>$(MSBuildThisFileDirectory)nupkgs</PackageOutputPath>
<OsPlatform Condition="$(OsPlatform) == '' AND '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">Windows</OsPlatform>
<OsPlatform Condition="$(OsPlatform) == '' AND '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))' == 'true'">Unix</OsPlatform>
<OsPlatform Condition="$(OsPlatform) == '' AND '$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))' == 'true'">MACOS</OsPlatform>
<OsPlatform Condition="$(OsPlatform) == ''">Unknown</OsPlatform>
</PropertyGroup>

<PropertyGroup Condition="$(IsRunningTests)">
<DefineConstants>$(DefineConstants);IS_RUNNING_TESTS</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(OsPlatform) == 'Windows'">
<DefineConstants>$(DefineConstants);PLATFORM_WINDOWS</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(OsPlatform) == 'Unix'">
<DefineConstants>$(DefineConstants);PLATFORM_UNIX</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="$(OsPlatform) == 'MACOS'">
<DefineConstants>$(DefineConstants);PLATFORM_MACOS</DefineConstants>
</PropertyGroup>

</Project>
5 changes: 5 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sdk": {
"version": "3.1.301"
}
}
46 changes: 46 additions & 0 deletions src/GprTool/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace GprTool
{
internal static class EnumerableExtensions
{
public static Task ForEachAsync<T>([NotNull] this IEnumerable<T> source,
[NotNull] Func<T, CancellationToken, Task> onExecuteFunc, Action<T, Exception> onExceptionAction = null,
CancellationToken cancellationToken = default, int concurrency = 1)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (onExecuteFunc == null) throw new ArgumentNullException(nameof(onExecuteFunc));
if (concurrency <= 0) throw new ArgumentOutOfRangeException(nameof(concurrency));

// https://devblogs.microsoft.com/pfxteam/implementing-a-simple-foreachasync-part-2/
return Task.WhenAll(
Partitioner
.Create(source)
.GetPartitions(concurrency)
.Select(partition => Task.Run(async delegate
{
using (partition)
{
while (partition.MoveNext())
{
try
{
await onExecuteFunc(partition.Current, cancellationToken);
}
catch (Exception e)
{
onExceptionAction?.Invoke(partition.Current, e);
throw;
}
}
}
}, default)));
}
}
}
86 changes: 86 additions & 0 deletions src/GprTool/GlobExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using DotNet.Globbing;
using DotNet.Globbing.Token;

namespace GprTool
{
public static class GlobExtensions
{
public static bool IsGlobPattern(this Glob glob)
{
return glob.Tokens.Any(x => !(x is PathSeparatorToken || x is LiteralToken));
}

public static string BuildBasePathFromGlob(this Glob glob, string baseDirectory)
{
if (glob == null) throw new ArgumentNullException(nameof(glob));
if (baseDirectory == null) throw new ArgumentNullException(nameof(baseDirectory));

var globTokens = glob.Tokens.ToList();
var pathTokens = new List<IGlobToken>();

for (var index = 0; index < globTokens.Count; index++)
{
var token = glob.Tokens[index];
var tokenNext = index + 1 < globTokens.Count ? glob.Tokens[index + 1] : null;

switch (token)
{
case LiteralToken _:
pathTokens.Add(token);
if (tokenNext is AnyCharacterToken
|| tokenNext is INegatableToken
&& pathTokens.Any())
{
pathTokens.RemoveAt(pathTokens.Count - 1);
goto done;
}
continue;
case PathSeparatorToken _ when (tokenNext is LiteralToken):
pathTokens.Add(token);
continue;
}

goto done;
}

done:

var pathStringBuilder = new StringBuilder();

foreach (var token in pathTokens)
{
switch (token)
{
case LiteralToken literalToken:
pathStringBuilder.Append(literalToken.Value);
break;
case PathSeparatorToken _: // xplat
pathStringBuilder.Append("/");
break;
default:
throw new NotSupportedException(token.GetType().FullName);
}
}

var pathStr = pathStringBuilder.ToString();

// Remove trailing backward/forward slash
var lastAppendedGlobToken = pathTokens.LastOrDefault();
if (lastAppendedGlobToken is PathSeparatorToken
&& pathStr.Sum(x => x == '/' ? 1 : 0) > 1)
{
pathStr = pathStr.Substring(0, pathStr.Length - 1);
} else if (lastAppendedGlobToken is LiteralToken literalToken && literalToken.Value == ".")
{
return Path.GetFullPath(baseDirectory);
}

return !Path.IsPathRooted(pathStr) ? Path.GetFullPath(pathStr, baseDirectory) : Path.GetFullPath(pathStr);
}
}
}
12 changes: 9 additions & 3 deletions src/GprTool/GprTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@
<PackageProjectUrl>https://github.com/jcansdale/gpr</PackageProjectUrl>
<Title>GPR Tool</Title>
<PackageDescription>A .NET Core tool for working the GitHub Package Registry.</PackageDescription>
<PackageOutputPath>./nupkg</PackageOutputPath>
<AssemblyName>gpr</AssemblyName>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<Copyright>Mutant Design Limited</Copyright>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.4.1" />
<PackageReference Include="DotNet.Glob" Version="3.0.9" />
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="3.0.0" />
<PackageReference Include="Octokit.GraphQL" Version="0.1.4-packages-preview2" />
<PackageReference Include="RestSharp" Version="106.10.1" />
<PackageReference Include="Polly" Version="7.2.1" />
<PackageReference Include="RestSharp" Version="106.11.4" />
<PackageReference Include="NuGet.Packaging" Version="5.6.0" />
<PackageReference Include="Nerdbank.GitVersioning" Condition="!$(IsRunningTests)">
<Version>3.1.91</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

</Project>
69 changes: 69 additions & 0 deletions src/GprTool/IoExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DotNet.Globbing;

namespace GprTool
{
public static class IoExtensions
{
public static IEnumerable<string> GetFilesByGlobPattern(this string baseDirectory, string globPattern, out Glob outGlob)
{
var baseDirectoryGlobPattern = Path.GetFullPath(Path.Combine(baseDirectory, globPattern));
var fileNames = new List<string>();

if (string.Equals(".", globPattern))
{
globPattern = Path.GetFullPath(Path.Combine(baseDirectory, "*.*"));
} else if (Directory.Exists(baseDirectoryGlobPattern))
{
globPattern = Path.GetFullPath(Path.Combine(baseDirectoryGlobPattern, "*.*"));
} else if (File.Exists(baseDirectoryGlobPattern))
{
globPattern = Path.GetFullPath(baseDirectoryGlobPattern);
} else if (globPattern.Contains(" "))
{
baseDirectoryGlobPattern = baseDirectory;

fileNames.AddRange(globPattern
.Split(" ", StringSplitOptions.RemoveEmptyEntries)
.Select(x => Path.IsPathRooted(x)
? Path.GetFullPath(x)
: Path.GetFullPath(Path.Combine(baseDirectoryGlobPattern, x)))
.Where(x => !Directory.Exists(x)));

globPattern = string.Empty;
}

var glob = Path.IsPathRooted(globPattern)
? Glob.Parse(globPattern)
: Glob.Parse(baseDirectoryGlobPattern);

var basePathFromGlob = Path.GetDirectoryName(glob.BuildBasePathFromGlob(baseDirectory));

outGlob = glob;

return Directory
.GetFiles(basePathFromGlob, "*.*", SearchOption.AllDirectories)
.Where(filename =>
filename.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase)
|| filename.EndsWith(".snupkg", StringComparison.OrdinalIgnoreCase))
.Where(filename => fileNames.Contains(filename, StringComparer.Ordinal) || glob.IsMatch(filename));
}

public static FileStream OpenReadShared(this string filename)
{
return File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
}

public static MemoryStream ReadSharedToStream(this string filename)
{
using var fileStream = filename.OpenReadShared();
var outputStream = new MemoryStream();
fileStream.CopyTo(outputStream);
outputStream.Seek(0, SeekOrigin.Begin);
return outputStream;
}
}
}
Loading

0 comments on commit 7467f0d

Please sign in to comment.