Update to MSBuild

This commit is contained in:
Pranav K 2017-03-04 20:27:09 -08:00
parent c598f1918d
commit 471f48f56e
27 changed files with 1109 additions and 1708 deletions

55
.gitignore vendored
View File

@ -14,56 +14,7 @@ artifacts
StyleCop.Cache
node_modules
*.snk
.nuget/NuGet.exe
project.lock.json
.build
.nuget/
# repo folders
/Antiforgery/
/AzureIntegration/
/BasicMiddleware/
/BrowserLink/
/CORS/
/Caching/
/Common/
/Configuration/
/DataProtection/
/DependencyInjection/
/Diagnostics/
/DotNetTools/
/EntityFramework.Tools/
/EntityFramework/
/Entropy/
/EventNotification/
/FileSystem/
/Hosting/
/HtmlAbstractions/
/HttpAbstractions/
/HttpSysServer/
/IISIntegration/
/Identity/
/IdentityService/
/JsonPatch/
/KestrelHttpServer/
/Localization/
/Logging/
/MetaPackages/
/Microsoft.Data.Sqlite/
/MusicStore/
/Mvc/
/MvcPrecompilation/
/Options/
/PlatformAbstractions/
/Proxy/
/Razor/
/ResponseCaching/
/Routing/
/Scaffolding/
/Security/
/ServerTests/
/Session/
/SignalR/
/StaticFiles/
/Testing/
/WebSockets/
.nuget
.r
.deps

37
Universe.sln Normal file
View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildGraph", "tools\BuildGraph\BuildGraph.csproj", "{B0621D49-4770-4552-9425-D6BD2CF0FB50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PinVersions", "tools\PinVersions\PinVersions.csproj", "{DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{085280EC-7055-426A-BF9C-1B692B9599AB}"
ProjectSection(SolutionItems) = preProject
tools\shared\DependencyGraphSpecProvider.cs = tools\shared\DependencyGraphSpecProvider.cs
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B0621D49-4770-4552-9425-D6BD2CF0FB50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B0621D49-4770-4552-9425-D6BD2CF0FB50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0621D49-4770-4552-9425-D6BD2CF0FB50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0621D49-4770-4552-9425-D6BD2CF0FB50}.Release|Any CPU.Build.0 = Release|Any CPU
{0DC180DF-D87B-448A-BCDE-2A648F41103E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0DC180DF-D87B-448A-BCDE-2A648F41103E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0DC180DF-D87B-448A-BCDE-2A648F41103E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0DC180DF-D87B-448A-BCDE-2A648F41103E}.Release|Any CPU.Build.0 = Release|Any CPU
{DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DACA9DFB-508E-45EA-A5CF-C0F5C2BA181B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,243 +0,0 @@
#update-release
-// Merge dev branch to release
@{
Parallel.ForEach(GetAllRepos(), CloneOrUpdate);
Log.Info("************************************* Checking repos for diffs *************************");
foreach (var repo in GetAllRepos())
{
Log.Info("Checking repo: " + repo);
// Check if the repo previously had a release branch
try
{
GitCommand(repo, "rev-parse --verify --quiet origin/release");
}
catch
{
Log.Info("Repository " + repo + " does not have a release branch.");
continue;
}
try
{
GitCommand(repo, "log -1 --exit-code origin/dev..origin/release");
}
catch
{
Log.Warn("Unmerged changes in repository " + repo);
GitCommand(repo, "log origin/dev..origin/release");
throw;
}
}
Log.Info("No conflicts in repos, continuing with creating release branch.");
foreach (var repo in GetAllRepos())
{
GitCommand(repo, "checkout origin/dev -B release");
var filesChanged = false;
// Update NuGet.Config
var nugetConfigPath = Path.Combine(repo, "NuGet.config");
if (File.Exists(nugetConfigPath))
{
var original = File.ReadAllText(nugetConfigPath);
var modified = original
.Replace("https://dotnet.myget.org/F/aspnetcore-ci-dev", "https://dotnet.myget.org/F/aspnetcore-ci-release");
if (!string.Equals(original, modified, StringComparison.Ordinal))
{
File.WriteAllText(nugetConfigPath, modified);
GitCommand(repo, "add NuGet.config");
filesChanged = true;
}
}
var buildPs1Path = Path.Combine(repo, "build.ps1");
if (File.Exists(buildPs1Path))
{
var original = File.ReadAllText(buildPs1Path);
var modified = original
.Replace("https://github.com/aspnet/KoreBuild/archive/dev.zip", "https://github.com/aspnet/KoreBuild/archive/release.zip");
if (!string.Equals(original, modified, StringComparison.Ordinal))
{
File.WriteAllText(buildPs1Path, modified);
GitCommand(repo, "add build.ps1");
filesChanged = true;
}
}
var buildShPath = Path.Combine(repo, "build.sh");
if (File.Exists(buildShPath))
{
var original = File.ReadAllText(buildShPath);
var modified = original
.Replace("https://github.com/aspnet/KoreBuild/archive/dev.zip", "https://github.com/aspnet/KoreBuild/archive/release.zip");
if (!string.Equals(original, modified, StringComparison.Ordinal))
{
File.WriteAllText(buildShPath, modified);
GitCommand(repo, "add build.sh");
filesChanged = true;
}
}
if (filesChanged)
{
GitCommand(repo, "commit -m \"Updating to release.\"");
}
GitCommand(repo, "push origin release:release");
GitCommand(repo, "checkout origin/dev -B dev");
GitCommand(repo, "merge release -s ours");
GitCommand(repo, "push origin dev:dev");
}
}
#update-master .pull-all
-// Merge release branch to master
-// Pin versions of packages in project.json and updated project.lock.json
-// More information https://github.com/aspnet/Universe/wiki/%23pin-version-:-Pinning-package-version-for-a-particular-release-in-project.json
@{
var koreBuildTag = GetEnvironmentParameter("KOREBUILD_TAG");
var coherenceFeed = GetEnvironmentParameter("COHERENCE_FEED");
if (string.IsNullOrEmpty(coherenceFeed))
{
throw new Exception("COHERENCE_FEED not specified. Usually this is Packages-NoTimestamp directory of Coherence-Signed.");
}
if (string.IsNullOrEmpty(koreBuildTag))
{
throw new Exception("KOREBUILD_TAG environment variable is not specified.");
}
var excludeReposForJson = new[]
{
"Coherence",
"Coherence-Signed",
"dnvm",
"Entropy",
"Setup",
"libuv-build",
};
Exec("dotnet", "restore", "tools/PinVersion");
foreach (var repo in GetAllRepos())
{
GitCommand(repo, "checkout origin/release -B master");
if (File.Exists(Path.Combine(repo, "NuGet.config")))
{
File.Copy(Path.Combine("build-template", "NuGet.master.config"),
Path.Combine(repo, "NuGet.config"),
overwrite: true);
GitCommand(repo, "add NuGet.*");
GitCommand(repo, "commit -m \"Updating NuGet.config\"");
}
}
var reposToPin = GetAllRepos().Except(excludeReposForJson);
var repositoryNamesFile = Path.GetTempFileName();
File.WriteAllLines(repositoryNamesFile, reposToPin.Select(r => Path.Combine(Directory.GetCurrentDirectory(), r)));
var pinToolsArgs = string.Format(@"run -p tools/PinVersion ""{0}"" ""{1}"" ""{2}""",
coherenceFeed,
koreBuildTag,
repositoryNamesFile);
Exec("dotnet", pinToolsArgs, "");
try
{
File.Delete(repositoryNamesFile);
}
catch
{
}
foreach (var repo in reposToPin)
{
var repoPath = Path.Combine(Directory.GetCurrentDirectory(), repo);
try
{
GitCommand(repo, "commit -am \"Updating json files to pin versions and build files to pin KoreBuild\"");
}
catch
{
// Don't fail if there was nothing to add.
}
}
foreach (var repo in GetAllRepos())
{
GitCommand(repo, "push origin +master:master");
}
CallTarget("update-prerelease-tags");
}
#update-prerelease-tags
-// Update tags on each repo to have the latest release tag
@{
var preReleaseTag = GetEnvironmentParameter("PRERELEASETAG");
if (string.IsNullOrEmpty(preReleaseTag))
{
throw new Exception("PRERELEASETAG tag not defined");
}
var versionFile = "version.txt";
foreach (var repo in GetAllRepos())
{
GitCommand(repo, "pull --tags");
string version = null;
try
{
GitCommand(repo, string.Format("describe --tags > ..\\{0}", versionFile));
}
catch
{
version = "1.0.0-" + preReleaseTag;
Log.Warn(string.Format("{0} repo not tagged. Using default version {1}.", repo, version));
}
if (version == null)
{
version = File.ReadAllText(versionFile);
File.Delete(versionFile);
}
Log.Info(string.Format("Current version on repo {0} is {1}", repo, version));
var majorVersion = version.Split(new string[]{"-"}, StringSplitOptions.None)[0];
var newVersion = majorVersion + string.Format("-{0}", preReleaseTag);
Log.Info(string.Format("New version for repo is {0}", newVersion));
GitCommand(repo, string.Format("tag -f -a {0} -m \"Tag for new release {0}\"", newVersion));
GitCommand(repo, "push origin --tags +" + newVersion);
}
}
functions
@{
IEnumerable<string> GetAllRepos()
{
var nonDefaultRepos = new[]
{
"CoreCLR",
"Coherence",
"Coherence-Signed",
"KoreBuild",
"Universe",
"libuv-build",
};
return Enumerable.Concat(nonDefaultRepos, repositories);
}
}

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="AspNetVNext" value="https://www.myget.org/f/aspnetmaster/api/v3/index.json" />
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>

58
build/Repositories.props Normal file
View File

@ -0,0 +1,58 @@
<Project>
<ItemDefinitionGroup>
<Repository>
<Branch>dev</Branch>
<CloneUrl>git@github.com:aspnet/%(Identity)</CloneUrl>
</Repository>
</ItemDefinitionGroup>
<ItemGroup>
<Repository Include="Antiforgery" Commit="" />
<Repository Include="AzureIntegration" Commit="" />
<Repository Include="BasicMiddleware" Commit="" />
<Repository Include="BrowserLink" Commit="" />
<Repository Include="Caching" Commit="" />
<Repository Include="Common" Commit="" />
<Repository Include="Configuration" Commit="" />
<Repository Include="CORS" Commit="" />
<Repository Include="DataProtection" Commit="" />
<Repository Include="DependencyInjection" Commit="" />
<Repository Include="Diagnostics" Commit="" />
<Repository Include="DotNetTools" Commit="" />
<Repository Include="EntityFramework" Commit="" />
<Repository Include="EntityFramework.Tools" Commit="" />
<Repository Include="Entropy" Commit="" />
<Repository Include="EventNotification" Commit="" />
<Repository Include="FileSystem" Commit="" />
<Repository Include="Hosting" Commit="" />
<Repository Include="HtmlAbstractions" Commit="" />
<Repository Include="HttpAbstractions" Commit="" />
<Repository Include="HttpSysServer" Commit="" />
<Repository Include="Identity" Commit="" />
<Repository Include="IdentityService" Commit="" />
<Repository Include="IISIntegration" Commit="" />
<Repository Include="JsonPatch" Commit="" />
<Repository Include="KestrelHttpServer" Commit="" />
<Repository Include="Localization" Commit="" />
<Repository Include="Logging" Commit="" />
<Repository Include="MetaPackages" Commit="" />
<Repository Include="Microsoft.Data.Sqlite" Commit="" />
<Repository Include="MusicStore" Commit="" />
<Repository Include="Mvc" Commit="" />
<Repository Include="MvcPrecompilation" Commit="" />
<Repository Include="Options" Commit="" />
<Repository Include="PlatformAbstractions" Commit="" />
<Repository Include="Proxy" Commit="" />
<Repository Include="Razor" Commit="" />
<Repository Include="ResponseCaching" Commit="" />
<Repository Include="Routing" Commit="" />
<Repository Include="Scaffolding" Commit="" />
<Repository Include="Security" Commit="" />
<Repository Include="ServerTests" Commit="" />
<Repository Include="Session" Commit="" />
<Repository Include="SignalR" Commit="" />
<Repository Include="StaticFiles" Commit="" />
<Repository Include="Testing" Commit="" />
<Repository Include="WebSockets" Commit="" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,83 @@
<Project>
<Import Project="$(_BuildGraphFile)" />
<Target Name="BuildRepositories">
<ItemGroup>
<BatchedRepository Include="$(MSBuildProjectFullPath)">
<AdditionalProperties>
RepositoryToBuild=%(RepositoryToBuildInOrder.Identity);
BuildRepositoryRoot=$(_CloneRepositoryRoot)%(RepositoryToBuildInOrder.Identity)\
</AdditionalProperties>
<BuildGroup>%(RepositoryToBuildInOrder.Order)</BuildGroup>
</BatchedRepository>
</ItemGroup>
<PropertyGroup>
<BatchBuilds Condition="$(BuildInParallel) AND '$(CompileOnly)'=='true'">true</BatchBuilds>
<BatchBuilds Condition="'$(BatchBuilds)'==''">false</BatchBuilds>
</PropertyGroup>
<MSBuild
Projects="@(BatchedRepository)"
BuildInParallel="$(BatchBuilds)"
Targets="_BuildRepository"
Properties="BuildGroup=%(BatchedRepository.BuildGroup)" />
</Target>
<Target Name="_BuildRepository" DependsOnTargets="_PinVersions">
<PropertyGroup>
<RepositoryKoreBuildDirectory>$(BuildRepositoryRoot).build\</RepositoryKoreBuildDirectory>
<RepositoryArtifactsDirectory>$(BuildRepositoryRoot)artifacts\build\</RepositoryArtifactsDirectory>
</PropertyGroup>
<ItemGroup>
<KoreBuildFiles Include="$(KoreBuildDirectory)**\*" />
</ItemGroup>
<Message Text="============ Building $(RepositoryToBuild) ============" Importance="High" />
<Copy SourceFiles="@(KoreBuildFiles)" DestinationFolder="$(RepositoryKoreBuildDirectory)%(RecursiveDir)" />
<ItemGroup>
<RepositoryKoreBuildProject Include="$(RepositoryKoreBuildDirectory)$(KoreBuildProject)">
<AdditionalProperties>
RepositoryRoot=$(BuildRepositoryRoot);
BuildNumber=$(BuildNumber);
Configuration=$(Configuration)
</AdditionalProperties>
</RepositoryKoreBuildProject>
</ItemGroup>
<MSBuild
Projects="@(RepositoryKoreBuildProject)"
Targets="Restore"
Properties="PreflightRestore=true" />
<MSBuild
Projects="@(RepositoryKoreBuildProject)"
Targets="$(_RepositoryBuildTargets)" />
<ItemGroup>
<RepositoryArtifacts Include="$(RepositoryArtifactsDirectory)*" />
</ItemGroup>
<Copy
SourceFiles="@(RepositoryArtifacts)"
DestinationFolder="$(UniverseBuildDir)" />
<Exec
Command="$(DotNetPath) nuget push &quot;%(RepositoryArtifacts.Identity)&quot; -s $(NuGetFeed) -k $(APIKEY)"
Condition="'$(PublishPackages)'=='true' AND '%(RepositoryArtifacts.Extension)'=='.nupkg'" />
<Message Text="============ Done building $(RepositoryToBuild) ============" Importance="High" />
</Target>
<Target Name="_PinVersions">
<PropertyGroup>
<PinToolBinary>$(RepositoryRoot)tools\PinVersions\bin\$(Configuration)\netcoreapp1.1\PinVersions.dll</PinToolBinary>
<PinVersionArgs>$(DotNetPath) $(PinToolBinary) --graph-specs-root &quot;$(_RestoreGraphSpecsDirectory) &quot; -s &quot;$(UniverseBuildDir) &quot; &quot;$(BuildRepositoryRoot) &quot;</PinVersionArgs>
<PinVersionArgs Condition="Exists('$(_DependencyPackagesDirectory)')">$(PinVersionArgs) -s &quot;$(_DependencyPackagesDirectory) &quot;</PinVersionArgs>
</PropertyGroup>
<Exec Command="$(PinVersionArgs)" />
</Target>
</Project>

View File

@ -1,6 +0,0 @@
<Project>
<PropertyGroup>
<DisableDefaultItems>true</DisableDefaultItems>
<DisableDefaultTargets>true</DisableDefaultTargets>
</PropertyGroup>
</Project>

View File

@ -1,56 +1,220 @@
<Project>
<PropertyGroup>
<_SakeTargets Condition="'$(Configuration)' == 'Release'">--config-release</_SakeTargets>
<NuGetPublishVolatileFeed>https://dotnet.myget.org/F/aspnetcore-volatile-dev/api/v2/package</NuGetPublishVolatileFeed>
<_BuildGraphFile>$(BuildDir)BuildGraph.proj</_BuildGraphFile>
<_CloneRepositoryRoot>$(RepositoryRoot).r\</_CloneRepositoryRoot>
<_DependencyPackagesDirectory>$(RepositoryRoot).deps\build\</_DependencyPackagesDirectory>
<_CommitsFile>$(RepositoryRoot).deps\build\RepositoryCommits.proj</_CommitsFile>
<_RestoreGraphSpecsDirectory>$(RepositoryRoot)obj\package-specs\</_RestoreGraphSpecsDirectory>
<_RepositoryBuildTargets Condition="'$(_RepositoryBuildTargets)'=='' AND '$(CompileOnly)'=='true'">Package;VerifyPackages</_RepositoryBuildTargets>
<_RepositoryBuildTargets Condition="'$(_RepositoryBuildTargets)'==''">Verify</_RepositoryBuildTargets>
<_RepositoriesWithCommitsFile>$(RepositoryRoot).deps\build\Repositories.props</_RepositoriesWithCommitsFile>
<PrepareDependsOn>$(PrepareDependsOn);CleanUniverseArtifacts</PrepareDependsOn>
<CleanDependsOn>$(CleanDependsOn);CleanUniverseArtifacts</CleanDependsOn>
<BuildDependsOn>$(BuildDependsOn);CloneRepositories;BuildRepositories</BuildDependsOn>
</PropertyGroup>
<!-- workaround. Using Sake as the intermediate means this property doesn't flow into repo builds. -->
<Target Name="SetBuildNumber" Condition="'$(BuildNumber)' != ''">
<SetEnvironmentVariable Variable="BuildNumber" Value="$(BuildNumber)" />
<Import
Project="$(_RepositoriesWithCommitsFile)"
Condition="Exists('$(_RepositoriesWithCommitsFile)')" />
<Import
Project="Repositories.props"
Condition="!Exists('$(_RepositoriesWithCommitsFile)')" />
<Import
Project="$(_CommitsFile)"
Condition="Exists('$(_CommitsFile)')" />
<Target Name="CleanUniverseArtifacts">
<RemoveDir Directories="$(RepositoryRoot)obj" Condition="Exists('$(RepositoryRoot)obj')" />
<RemoveDir Directories="$(_CloneRepositoryRoot)" Condition="Exists('$(_CloneRepositoryRoot)')" />
</Target>
<Target Name="VerifyAll">
<Target Name="_FilterRepositories">
<ItemGroup Condition="'$(KOREBUILD_REPOSITORY_INCLUDE)'!=''">
<_RepositoriesToInclude Include="$(KOREBUILD_REPOSITORY_INCLUDE)" />
<Repository
Remove="@(Repository)"
Condition="'@(Repository)'!='@(_RepositoriesToInclude)' AND '%(Identity)'!=''" />
</ItemGroup>
<ItemGroup Condition="'$(KOREBUILD_REPOSITORY_EXCLUDE)'!=''">
<RepositoriesToExclude Include="$(KOREBUILD_REPOSITORY_EXCLUDE)" />
<Repository Remove="@(RepositoriesToExclude)" />
</ItemGroup>
<Error Text="KOREBUILD_REPOSITORY_EXCLUDE AND KOREBUILD_REPOSITORY_INCLUDE are specified."
Condition="'$(KOREBUILD_REPOSITORY_INCLUDE)' != '' AND '$(KOREBUILD_REPOSITORY_EXCLUDE)' != ''" />
<Message Text="%(Repository.CloneUrl)" />
</Target>
<Target Name="CloneRepositories" DependsOnTargets="_FilterRepositories">
<ItemGroup>
<_CloneRepository Include="$(MSBuildProjectFullPath)">
<AdditionalProperties>
CloneRepository=%(Repository.Identity);
CloneUrl=%(Repository.CloneUrl);
CloneBranch=%(Repository.Branch);
CloneRepositoryCommit=%(Repository.Commit);
UseGateBranch=$(UseGateBranch)
</AdditionalProperties>
</_CloneRepository>
</ItemGroup>
<MakeDir Directories="$(_CloneRepositoryRoot)" />
<MSBuild Projects="@(_CloneRepository)"
Targets="_CloneRepository"
BuildInParallel="$(BuildInParallel)" />
</Target>
<Target Name="_CloneRepository">
<PropertyGroup>
<_SakeTargets>$(_SakeTargets):verify-all</_SakeTargets>
<ShallowClone Condition="'$(ShallowClone)'=='' OR '$(CloneRepositoryCommit)'!=''">false</ShallowClone>
<_CloneArguments>git clone --quiet $(CloneUrl)</_CloneArguments>
<_CloneArguments Condition="'$(ShallowClone)'=='true'">$(_CloneArguments) --depth 1</_CloneArguments>
</PropertyGroup>
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=$(_SakeTargets);RepositoryRoot=$(RepositoryRoot)" />
<Message Text="Cloning $(CloneRepository) ..." Importance="High" />
<Exec
Command="$(_CloneArguments) --branch $(CloneBranch)-gate"
Condition="'$(UseGateBranch)'=='true'"
IgnoreExitCode="true"
IgnoreStandardErrorWarningFormat="true"
WorkingDirectory="$(_CloneRepositoryRoot)">
<Output TaskParameter="ExitCode" PropertyName="GateBranchExitCode" />
</Exec>
<Warning Text="Using $(CloneBranch)-gate for $(CloneRepository)"
Condition="'$(GateBranchExitCode)'=='0'" />
<Exec
Command="$(_CloneArguments) --branch $(CloneBranch)"
Condition="'$(GateBranchExitCode)'!='0'"
WorkingDirectory="$(_CloneRepositoryRoot)" />
<Exec
Command="git reset --quiet --hard $(CloneRepositoryCommit)"
WorkingDirectory="$(_CloneRepositoryRoot)$(CloneRepository)"
Condition="'$(CloneRepositoryCommit)'!=''" />
</Target>
<Target Name="CIBuild" DependsOnTargets="SetBuildNumber">
<Target Name="BuildRepositories"
DependsOnTargets="_FilterRepositories;_FindDotNetPath;_GenerateRestoreGraphSpecs;_GenerateBuildGraph;_UpdateNuGetConfig;_CreateRepositoriesListWithCommits">
<PropertyGroup>
<_SakeTargets>$(_SakeTargets):ci-build</_SakeTargets>
<_BuildRepositoryProperties>
UniverseBuildDir=$(BuildDir);
BuildInParallel=$(BuildInParallel);
BuildNumber=$(BuildNumber);
Configuration=$(Configuration);
DotNetPath=$(DotNetPath);
KoreBuildDirectory=$(MSBuildProjectDirectory)\;
KoreBuildProject=$(MSBuildProjectFile);
RepositoryRoot=$(RepositoryRoot);
_BuildGraphFile=$(_BuildGraphFile);
_CloneRepositoryRoot=$(_CloneRepositoryRoot);
_DependencyPackagesDirectory=$(_DependencyPackagesDirectory);
_RepositoryBuildTargets=$(_RepositoryBuildTargets);
_RestoreGraphSpecsDirectory=$(_RestoreGraphSpecsDirectory)
</_BuildRepositoryProperties>
</PropertyGroup>
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=$(_SakeTargets);RepositoryRoot=$(RepositoryRoot)" />
<MSBuild
Projects="$(MSBuildThisFileDirectory)RepositoryBuild.targets"
Targets="BuildRepositories"
Properties="$(_BuildRepositoryProperties)" />
<MSBuild
Projects="$(MSBuildThisFileDirectory)PublishPackages.targets"
Condition="'$(PublishPackages)'=='true'"
Properties="
PackagesDirectory=$(ArtifactsDir);
DotNetPath=$(DotNetPath);
NuGetFeed=$(NuGetPublishFeed);
APIKey=$(APIKey)" />
</Target>
<Target Name="CITest" DependsOnTargets="SetBuildNumber">
<PropertyGroup>
<_SakeTargets>$(_SakeTargets):ci-test</_SakeTargets>
<Target Name="_GenerateRestoreGraphSpecs" DependsOnTargets="_FindDotNetPath">
<ItemGroup>
<Solution Include="$(_CloneRepositoryRoot)%(Repository.Identity)\*.sln">
<Repository>%(Repository.Identity)</Repository>
</Solution>
<Solution>
<AdditionalProperties>RestoreGraphOutputPath=$(_RestoreGraphSpecsDirectory)%(Solution.Repository)\%(Solution.FileName)%(Solution.Extension).json</AdditionalProperties>
</Solution>
</ItemGroup>
<MSBuild
Projects="@(Solution)"
Targets="GenerateRestoreGraphFile"
BuildInParallel="$(BuildInParallel)" />
</Target>
<Target Name="_GenerateBuildGraph" DependsOnTargets="_FindDotNetPath">
<Exec
Command="$(DotNetPath) run -r &quot;$(_CloneRepositoryRoot) &quot; --graph-specs-root &quot;$(_RestoreGraphSpecsDirectory) &quot; &quot;$(_BuildGraphFile)&quot;"
WorkingDirectory="$(RepositoryRoot)tools\BuildGraph\" />
</Target>
<Target Name="_UpdateNuGetConfig">
<UpdatePackageSource
NuGetConfigPath="$(_CloneRepositoryRoot)%(Repository.Identity)\NuGet.config"
SourceName="Dependencies"
SourceUri="$(_DependencyPackagesDirectory)"
Condition="Exists('$(_DependencyPackagesDirectory)')" />
<MakeDir Directories="$(BuildDir)" Condition="!Exists('$(BuildDir)')" />
<UpdatePackageSource
NuGetConfigPath="$(_CloneRepositoryRoot)%(Repository.Identity)\NuGet.config"
SourceName="Artifacts"
SourceUri="$(BuildDir)" />
</Target>
<Target Name="_CreateRepositoriesListWithCommits" DependsOnTargets="_GetRepositoryCommits">
<PropertyGroup>
<RepositoryFileWithCommit>$(BuildDir)Repositories.props</RepositoryFileWithCommit>
</PropertyGroup>
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=$(_SakeTargets);RepositoryRoot=$(RepositoryRoot)" />
<Copy
SourceFiles="$(MSBuildThisFileDirectory)Repositories.props"
DestinationFiles="$(RepositoryFileWithCommit)" />
<XmlPoke2
XmlInputPath="$(RepositoryFileWithCommit)"
Query="//Repository[@Include='%(Repository.Identity)']/@Commit"
Value="%(Repository.Commit)" />
</Target>
<Target Name="CIPull">
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=ci-pull;RepositoryRoot=$(RepositoryRoot)" />
<!-- Based on the solution here: http://stackoverflow.com/a/11331566 -->
<Target Name="_GetRepositoryCommits" Outputs="%(Repository.Identity)">
<PropertyGroup>
<RepositoryCloneDirectory>$(_CloneRepositoryRoot)%(Repository.Identity)</RepositoryCloneDirectory>
</PropertyGroup>
<Error Text="%(Repository.Identity) has not been cloned."
Condition="!Exists('$(RepositoryCloneDirectory)')" />
<GetGitCommitInfo WorkingDirectory="$(RepositoryCloneDirectory)">
<Output TaskParameter="CommitHash" PropertyName="_Hash" />
</GetGitCommitInfo>
<ItemGroup>
<Repository Update="%(Identity)" Commit="$(_Hash)" />
</ItemGroup>
<PropertyGroup>
<_Hash></_Hash>
</PropertyGroup>
</Target>
<Target Name="UpdateRepos">
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=update;RepositoryRoot=$(RepositoryRoot)" />
<Target Name="_FindDotNetPath">
<GetDotNetHost>
<Output TaskParameter="ExecutablePath" PropertyName="DotNetPath" />
</GetDotNetHost>
</Target>
<Target Name="CleanAll">
<MSBuild Projects="$(MSBuildProjectFullPath)"
Targets="Sake"
Properties="SakeTargets=git-clean;RepositoryRoot=$(RepositoryRoot)" />
</Target>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\shared\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.Cli.Utils" Version="1.0.1" />
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace BuildGraph
{
public class DGMLFormatter : GraphFormatter
{
public override void Format(IList<GraphNode> nodes, string outputPath)
{
var xmlns = XNamespace.Get("http://schemas.microsoft.com/vs/2009/dgml");
var xdoc = new XDocument(
new XElement(xmlns + "DirectedGraph",
new XElement(xmlns + "Nodes", GetNodes(xmlns, nodes).ToArray()),
new XElement(xmlns + "Links", GetLinks(xmlns, nodes).ToArray()),
new XElement(xmlns + "Properties", GetProperties(xmlns).ToArray())));
using (var writer = File.OpenWrite(outputPath))
{
xdoc.Save(writer);
}
}
private IEnumerable<XElement> GetLinks(XNamespace xmlns, IEnumerable<GraphNode> nodes)
{
foreach (var node in nodes)
{
foreach (var outgoing in node.Outgoing)
{
yield return new XElement(xmlns + "Link",
new XAttribute("Source", node.Repository.Name),
new XAttribute("Target", outgoing.Repository.Name));
}
}
}
private IEnumerable<XElement> GetNodes(XNamespace xmlns, IEnumerable<GraphNode> nodes)
{
foreach (var node in nodes)
{
yield return new XElement(xmlns + "Node",
new XAttribute("Id", node.Repository.Name),
new XAttribute("Label", $"{node.Repository.Name}"));
}
}
private IEnumerable<XElement> GetProperties(XNamespace xmlns)
{
yield return new XElement(xmlns + "Property",
new XAttribute("Id", "Label"),
new XAttribute("Label", "Label"),
new XAttribute("DataType", "String"));
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BuildGraph
{
public static class GraphBuilder
{
public static IList<GraphNode> Generate(IList<Repository> repositories)
{
// Build global list of primary projects
var primaryProjects = repositories.SelectMany(c => c.Projects)
.ToDictionary(p => p.Name, StringComparer.OrdinalIgnoreCase);
var graphNodes = repositories.Select(r => new GraphNode { Repository = r })
.ToDictionary(r => r.Repository);
foreach (var project in repositories.SelectMany(r => r.AllProjects))
{
var thisProjectRepositoryNode = graphNodes[project.Repository];
foreach (var packageDependency in project.PackageReferences)
{
if (primaryProjects.TryGetValue(packageDependency, out var dependencyProject))
{
var dependencyRepository = dependencyProject.Repository;
var dependencyNode = graphNodes[dependencyRepository];
thisProjectRepositoryNode.Incoming.Add(dependencyNode);
dependencyNode.Outgoing.Add(thisProjectRepositoryNode);
}
}
}
return graphNodes.Values.ToList();
}
}
}

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace BuildGraph
{
public abstract class GraphFormatter
{
public abstract void Format(IList<GraphNode> nodes, string outputPath);
}
}

View File

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace BuildGraph
{
[DebuggerDisplay("{Repository.Name}")]
public class GraphNode
{
public Repository Repository { get; set; }
public ISet<GraphNode> Incoming { get; } = new HashSet<GraphNode>();
public ISet<GraphNode> Outgoing { get; } = new HashSet<GraphNode>();
}
}

View File

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace BuildGraph
{
public class MSBuildGraphFormatter : GraphFormatter
{
public override void Format(IList<GraphNode> nodes, string outputPath)
{
var sortedNodes = nodes.Select(node => new { Repository = node.Repository, Order = TopologicalSort.GetOrder(node) })
.OrderBy(item => item.Order);
var projectElement = new XElement("Project",
new XElement("ItemGroup",
sortedNodes.Select(item => new XElement("RepositoryToBuildInOrder",
new XAttribute("Include", item.Repository.Name),
new XAttribute("Order", item.Order)))));
File.WriteAllText(outputPath, projectElement.ToString());
}
}
}

View File

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.CommandLineUtils;
using UniverseTools;
namespace BuildGraph
{
class Program
{
static int Main(string[] args)
{
var app = new CommandLineApplication();
var outputTypeOption = app.Option("--output-type",
"Output type of generated graph. Valid values are: msbuild, and dgml.",
CommandOptionType.SingleValue);
var repositoriesRootOption = app.Option("-r|--repositories-root",
"Directory containing repositories to calculate graph for.",
CommandOptionType.SingleValue);
var packageSpecsDirectoryOption = app.Option("--graph-specs-root",
"Directory containing package specs. (Optional)",
CommandOptionType.SingleValue);
var outputPathArgument = app.Argument("Output path", "Output path");
app.OnExecute(() =>
{
if (!repositoriesRootOption.HasValue())
{
Console.Error.WriteLine($"Option {repositoriesRootOption.Template} must have a value.");
return 1;
}
var outputPath = outputPathArgument.Value;
if (string.IsNullOrEmpty(outputPath))
{
Console.Error.WriteLine($"Output path not specified.");
return 1;
}
var outputDirectory = Path.GetDirectoryName(outputPath);
Directory.CreateDirectory(outputDirectory);
var outputType = outputTypeOption.Value() ?? "msbuild";
var graphSpecProvider = packageSpecsDirectoryOption.HasValue()
? new DependencyGraphSpecProvider(packageSpecsDirectoryOption.Value().Trim())
: DependencyGraphSpecProvider.Default;
IList<Repository> repositories;
using (graphSpecProvider)
{
repositories = Repository.ReadAllRepositories(repositoriesRootOption.Value().Trim(), graphSpecProvider);
}
var graph = GraphBuilder.Generate(repositories);
GraphFormatter formatter;
switch (outputType)
{
case "msbuild":
formatter = new MSBuildGraphFormatter();
break;
case "dgml":
formatter = new DGMLFormatter();
break;
default:
app.Error.WriteLine($"Unknown output type: {outputType}.");
return 1;
}
formatter.Format(graph, outputPathArgument.Value);
return 0;
});
return app.Execute(args);
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace BuildGraph
{
[DebuggerDisplay("{Name}")]
public class Project
{
public Project(string name)
{
Name = name;
}
public string Name { get; }
public Repository Repository { get; set; }
public IList<string> PackageReferences { get; set; } = Array.Empty<string>();
}
}

View File

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using NuGet.LibraryModel;
using NuGet.ProjectModel;
using UniverseTools;
namespace BuildGraph
{
[DebuggerDisplay("{Name}")]
public class Repository : IEquatable<Repository>
{
public Repository(string name)
{
Name = name;
}
public string Name { get; private set; }
public IList<Project> Projects { get; } = new List<Project>();
public IList<Project> SupportProjects { get; } = new List<Project>();
public IEnumerable<Project> AllProjects => Projects.Concat(SupportProjects);
public static IList<Repository> ReadAllRepositories(string repositoriesRoot, DependencyGraphSpecProvider provider)
{
var directories = new DirectoryInfo(repositoriesRoot).GetDirectories();
var repositories = new Repository[directories.Length];
var sw = Stopwatch.StartNew();
Parallel.For(0, directories.Length, new ParallelOptions { MaxDegreeOfParallelism = 6 }, i =>
{
var directoryInfo = directories[i];
Console.WriteLine($"Gathering dependency information from {directoryInfo.Name}.");
var repository = Read(provider, directoryInfo.Name, directoryInfo.FullName);
repositories[i] = repository;
Console.WriteLine($"Done gathering dependency information from {directoryInfo.Name}.");
});
sw.Stop();
Console.WriteLine($"Done reading dependency information for all repos in {sw.Elapsed}.");
return repositories;
}
public bool Equals(Repository other) => string.Equals(Name, other.Name, StringComparison.OrdinalIgnoreCase);
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Name);
private static Repository Read(DependencyGraphSpecProvider provider, string name, string repositoryPath)
{
var repository = new Repository(name);
ReadSharedSourceProjects(Path.Combine(repositoryPath, "shared"), repository, repository.Projects);
var srcDirectory = Path.Combine(repositoryPath, "src");
var solutionFiles = Directory.EnumerateFiles(repositoryPath, "*.sln");
var knownProjects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var file in solutionFiles)
{
var spec = provider.GetDependencyGraphSpec(name, file);
foreach (var specProject in spec.Projects)
{
if (!knownProjects.Add(specProject.FilePath) ||
specProject.RestoreMetadata.ProjectStyle != ProjectStyle.PackageReference)
{
continue;
}
var projectPath = Path.GetFullPath(specProject.FilePath);
var project = new Project(specProject.Name)
{
PackageReferences = GetPackageReferences(specProject),
Repository = repository,
};
var projectGroup = projectPath.StartsWith(srcDirectory, StringComparison.OrdinalIgnoreCase) ?
repository.Projects :
repository.SupportProjects;
projectGroup.Add(project);
}
}
return repository;
}
private static List<string> GetPackageReferences(NuGet.ProjectModel.PackageSpec specProject)
{
var allDependencies = Enumerable.Concat(
specProject.Dependencies,
specProject.TargetFrameworks.SelectMany(tfm => tfm.Dependencies))
.Distinct();
var packageReferences = allDependencies
.Where(d => d.LibraryRange.TypeConstraintAllows(LibraryDependencyTarget.Package))
.Select(d => d.Name)
.ToList();
return packageReferences;
}
private static void ReadSharedSourceProjects(string sharedSourceProjectsRoot, Repository repository, IList<Project> projects)
{
if (!Directory.Exists(sharedSourceProjectsRoot))
{
return;
}
foreach (var directory in new DirectoryInfo(sharedSourceProjectsRoot).EnumerateDirectories())
{
var project = new Project(directory.Name)
{
Repository = repository,
};
projects.Add(project);
}
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace BuildGraph
{
public class TopologicalSort : IComparer<GraphNode>
{
public static readonly TopologicalSort Instance = new TopologicalSort();
public int Compare(GraphNode x, GraphNode y)
{
var xScore = GetOrder(x);
var yScore = GetOrder(y);
return xScore.CompareTo(yScore);
}
public static int GetOrder(GraphNode node)
{
var visited = new List<GraphNode>();
return GetOrder(node, visited);
}
private static int GetOrder(GraphNode node, List<GraphNode> visited)
{
if (visited.Contains(node))
{
var cycle = string.Join(" -> ", visited.Select(v => v.Repository.Name));
throw new Exception($"Cycle detected in the build graph: {cycle} -> {node.Repository.Name}.");
}
var score = 0;
visited.Add(node);
foreach (var dependentNode in node.Incoming)
{
score = Math.Max(score, GetOrder(dependentNode, visited));
}
visited.RemoveAt(visited.Count - 1);
return score + 1;
}
}
}

View File

@ -1,22 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinVersion", "PinVersion\PinVersion.xproj", "{3D3B5750-0C24-4F1C-9304-B5E4D85CF5A0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3D3B5750-0C24-4F1C-9304-B5E4D85CF5A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D3B5750-0C24-4F1C-9304-B5E4D85CF5A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D3B5750-0C24-4F1C-9304-B5E4D85CF5A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D3B5750-0C24-4F1C-9304-B5E4D85CF5A0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>3d3b5750-0c24-4f1c-9304-b5e4d85cf5a0</ProjectGuid>
<RootNamespace>PinVersion</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,125 +0,0 @@
// 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.Concurrent;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NuGet.Common;
using NuGet.Protocol.Core.Types;
using NuGet.Protocol.Core.v3;
using NuGet.Versioning;
namespace PinVersion
{
public class Program
{
private static ConcurrentDictionary<string, Task<NuGetVersion>> _packageVersionLookup =
new ConcurrentDictionary<string, Task<NuGetVersion>>(StringComparer.OrdinalIgnoreCase);
public static void Main(string[] args)
{
if (args.Length != 3)
{
Console.Error.WriteLine("Usage <package source> <Korebuild Tag> <repository-names-file>");
}
var packageSource = args[0];
var korebuildTag = args[1];
var repositoryNames = File.ReadAllLines(args[2]);
Task.WaitAll(repositoryNames
.Select(repositoryPath => ExecuteAsync(repositoryPath, packageSource, korebuildTag))
.ToArray());
}
public static async Task ExecuteAsync(string repositoryPath, string packageSource, string korebuildTag)
{
var packageRepository = Repository.Factory.GetCoreV3(packageSource);
var metadataResource = await packageRepository.GetResourceAsync<MetadataResource>();
// Pin project.json files
foreach (var file in Directory.EnumerateFiles(repositoryPath, "project.json", SearchOption.AllDirectories))
{
var projectJson = JObject.Parse(File.ReadAllText(file));
var projectName = Path.GetFileName(Path.GetDirectoryName(file));
var latestPackageVersion = await GetOrAddVersion(metadataResource, projectName);
if (latestPackageVersion != null)
{
((JValue)projectJson["version"]).Value = latestPackageVersion.ToNormalizedString();
}
var frameworkDependencies = projectJson["frameworks"]
?.Cast<JProperty>()
?.Select(f => ((JObject)f.Value)["dependencies"])
?? Enumerable.Empty<JToken>();
var dependencies = Enumerable.Concat(new[] { projectJson["dependencies"] }, frameworkDependencies)
.Where(d => d != null)
.SelectMany(d => d)
.Cast<JProperty>();
foreach (var dependency in dependencies)
{
latestPackageVersion = await GetOrAddVersion(metadataResource, dependency.Name);
if (latestPackageVersion != null)
{
if (dependency.Value.Type == JTokenType.Object)
{
// "key": { "version": "1.0.0-*", "type": "build" }
var value = (JObject)dependency.Value;
value["version"] = latestPackageVersion.ToNormalizedString();
}
else
{
// "key": "version"
dependency.Value = latestPackageVersion.ToNormalizedString();
}
}
}
using (var fileWriter = new JsonTextWriter(new StreamWriter(file)))
{
fileWriter.Formatting = Formatting.Indented;
fileWriter.Indentation = 2;
projectJson.WriteTo(fileWriter);
}
// Update KoreBuild path
var buildFiles = new[] { "build.ps1", "build.sh" };
foreach (var buildFile in buildFiles)
{
var buildFilePath = Path.Combine(repositoryPath, buildFile);
if (File.Exists(buildFilePath))
{
var content = File.ReadAllText(buildFilePath);
var replaced = content.Replace("KoreBuild/archive/release.zip", $"KoreBuild/archive/{korebuildTag}.zip");
if (content != replaced)
{
File.WriteAllText(buildFilePath, replaced);
}
}
}
}
}
private static Task<NuGetVersion> GetOrAddVersion(MetadataResource resource, string packageId)
{
return _packageVersionLookup.GetOrAdd(packageId, id =>
{
return resource.GetLatestVersion(
packageId,
includePrerelease: true,
includeUnlisted: false,
log: NullLogger.Instance,
token: default(CancellationToken));
});
}
}
}

View File

@ -1,13 +0,0 @@
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Newtonsoft.Json": "9.0.1",
"NuGet.Protocol.Core.v3": "3.5.0-beta-final"
},
"frameworks": {
"net451": { }
}
}

View File

@ -0,0 +1,139 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using NuGet.Common;
using NuGet.Frameworks;
using NuGet.LibraryModel;
using NuGet.ProjectModel;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
using UniverseTools;
namespace PinVersions
{
class PinVersionUtility
{
private readonly string _repositoryRoot;
private readonly FindPackageByIdResource[] _findPackageResources;
private readonly ConcurrentDictionary<string, Task<NuGetVersion>> _exactMatches = new ConcurrentDictionary<string, Task<NuGetVersion>>(StringComparer.OrdinalIgnoreCase);
private readonly DependencyGraphSpecProvider _provider;
private readonly SourceCacheContext _sourceCacheContext;
public PinVersionUtility(string repositoryRoot, List<string> pinSources, DependencyGraphSpecProvider provider)
{
_repositoryRoot = repositoryRoot;
_findPackageResources = new FindPackageByIdResource[pinSources.Count];
for (var i = 0; i < pinSources.Count; i++)
{
var repository = FactoryExtensionsV3.GetCoreV3(Repository.Factory, pinSources[i].Trim());
_findPackageResources[i] = repository.GetResource<FindPackageByIdResource>();
}
_provider = provider;
_sourceCacheContext = new SourceCacheContext();
}
public void Execute()
{
var repositoryDirectoryInfo = new DirectoryInfo(_repositoryRoot);
var knownProjects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var slnFile in repositoryDirectoryInfo.EnumerateFiles("*.sln"))
{
var graphSpec = _provider.GetDependencyGraphSpec(repositoryDirectoryInfo.Name, slnFile.FullName);
foreach (var specProject in graphSpec.Projects)
{
if (!knownProjects.Add(specProject.FilePath) ||
specProject.RestoreMetadata.ProjectStyle != ProjectStyle.PackageReference)
{
continue;
}
var projectFileInfo = new FileInfo(specProject.FilePath);
var pinnedReferencesFile = Path.Combine(
specProject.RestoreMetadata.OutputPath,
projectFileInfo.Name + ".pinnedversions.targets");
Directory.CreateDirectory(Path.GetDirectoryName(pinnedReferencesFile));
var allDependencies = specProject.Dependencies.Select(dependency => new { Dependency = dependency, FrameworkName = NuGetFramework.AnyFramework })
.Concat(specProject.TargetFrameworks.SelectMany(tfm => tfm.Dependencies.Select(dependency => new { Dependency = dependency, tfm.FrameworkName })))
.Where(d => d.Dependency.LibraryRange.TypeConstraintAllows(LibraryDependencyTarget.Package));
var packageReferencesItemGroup = new XElement("ItemGroup");
foreach (var dependency in allDependencies)
{
var reference = dependency.Dependency;
var versionRange = reference.LibraryRange.VersionRange;
if (!versionRange.IsFloating)
{
continue;
}
var exactVersion = GetExactVersion(reference.Name, versionRange);
if (exactVersion == null)
{
continue;
}
var metadata = new List<XAttribute>
{
new XAttribute("Update", reference.Name),
new XAttribute("Version", exactVersion.ToNormalizedString()),
};
if (dependency.FrameworkName != NuGetFramework.AnyFramework)
{
metadata.Add(new XAttribute("Condition", $"'$(TargetFramework)'=='{dependency.FrameworkName.GetShortFolderName()}'"));
}
packageReferencesItemGroup.Add(new XElement("PackageReference", metadata));
}
var pinnedVersionRoot = new XElement("Project", packageReferencesItemGroup);
File.WriteAllText(pinnedReferencesFile, pinnedVersionRoot.ToString());
}
}
}
private NuGetVersion GetExactVersion(string name, VersionRange range)
{
if (range.MinVersion == null)
{
throw new Exception($"Unsupported version range {range}.");
}
if (!_exactMatches.TryGetValue(name, out var versionTask))
{
versionTask = _exactMatches.GetOrAdd(name, GetExactVersionAsync(name, range.MinVersion));
}
return versionTask.Result;
}
private async Task<NuGetVersion> GetExactVersionAsync(string name, NuGetVersion floatingVersion)
{
foreach (var findPackageResource in _findPackageResources)
{
var packageVersions = await findPackageResource.GetAllVersionsAsync(name, _sourceCacheContext, NullLogger.Instance, default(CancellationToken));
var matchingVersions = packageVersions.Where(v => v.Version == floatingVersion.Version).ToList();
switch (matchingVersions.Count)
{
case 0:
return null;
case 1:
return matchingVersions[0];
default:
throw new Exception($"More than one version for {name} found that matches the specified version constraint: {string.Join(" ", matchingVersions)}.");
}
}
return null;
}
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\shared\*.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.DotNet.Cli.Utils" Version="1.0.1" />
<PackageReference Include="Microsoft.Extensions.CommandLineUtils" Version="1.1.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,53 @@
using System;
using Microsoft.Extensions.CommandLineUtils;
using UniverseTools;
namespace PinVersions
{
class Program
{
static int Main(string[] args)
{
var app = new CommandLineApplication();
var pinSourceOption = app.Option("-s|--source",
"Feed containing packages to pin.",
CommandOptionType.MultipleValue);
var packageSpecsDirectoryOption = app.Option("--graph-specs-root",
"Directory containing package specs. (Optional)",
CommandOptionType.SingleValue);
var repositoryArgument = app.Argument("Repository", "Repository directory");
app.OnExecute(() =>
{
if (!pinSourceOption.HasValue())
{
Console.Error.WriteLine($"Option {pinSourceOption.Template} must have a value.");
return 1;
}
if (string.IsNullOrEmpty(repositoryArgument.Value))
{
Console.Error.WriteLine($"Repository argument must be specified.");
return 1;
}
var graphSpecProvider = packageSpecsDirectoryOption.HasValue() ?
new DependencyGraphSpecProvider(packageSpecsDirectoryOption.Value().Trim()) :
DependencyGraphSpecProvider.Default;
using (graphSpecProvider)
{
var pinVersionUtility = new PinVersionUtility(repositoryArgument.Value.Trim(), pinSourceOption.Values, graphSpecProvider);
pinVersionUtility.Execute();
}
return 0;
});
return app.Execute(args);
}
}
}

View File

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Microsoft.DotNet.Cli.Utils;
using NuGet.ProjectModel;
namespace UniverseTools
{
public class DependencyGraphSpecProvider : IDisposable
{
private readonly string _packageSpecDirectory;
private readonly bool _deleteSpecDirectoryOnDispose;
private readonly string _muxerPath;
public DependencyGraphSpecProvider(string packageSpecDirectory)
: this(packageSpecDirectory, deleteSpecDirectoryOnDispose: false)
{
}
private DependencyGraphSpecProvider(string packageSpecDirectory, bool deleteSpecDirectoryOnDispose)
{
_packageSpecDirectory = packageSpecDirectory;
_deleteSpecDirectoryOnDispose = deleteSpecDirectoryOnDispose;
_muxerPath = new Muxer().MuxerPath;
}
public static DependencyGraphSpecProvider Default { get; } =
new DependencyGraphSpecProvider(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), deleteSpecDirectoryOnDispose: true);
public DependencyGraphSpec GetDependencyGraphSpec(string repositoryName, string solutionPath)
{
var outputFile = Path.Combine(_packageSpecDirectory, repositoryName, Path.GetFileName(solutionPath) + ".json");
if (!File.Exists(outputFile))
{
RunMSBuild(solutionPath, outputFile);
}
return DependencyGraphSpec.Load(outputFile);
}
private void RunMSBuild(string solutionPath, string outputFile)
{
var psi = new ProcessStartInfo(_muxerPath);
var arguments = new List<string>
{
"msbuild",
$"\"{solutionPath}\"",
"/t:GenerateRestoreGraphFile",
"/nologo",
"/v:q",
"/p:BuildProjectReferences=false",
$"/p:RestoreGraphOutputPath=\"{outputFile}\"",
};
psi.Arguments = string.Join(" ", arguments);
psi.RedirectStandardOutput = true;
var process = new Process
{
StartInfo = psi,
EnableRaisingEvents = true,
};
process.OutputDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
{
Console.WriteLine(args.Data);
}
};
using (process)
{
process.Start();
process.BeginOutputReadLine();
process.WaitForExit(60 * 5000);
if (process.ExitCode != 0)
{
throw new Exception($"{psi.FileName} {psi.Arguments} failed. Exit code {process.ExitCode}.");
}
}
}
public void Dispose()
{
if (_deleteSpecDirectoryOnDispose)
{
Directory.Delete(_packageSpecDirectory, recursive: true);
}
}
}
}