Update the bootstrapper to install the compiled version of KoreBuild

- Replace SplitPackages as a package reference with a RepoTask instead
This commit is contained in:
Nate McMaster 2017-07-24 18:14:46 -07:00
Родитель 006cf52afa
Коммит f7fcc555ff
14 изменённых файлов: 649 добавлений и 122 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -2,7 +2,6 @@
[Bb]in/
TestResults/
.nuget/
.build/
.testPublish/
*.sln.ide/
_ReSharper.*/
@ -37,3 +36,4 @@ node_modules
**/[Cc]ompiler/[Rr]esources/**/*.js
*launchSettings.json
global.json
korebuild-lock.txt

Просмотреть файл

@ -1,10 +1,23 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26206.0
VisualStudioVersion = 15.0.26621.2
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoherenceBuild", "tools\CoherenceBuild\CoherenceBuild.csproj", "{182ACF9E-135C-42D5-A19C-A6C9FCF0529F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{DBFB488A-D866-4FD2-BADF-D760DDF114E0}"
ProjectSection(SolutionItems) = preProject
build\repo.props = build\repo.props
build\repo.targets = build\repo.targets
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepoTasks", "build\tasks\RepoTasks.csproj", "{2DF1B138-D369-4701-82FA-187B9C90D7E8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1C53F28D-BEF5-4DD4-9766-895C17FE2A09}"
ProjectSection(SolutionItems) = preProject
packages\packages.csv = packages\packages.csv
packages\packages.key.txt = packages\packages.key.txt
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,8 +28,16 @@ Global
{182ACF9E-135C-42D5-A19C-A6C9FCF0529F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{182ACF9E-135C-42D5-A19C-A6C9FCF0529F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{182ACF9E-135C-42D5-A19C-A6C9FCF0529F}.Release|Any CPU.Build.0 = Release|Any CPU
{2DF1B138-D369-4701-82FA-187B9C90D7E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DF1B138-D369-4701-82FA-187B9C90D7E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2DF1B138-D369-4701-82FA-187B9C90D7E8} = {DBFB488A-D866-4FD2-BADF-D760DDF114E0}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E8514249-D06D-486A-83DB-ABDE80756DEA}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1 +0,0 @@
dev

227
build.ps1
Просмотреть файл

@ -1,68 +1,177 @@
$ErrorActionPreference = "Stop"
#!/usr/bin/env powershell
#requires -version 4
function DownloadWithRetry([string] $url, [string] $downloadLocation, [int] $retries)
{
while($true)
{
try
{
Invoke-WebRequest $url -OutFile $downloadLocation
break
<#
.SYNOPSIS
Build this repository
.DESCRIPTION
Downloads korebuild if required. Then builds the repository.
.PARAMETER Path
The folder to build. Defaults to the folder containing this script.
.PARAMETER Channel
The channel of KoreBuild to download. Overrides the value from the config file.
.PARAMETER DotNetHome
The directory where .NET Core tools will be stored.
.PARAMETER ToolsSource
The base url where build tools can be downloaded. Overrides the value from the config file.
.PARAMETER Update
Updates KoreBuild to the latest version even if a lock file is present.
.PARAMETER ConfigFile
The path to the configuration file that stores values. Defaults to version.xml.
.PARAMETER MSBuildArgs
Arguments to be passed to MSBuild
.NOTES
This function will create a file $PSScriptRoot/korebuild-lock.txt. This lock file can be committed to source, but does not have to be.
When the lockfile is not present, KoreBuild will create one using latest available version from $Channel.
The $ConfigFile is expected to be an XML file. It is optional, and the configuration values in it are optional as well.
.EXAMPLE
Example config file:
```xml
<!-- version.xml -->
<Project>
<PropertyGroup>
<KoreBuildChannel>dev</KoreBuildChannel>
<KoreBuildToolsSource>https://aspnetcore.blob.core.windows.net/buildtools</KoreBuildToolsSource>
</PropertyGroup>
</Project>
```
#>
[CmdletBinding(PositionalBinding = $false)]
param(
[string]$Path = $PSScriptRoot,
[Alias('c')]
[string]$Channel,
[Alias('d')]
[string]$DotNetHome,
[Alias('s')]
[string]$ToolsSource,
[Alias('u')]
[switch]$Update,
[string]$ConfigFile = (Join-Path $PSScriptRoot 'version.xml'),
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$MSBuildArgs
)
Set-StrictMode -Version 2
$ErrorActionPreference = 'Stop'
#
# Functions
#
function Get-KoreBuild {
$lockFile = Join-Path $Path 'korebuild-lock.txt'
if (!(Test-Path $lockFile) -or $Update) {
Get-RemoteFile "$ToolsSource/korebuild/channels/$Channel/latest.txt" $lockFile
}
catch
{
$exceptionMessage = $_.Exception.Message
Write-Host "Failed to download '$url': $exceptionMessage"
if ($retries -gt 0) {
$retries--
Write-Host "Waiting 10 seconds before retrying. Retries left: $retries"
Start-Sleep -Seconds 10
$version = Get-Content $lockFile | Where-Object { $_ -like 'version:*' } | Select-Object -first 1
if (!$version) {
Write-Error "Failed to parse version from $lockFile. Expected a line that begins with 'version:'"
}
else
{
$exception = $_.Exception
throw $exception
$version = $version.TrimStart('version:').Trim()
$korebuildPath = Join-Paths $DotNetHome ('buildtools', 'korebuild', $version)
if (!(Test-Path $korebuildPath)) {
Write-Host -ForegroundColor Magenta "Downloading KoreBuild $version"
New-Item -ItemType Directory -Path $korebuildPath | Out-Null
$remotePath = "$ToolsSource/korebuild/artifacts/$version/korebuild.$version.zip"
try {
$tmpfile = Join-Path ([IO.Path]::GetTempPath()) "KoreBuild-$([guid]::NewGuid()).zip"
Get-RemoteFile $remotePath $tmpfile
if (Get-Command -Name 'Expand-Archive' -ErrorAction Ignore) {
# Use built-in commands where possible as they are cross-plat compatible
Expand-Archive -Path $tmpfile -DestinationPath $korebuildPath
}
}
}
}
cd $PSScriptRoot
$repoFolder = $PSScriptRoot
$env:REPO_FOLDER = $repoFolder
$korebuildVersion = $(Get-Content -Raw $PSScriptRoot/KoreBuildVersion.txt).Trim()
$koreBuildZip="https://github.com/aspnet/KoreBuild/archive/$korebuildVersion.zip"
if ($env:KOREBUILD_ZIP)
{
$koreBuildZip=$env:KOREBUILD_ZIP
}
$buildFolder = ".build"
$buildFile="$buildFolder\KoreBuild.ps1"
if (!(Test-Path $buildFolder)) {
Write-Host "Downloading KoreBuild from $koreBuildZip"
$tempFolder=$env:TEMP + "\KoreBuild-" + [guid]::NewGuid()
New-Item -Path "$tempFolder" -Type directory | Out-Null
$localZipFile="$tempFolder\korebuild.zip"
DownloadWithRetry -url $koreBuildZip -downloadLocation $localZipFile -retries 6
else {
# Fallback to old approach for old installations of PowerShell
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($localZipFile, $tempFolder)
New-Item -Path "$buildFolder" -Type directory | Out-Null
copy-item "$tempFolder\**\build\*" $buildFolder -Recurse
# Cleanup
if (Test-Path $tempFolder) {
Remove-Item -Recurse -Force $tempFolder
[System.IO.Compression.ZipFile]::ExtractToDirectory($tmpfile, $korebuildPath)
}
}
catch {
Remove-Item -Recurse -Force $korebuildPath -ErrorAction Ignore
throw
}
finally {
Remove-Item $tmpfile -ErrorAction Ignore
}
}
return $korebuildPath
}
&"$buildFile" @args
function Join-Paths([string]$path, [string[]]$childPaths) {
$childPaths | ForEach-Object { $path = Join-Path $path $_ }
return $path
}
function Get-RemoteFile([string]$RemotePath, [string]$LocalPath) {
if ($RemotePath -notlike 'http*') {
Copy-Item $RemotePath $LocalPath
return
}
$retries = 10
while ($retries -gt 0) {
$retries -= 1
try {
Invoke-WebRequest -UseBasicParsing -Uri $RemotePath -OutFile $LocalPath
return
}
catch {
Write-Verbose "Request failed. $retries retries remaining"
}
}
Write-Error "Download failed: '$RemotePath'."
}
#
# Main
#
# Load configuration or set defaults
if (Test-Path $ConfigFile) {
[xml] $config = Get-Content $ConfigFile
if (!($Channel)) { [string] $Channel = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildChannel' }
if (!($ToolsSource)) { [string] $ToolsSource = Select-Xml -Xml $config -XPath '/Project/PropertyGroup/KoreBuildToolsSource' }
}
if (!$DotNetHome) {
$DotNetHome = if ($env:DOTNET_HOME) { $env:DOTNET_HOME } `
elseif ($env:USERPROFILE) { Join-Path $env:USERPROFILE '.dotnet'} `
elseif ($env:HOME) {Join-Path $env:HOME '.dotnet'}`
else { Join-Path $PSScriptRoot '.dotnet'}
}
if (!$Channel) { $Channel = 'dev' }
if (!$ToolsSource) { $ToolsSource = 'https://aspnetcore.blob.core.windows.net/buildtools' }
# Execute
$korebuildPath = Get-KoreBuild
Import-Module -Force -Scope Local (Join-Path $korebuildPath 'KoreBuild.psd1')
try {
Install-Tools $ToolsSource $DotNetHome
Invoke-RepositoryBuild $Path @MSBuildArgs
}
finally {
Remove-Module 'KoreBuild' -ErrorAction Ignore
}

222
build.sh
Просмотреть файл

@ -1,47 +1,195 @@
#!/usr/bin/env bash
repoFolder="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $repoFolder
koreBuildVersion=$(cat $repoFolder/KoreBuildVersion.txt)
koreBuildZip="https://github.com/aspnet/KoreBuild/archive/$koreBuildVersion.zip"
if [ ! -z $KOREBUILD_ZIP ]; then
koreBuildZip=$KOREBUILD_ZIP
fi
set -euo pipefail
buildFolder=".build"
buildFile="$buildFolder/KoreBuild.sh"
#
# variables
#
if test ! -d $buildFolder; then
echo "Downloading KoreBuild from $koreBuildZip"
RESET="\033[0m"
RED="\033[0;31m"
MAGENTA="\033[0;95m"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
[ -z "${DOTNET_HOME:-}"] && DOTNET_HOME="$HOME/.dotnet"
config_file="$DIR/version.xml"
verbose=false
update=false
repo_path="$DIR"
channel=''
tools_source=''
tempFolder="/tmp/KoreBuild-$(uuidgen)"
mkdir $tempFolder
#
# Functions
#
__usage() {
echo "Usage: $(basename ${BASH_SOURCE[0]}) [options] [[--] <MSBUILD_ARG>...]"
echo ""
echo "Arguments:"
echo " <MSBUILD_ARG>... Arguments passed to MSBuild. Variable number of arguments allowed."
echo ""
echo "Options:"
echo " --verbose Show verbose output."
echo " -c|--channel <CHANNEL> The channel of KoreBuild to download. Overrides the value from the config file.."
echo " --config-file <FILE> TThe path to the configuration file that stores values. Defaults to version.xml."
echo " -d|--dotnet-home <DIR> The directory where .NET Core tools will be stored. Defaults to '\$DOTNET_HOME' or '\$HOME/.dotnet."
echo " --path <PATH> The directory to build. Defaults to the directory containing the script."
echo " -s|--tools-source <URL> The base url where build tools can be downloaded. Overrides the value from the config file."
echo " -u|--update Update to the latest KoreBuild even if the lock file is present."
echo ""
echo "Description:"
echo " This function will create a file \$DIR/korebuild-lock.txt. This lock file can be committed to source, but does not have to be."
echo " When the lockfile is not present, KoreBuild will create one using latest available version from \$channel."
localZipFile="$tempFolder/korebuild.zip"
if [[ "${1:-}" != '--no-exit' ]]; then
exit 2
fi
}
retries=6
until (wget -O $localZipFile $koreBuildZip 2>/dev/null || curl -o $localZipFile --location $koreBuildZip 2>/dev/null)
do
echo "Failed to download '$koreBuildZip'"
if [ "$retries" -le 0 ]; then
get_korebuild() {
local lock_file="$repo_path/korebuild-lock.txt"
if [ ! -f $lock_file ] || [ "$update" = true ]; then
__get_remote_file "$tools_source/korebuild/channels/$channel/latest.txt" $lock_file
fi
local version="$(grep 'version:*' -m 1 $lock_file)"
if [[ "$version" == '' ]]; then
__error "Failed to parse version from $lock_file. Expected a line that begins with 'version:'"
return 1
fi
version="$(echo ${version#version:} | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
local korebuild_path="$DOTNET_HOME/buildtools/korebuild/$version"
{
if [ ! -d "$korebuild_path" ]; then
mkdir -p "$korebuild_path"
local remote_path="$tools_source/korebuild/artifacts/$version/korebuild.$version.zip"
tmpfile="$(mktemp)"
echo -e "${MAGENTA}Downloading KoreBuild ${version}${RESET}"
if __get_remote_file $remote_path $tmpfile; then
unzip -q -d "$korebuild_path" $tmpfile
fi
rm $tmpfile || true
fi
source "$korebuild_path/KoreBuild.sh"
} || {
if [ -d "$korebuild_path" ]; then
echo "Cleaning up after failed installation"
rm -rf "$korebuild_path" || true
fi
return 1
}
}
__error() {
echo -e "${RED}$@${RESET}" 1>&2
}
__machine_has() {
hash "$1" > /dev/null 2>&1
return $?
}
__get_remote_file() {
local remote_path=$1
local local_path=$2
if [[ "$remote_path" != 'http'* ]]; then
cp $remote_path $local_path
return 0
fi
failed=false
if __machine_has curl ; then
curl --retry 10 -sSL -f --create-dirs -o $local_path $remote_path || failed=true
elif __machine_has wget; then
wget --tries 10 -O $local_path $remote_path || failed=true
else
failed=true
fi
if [ "$failed" = true ]; then
__error "Download failed: $remote_path" 1>&2
return 1
fi
}
__read_dom () { local IFS=\> ; read -d \< ENTITY CONTENT ;}
#
# main
#
while [[ $# > 0 ]]; do
case $1 in
-\?|-h|--help)
__usage --no-exit
exit 0
;;
-c|--channel|-Channel)
shift
channel=${1:-}
[ -z "$channel" ] && __usage
;;
--config-file|-ConfigFile)
shift
config_file="${1:-}"
[ -z "$config_file" ] && __usage
;;
-d|--dotnet-home|-DotNetHome)
shift
DOTNET_HOME=${1:-}
[ -z "$DOTNET_HOME" ] && __usage
;;
--path|-Path)
shift
repo_path="${1:-}"
[ -z "$repo_path" ] && __usage
;;
-s|--tools-source|-ToolsSource)
shift
tools_source="${1:-}"
[ -z "$tools_source" ] && __usage
;;
-u|--update|-Update)
update=true
;;
--verbose|-Verbose)
verbose=true
;;
--)
shift
break
;;
*)
break
;;
esac
shift
done
if ! __machine_has unzip; then
__error 'Missing required command: unzip'
exit 1
fi
retries=$((retries - 1))
echo "Waiting 10 seconds before retrying. Retries left: $retries"
sleep 10s
done
unzip -q -d $tempFolder $localZipFile
mkdir $buildFolder
cp -r $tempFolder/**/build/** $buildFolder
chmod +x $buildFile
# Cleanup
if test -d $tempFolder; then
rm -rf $tempFolder
fi
fi
$buildFile -r $repoFolder "$@"
if ! __machine_has curl && ! __machine_has wget; then
__error 'Missing required command. Either wget or curl is required.'
exit 1
fi
if [ -f $config_file ]; then
comment=false
while __read_dom; do
if [ "$comment" = true ]; then [[ $CONTENT == *'-->'* ]] && comment=false ; continue; fi
if [[ $ENTITY == '!--'* ]]; then comment=true; continue; fi
if [ -z "$channel" ] && [[ $ENTITY == "KoreBuildChannel" ]]; then channel=$CONTENT; fi
if [ -z "$tools_source" ] && [[ $ENTITY == "KoreBuildToolsSource" ]]; then tools_source=$CONTENT; fi
done < $config_file
fi
[ -z "$channel" ] && channel='dev'
[ -z "$tools_source" ] && tools_source='https://aspnetcore.blob.core.windows.net/buildtools'
get_korebuild
install_tools "$tools_source" "$DOTNET_HOME"
invoke_repository_build "$repo_path" $@

Просмотреть файл

@ -1,5 +0,0 @@
<Project>
<ItemGroup>
<PackageReference Include="SplitPackages" Version="1.0.3-*" />
</ItemGroup>
</Project>

Просмотреть файл

@ -2,7 +2,7 @@
<PropertyGroup>
<NuGetPublishFeed>https://dotnet.myget.org/f/aspnetcore-ci-dev</NuGetPublishFeed>
<NpmRegistry>$(NuGetPublishFeed)/npm/</NpmRegistry>
<BuildDependsOn>$(BuildDependsOn);RunVerifier;RunSplitPackages;PublishNpmModules</BuildDependsOn>
<BuildDependsOn>$(BuildDependsOn);RunVerifier;SplitPackages;PublishNpmModules</BuildDependsOn>
</PropertyGroup>
<Target Name="RunVerifier">
@ -27,11 +27,6 @@
<VerifierArgsList Include="--disable-partner-package-verification" Condition="'$(DISABLE_PARTNER_COHERENCE_CHECK)'=='true'"/>
</ItemGroup>
<ItemGroup Condition="'$(APIKEY)'!=''">
<VerifierArgsList Include="--nuget-publish-feed $(NuGetPublishFeed)" />
<VerifierArgsList Include="--api-key $(APIKEY)" />
</ItemGroup>
<PropertyGroup>
<VerifierProjectDirectory>$(RepositoryRoot)tools\CoherenceBuild\</VerifierProjectDirectory>
<VerifierArgs>@(VerifierArgsList, ' ')</VerifierArgs>
@ -40,14 +35,19 @@
<Exec Command="dotnet run $(VerifierArgs)" WorkingDirectory="$(VerifierProjectDirectory)" />
</Target>
<Target Name="RunSplitPackages" DependsOnTargets="_FindDotNetPath">
<Target Name="SplitPackages">
<PropertyGroup>
<ProductPackagesSource>$(ArtifactsDir)product-packages</ProductPackagesSource>
<SplitPackagesCsv>$(RepositoryRoot)packages\packages.csv</SplitPackagesCsv>
<SplitPackagesArgs>--source $(ProductPackagesSource) --csv $(SplitPackagesCsv) --destination $(ArtifactsDir)</SplitPackagesArgs>
<ProductPackagesSource>$(ArtifactsDir)product-packages\</ProductPackagesSource>
</PropertyGroup>
<Exec Command="&quot;$(DotNetPath)&quot; &quot;$(SplitPackagesNetCoreAppPath)&quot; $(SplitPackagesArgs)" />
<ItemGroup>
<_PackagesToCopy Include="$(ProductPackagesSource)*.nupkg" />
</ItemGroup>
<RepoTasks.CopyPackagesToSplitFolders
Packages="@(_PackagesToCopy)"
CsvFile="$(RepositoryRoot)packages\packages.csv"
DestinationFolder="$(ArtifactsDir)" />
<RemoveDir Directories="$(ProductPackagesSource)" />
</Target>
@ -68,10 +68,4 @@
<Exec Command="npm config delete $(AuthTokenSetting)" />
<Error Text="Publishing npm modules failed" Condition="%(ExitCodes.Identity) > 0"/>
</Target>
<Target Name="_FindDotNetPath">
<GetDotNetHost>
<Output TaskParameter="ExecutablePath" PropertyName="DotNetPath" />
</GetDotNetHost>
</Target>
</Project>

Просмотреть файл

@ -0,0 +1,109 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Text;
using Microsoft.Build.Framework;
using NuGet.Packaging;
using NuGet.Packaging.Core;
using RepoTasks.Utilities;
namespace RepoTasks
{
public class CopyPackagesToSplitFolders : Microsoft.Build.Utilities.Task
{
/// <summary>
/// The item group containing the nuget packages to split in different folders.
/// </summary>
[Required]
public ITaskItem[] Packages { get; set; }
/// <summary>
/// Path to the CSV file containing the names and subfolders where each package must go.
/// </summary>
[Required]
public string CsvFile { get; set; }
/// <summary>
/// The folder where packages should be copied. Subfolders will be created based on package category.
/// </summary>
[Required]
public string DestinationFolder { get; set; }
public override bool Execute()
{
if (Packages?.Length == 0)
{
Log.LogError("No packages were found.");
return false;
}
if (string.IsNullOrEmpty(CsvFile) || !File.Exists(CsvFile))
{
Log.LogError($"Package manifest (csv file) could not be loaded from '{CsvFile}'");
return false;
}
var expectedPackages = PackageCollection.DeserializeFromCsv(CsvFile);
Directory.CreateDirectory(DestinationFolder);
foreach (var package in Packages)
{
PackageIdentity identity;
using (var reader = new PackageArchiveReader(package.ItemSpec))
{
identity = reader.GetIdentity();
}
if (!expectedPackages.TryGetCategory(identity.Id, out var category))
{
Log.LogError($"{CsvFile} does not contain an entry for a package with id: {identity.Id}");
return false;
}
string destDir;
switch (category)
{
case PackageCategory.Unknown:
throw new InvalidOperationException($"Package {identity} does not have a recognized package category.");
case PackageCategory.Shipping:
destDir = Path.Combine(DestinationFolder, "ship");
break;
case PackageCategory.NoShip:
destDir = Path.Combine(DestinationFolder, "noship");
break;
case PackageCategory.ShipOob:
destDir = Path.Combine(DestinationFolder, "shipoob");
break;
default:
throw new NotImplementedException();
}
Directory.CreateDirectory(destDir);
var destFile = Path.Combine(destDir, Path.GetFileName(package.ItemSpec));
Log.LogMessage($"Copying {package.ItemSpec} to {destFile}");
File.Copy(package.ItemSpec, destFile);
expectedPackages.Remove(identity.Id);
}
if (expectedPackages.Count != 0)
{
var error = new StringBuilder();
foreach (var key in expectedPackages.Keys)
{
error.Append(" - ").AppendLine(key);
}
Log.LogError($"Expected the following packages based on the contents of {CsvFile}, but they were not found:" + error.ToString());
return false;
}
return true;
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(RepoTasksSdkPath)\Sdk.props" Condition="'$(RepoTasksSdkPath)' != '' "/>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NuGet.ProjectModel" Version="$(NuGetInMSBuildVersion)" />
</ItemGroup>
<Import Project="$(RepoTasksSdkPath)\Sdk.targets" Condition="'$(RepoTasksSdkPath)' != '' "/>
</Project>

Просмотреть файл

@ -0,0 +1,6 @@
<Project>
<PropertyGroup>
<_RepoTaskAssembly>$(MSBuildThisFileDirectory)bin\publish\RepoTasks.dll</_RepoTaskAssembly>
</PropertyGroup>
<UsingTask TaskName="RepoTasks.CopyPackagesToSplitFolders" AssemblyFile="$(_RepoTaskAssembly)" />
</Project>

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace RepoTasks.Utilities
{
public enum PackageCategory
{
Unknown = 0,
Shipping,
NoShip,
ShipOob
}
}

Просмотреть файл

@ -0,0 +1,110 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace RepoTasks.Utilities
{
public class PackageCollection
{
private readonly IDictionary<string, PackageCategory> _packages = new Dictionary<string, PackageCategory>(StringComparer.OrdinalIgnoreCase);
private PackageCollection()
{
}
public bool TryGetCategory(string packageId, out PackageCategory category) => _packages.TryGetValue(packageId, out category);
public void Remove(string packageId) => _packages.Remove(packageId);
public int Count => _packages.Count;
public IEnumerable<string> Keys => _packages.Keys;
public static PackageCollection DeserializeFromCsv(string filepath)
{
using (var stream = File.OpenRead(filepath))
using (var reader = new StreamReader(stream))
{
return DeserializeFromCsv(reader);
}
}
public static PackageCollection DeserializeFromCsv(TextReader reader)
{
var lineNo = 0;
var list = new PackageCollection();
string[] Split(string l) => l.Split(',').Select(s => s.Trim()).ToArray();
// Package,Category,...
// Microsoft.AspNetCore.Razor.Tools,ship,...
// Microsoft.VisualStudio.Web.CodeGeneration.Tools,ship,...
// Microsoft.Extensions.SecretManager.Tools,ship,...
var line = reader.ReadLine();
lineNo++;
var columns = Split(line);
EnsureHeaderColumns(columns);
while ((line = reader.ReadLine()) != null)
{
lineNo++;
var values = Split(line);
if (values.Length < 2)
{
throw new FormatException($"Error on line {lineNo}. Too few columns. Expected at least two.");
}
PackageCategory category;
switch (values[1].ToLowerInvariant())
{
case "ship":
category = PackageCategory.Shipping;
break;
case "noship":
category = PackageCategory.NoShip;
break;
case "shipoob":
category = PackageCategory.ShipOob;
break;
default:
category = PackageCategory.Unknown;
break;
}
if (list._packages.ContainsKey(values[0]))
{
throw new InvalidDataException($"Duplicate package id detected: {values[0]} on line {lineNo}");
}
list._packages.Add(values[0], category);
}
return list;
}
private static void EnsureHeaderColumns(string[] columns)
{
if (columns.Length < 2)
{
throw new FormatException("Unrecognized number of columns in csv file");
}
if (!columns[0].Equals("Package", StringComparison.OrdinalIgnoreCase))
{
throw new FormatException("Unrecognized column: " + columns[0]);
}
if (!columns[1].Equals("Category", StringComparison.OrdinalIgnoreCase))
{
throw new FormatException("Unrecognized column: " + columns[0]);
}
}
}
}

7
version.xml Normal file
Просмотреть файл

@ -0,0 +1,7 @@
<Project>
<PropertyGroup>
<KoreBuildChannel>dev</KoreBuildChannel>
<VersionPrefix>2.1.0</VersionPrefix>
<VersionSuffix>preview1</VersionSuffix>
</PropertyGroup>
</Project>