This commit is contained in:
joelhulen 2015-12-05 18:16:36 -08:00
Родитель 2b2041a3bb
Коммит 842f5dd7f8
14 изменённых файлов: 849 добавлений и 0 удалений

22
AppvNext.Throttlebird.sln Normal file
Просмотреть файл

@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppvNext.Throttlebird", "AppvNext.Throttlebird\AppvNext.Throttlebird.csproj", "{1E86B5C1-EEA2-429C-82C7-7DBD5F978A01}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E86B5C1-EEA2-429C-82C7-7DBD5F978A01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E86B5C1-EEA2-429C-82C7-7DBD5F978A01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E86B5C1-EEA2-429C-82C7-7DBD5F978A01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E86B5C1-EEA2-429C-82C7-7DBD5F978A01}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

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

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1E86B5C1-EEA2-429C-82C7-7DBD5F978A01}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AppvNext.Throttlebird</RootNamespace>
<AssemblyName>AppvNext.Throttlebird</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>Throttlebird.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Throttling\InMemoryThrottleStore.cs" />
<Compile Include="Throttling\IThrottleStore.cs" />
<Compile Include="Throttling\ThrottleEntry.cs" />
<Compile Include="Throttling\ThrottlingHandler.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Throttlebird.nuspec" />
<None Include="Throttlebird.snk" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

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

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Http;
namespace AppvNext.Throttlebird.Extensions
{
public static class HttpRequestMessageExtensions
{
private const string HttpContext = "MS_HttpContext";
private const string RemoteEndpointMessage = "System.ServiceModel.Channels.RemoteEndpointMessageProperty";
private const string OwinContext = "MS_OwinContext";
public static bool IsLocal(this HttpRequestMessage request)
{
var localFlag = request.Properties["MS_IsLocal"] as Lazy<bool>;
return localFlag != null && localFlag.Value;
}
public static string GetClientIpAddress(this HttpRequestMessage request)
{
//Web-hosting
if (request.Properties.ContainsKey(HttpContext))
{
dynamic ctx = request.Properties[HttpContext];
if (ctx != null)
{
return ctx.Request.UserHostAddress;
}
}
//Self-hosting
if (request.Properties.ContainsKey(RemoteEndpointMessage))
{
dynamic remoteEndpoint = request.Properties[RemoteEndpointMessage];
if (remoteEndpoint != null)
{
return remoteEndpoint.Address;
}
}
//Owin-hosting
if (request.Properties.ContainsKey(OwinContext))
{
dynamic ctx = request.Properties[OwinContext];
if (ctx != null)
{
return ctx.Request.RemoteIpAddress;
}
}
return null;
}
}
}

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

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("AppvNext.Throttlebird")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AppvNext.Throttlebird")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1e86b5c1-eea2-429c-82c7-7dbd5f978a01")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

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

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<owners>App vNext</owners>
<authors>Joel Hulen, App vNext</authors>
<description>
Throttlebird is a simple Http request throttler to help limit the number of client requests within a given period of time.
</description>
<language>en-US</language>
<licenseUrl>https://raw.github.com/App-vNext/Throttlebird/master/LICENSE.txt</licenseUrl>
<projectUrl>https://github.com/App-vNext/Throttlebird</projectUrl>
<tags>ASP.NET MVC HTTP Tools</tags>
<copyright>Copyright <20> 2015, App vNext</copyright>
<releaseNotes>
1.0.0
---------------------
- Initial release
</releaseNotes>
<dependencies>
</dependencies>
</metadata>
<files>
<file src="lib\**\*.*" target="lib" exclude="**\*.unsigned"/>
</files>
</package>

Двоичные данные
AppvNext.Throttlebird/Throttlebird.snk Normal file

Двоичный файл не отображается.

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

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppvNext.Throttlebird.Throttling
{
/// <summary>
/// Interface for caching request throttling data.
/// </summary>
public interface IThrottleStore
{
bool TryGetValue(string key, out ThrottleEntry entry);
void IncrementRequests(string key);
void Rollover(string key);
void Clear();
}
}

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

@ -0,0 +1,47 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace AppvNext.Throttlebird.Throttling
{
/// <summary>
/// Creates an in-memory throttle cache to keep track of how many Http
/// requests within a timespan each client is making.
/// </summary>
public class InMemoryThrottleStore : IThrottleStore
{
private readonly ConcurrentDictionary<string, ThrottleEntry> _throttleStore = new ConcurrentDictionary<string, ThrottleEntry>();
public bool TryGetValue(string key, out ThrottleEntry entry)
{
return _throttleStore.TryGetValue(key, out entry);
}
public void IncrementRequests(string key)
{
_throttleStore.AddOrUpdate(key,
k =>
{
return new ThrottleEntry() { Requests = 1 };
},
(k, e) =>
{
e.Requests++;
return e;
});
}
public void Rollover(string key)
{
ThrottleEntry dummy;
_throttleStore.TryRemove(key, out dummy);
}
public void Clear()
{
_throttleStore.Clear();
}
}
}

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

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace AppvNext.Throttlebird.Throttling
{
/// <summary>
/// Creates an entry in our throttle store.
/// </summary>
public class ThrottleEntry
{
public DateTime PeriodStart { get; set; }
public long Requests { get; set; }
public ThrottleEntry()
{
PeriodStart = DateTime.UtcNow;
Requests = 0;
}
}
}

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

@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using AppvNext.Throttlebird.Extensions;
namespace AppvNext.Throttlebird.Throttling
{
public class ThrottlingHandler
: DelegatingHandler
{
private readonly IThrottleStore _store;
private readonly Func<string, long> _maxRequestsForUserIdentifier;
private readonly TimeSpan _period;
private readonly string _message;
public ThrottlingHandler(IThrottleStore store, Func<string, long> maxRequestsForUserIdentifier, TimeSpan period)
: this(store, maxRequestsForUserIdentifier, period, "The allowed number of requests has been exceeded.")
{
}
public ThrottlingHandler(IThrottleStore store, Func<string, long> maxRequestsForUserIdentifier, TimeSpan period, string message)
{
_store = store;
_maxRequestsForUserIdentifier = maxRequestsForUserIdentifier;
_period = period;
_message = message;
}
protected virtual string GetUserIdentifier(HttpRequestMessage request)
{
return request.GetClientIpAddress();
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var identifier = GetUserIdentifier(request);
if (string.IsNullOrEmpty(identifier))
{
return CreateResponse(request, HttpStatusCode.Forbidden, "Could not identify client.");
}
var maxRequests = _maxRequestsForUserIdentifier(identifier);
ThrottleEntry entry = null;
if (_store.TryGetValue(identifier, out entry))
{
if (entry.PeriodStart + _period < DateTime.UtcNow)
{
_store.Rollover(identifier);
}
}
_store.IncrementRequests(identifier);
if (!_store.TryGetValue(identifier, out entry))
{
return CreateResponse(request, HttpStatusCode.Forbidden, "Could not identify client.");
}
Task<HttpResponseMessage> response = null;
if (entry.Requests > maxRequests)
{
response = CreateResponse(request, HttpStatusCode.ServiceUnavailable, _message);
}
else
{
response = base.SendAsync(request, cancellationToken);
}
return response.ContinueWith(task =>
{
var remaining = maxRequests - entry.Requests;
if (remaining < 0)
{
remaining = 0;
}
var httpResponse = task.Result;
httpResponse.Headers.Add("RateLimit-Limit", maxRequests.ToString());
httpResponse.Headers.Add("RateLimit-Remaining", remaining.ToString());
return httpResponse;
});
}
protected Task<HttpResponseMessage> CreateResponse(HttpRequestMessage request, HttpStatusCode statusCode, string message)
{
var tsc = new TaskCompletionSource<HttpResponseMessage>();
var response = request.CreateResponse(statusCode);
response.ReasonPhrase = message;
response.Content = new StringContent(message);
tsc.SetResult(response);
return tsc.Task;
}
}
}

26
LICENSE.txt Normal file
Просмотреть файл

@ -0,0 +1,26 @@
New BSD License
=
Copyright (c) 2015, App vNext
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the App vNext nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

6
build.bat Normal file
Просмотреть файл

@ -0,0 +1,6 @@
@ECHO OFF
PUSHD %~dp0
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& './build.ps1'"
IF %errorlevel% neq 0 PAUSE

291
build.cake Normal file
Просмотреть файл

@ -0,0 +1,291 @@
///////////////////////////////////////////////////////////////////////////////
// ARGUMENTS
///////////////////////////////////////////////////////////////////////////////
var target = Argument<string>("target", "Default");
var configuration = Argument<string>("configuration", "Release");
//////////////////////////////////////////////////////////////////////
// EXTERNAL NUGET TOOLS
//////////////////////////////////////////////////////////////////////
#Tool "xunit.runner.console"
#Tool "GitVersion.CommandLine"
#Tool "Brutal.Dev.StrongNameSigner"
#Tool "NuSpec.ReferenceGenerator"
//////////////////////////////////////////////////////////////////////
// EXTERNAL NUGET LIBRARIES
//////////////////////////////////////////////////////////////////////
#addin "System.Text.Json"
using System.Text.Json;
///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
///////////////////////////////////////////////////////////////////////////////
var projectName = "Throttlebird";
var keyName = "Throttlebird.snk";
var solutions = GetFiles("./**/*.sln");
var solutionPaths = solutions.Select(solution => solution.GetDirectory());
var srcDir = Directory("./AppvNext.Throttlebird");
var buildDir = Directory("./build");
var artifactsDir = Directory("./artifacts");
var testResultsDir = artifactsDir + Directory("test-results");
// NuGet
var nuspecFilename = projectName + ".nuspec";
var nuspecSrcFile = srcDir + File(nuspecFilename);
var nuspecDestFile = buildDir + File(nuspecFilename);
var nupkgDestDir = artifactsDir + Directory("nuget-package");
var snkFile = srcDir + File(keyName);
var projectToNugetFolderMap = new Dictionary<string, string[]>() {
{ "Net45", new [] {"net45"} }
};
// Gitversion
var gitVersionPath = ToolsExePath("GitVersion.exe");
Dictionary<string, object> gitVersionOutput;
// StrongNameSigner
var strongNameSignerPath = ToolsExePath("StrongNameSigner.Console.exe");
// NuSpec.ReferenceGenerator
var refGenPath = ToolsExePath("RefGen.exe");
///////////////////////////////////////////////////////////////////////////////
// SETUP / TEARDOWN
///////////////////////////////////////////////////////////////////////////////
Setup(() =>
{
Information("");
Information(" ████████╗██╗ ██╗██████╗ ██████╗ ████████╗████████╗██╗ ███████╗██████╗ ██╗██████╗ ██████╗ ");
Information(" ╚══██╔══╝██║ ██║██╔══██╗██╔═══██╗╚══██╔══╝╚══██╔══╝██║ ██╔════╝██╔══██╗██║██╔══██╗██╔══██╗");
Information(" ██║ ███████║██████╔╝██║ ██║ ██║ ██║ ██║ █████╗ ██████╔╝██║██████╔╝██║ ██║");
Information(" ██║ ██╔══██║██╔══██╗██║ ██║ ██║ ██║ ██║ ██╔══╝ ██╔══██╗██║██╔══██╗██║ ██║");
Information(" ██║ ██║ ██║██║ ██║╚██████╔╝ ██║ ██║ ███████╗███████╗██████╔╝██║██║ ██║██████╔╝");
Information(" ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚═════╝ ╚═╝╚═╝ ╚═╝╚═════╝ ");
Information("");
});
Teardown(() =>
{
Information("Finished running tasks.");
});
//////////////////////////////////////////////////////////////////////
// PRIVATE TASKS
//////////////////////////////////////////////////////////////////////
Task("__Clean")
.Does(() =>
{
CleanDirectories(new DirectoryPath[] {
buildDir,
artifactsDir,
testResultsDir,
nupkgDestDir
});
foreach(var path in solutionPaths)
{
Information("Cleaning {0}", path);
CleanDirectories(path + "/**/bin/" + configuration);
CleanDirectories(path + "/**/obj/" + configuration);
}
});
Task("__RestoreNugetPackages")
.Does(() =>
{
foreach(var solution in solutions)
{
Information("Restoring NuGet Packages for {0}", solution);
NuGetRestore(solution);
}
});
Task("__UpdateAssemblyVersionInformation")
.Does(() =>
{
var gitVersionSettings = new ProcessSettings()
.SetRedirectStandardOutput(true);
IEnumerable<string> outputLines;
StartProcess(gitVersionPath, gitVersionSettings, out outputLines);
var output = string.Join("\n", outputLines);
gitVersionOutput = new JsonParser().Parse<Dictionary<string, object>>(output);
Information("Updated GlobalAssemblyInfo");
Information("AssemblyVersion -> {0}", gitVersionOutput["AssemblySemVer"]);
Information("AssemblyFileVersion -> {0}", gitVersionOutput["MajorMinorPatch"]);
Information("AssemblyInformationalVersion -> {0}", gitVersionOutput["InformationalVersion"]);
});
Task("__UpdateAppVeyorBuildNumber")
.WithCriteria(() => AppVeyor.IsRunningOnAppVeyor)
.Does(() =>
{
var fullSemVer = gitVersionOutput["FullSemVer"].ToString();
AppVeyor.UpdateBuildVersion(fullSemVer);
});
Task("__BuildSolutions")
.Does(() =>
{
foreach(var solution in solutions)
{
Information("Building {0}", solution);
MSBuild(solution, settings =>
settings
.SetConfiguration(configuration)
.WithProperty("TreatWarningsAsErrors", "true")
.UseToolVersion(MSBuildToolVersion.NET46)
.SetVerbosity(Verbosity.Minimal)
.SetNodeReuse(false));
}
});
Task("__RunTests")
.Does(() =>
{
XUnit2("./src/**/bin/" + configuration + "/*.Specs.dll", new XUnit2Settings {
OutputDirectory = testResultsDir,
XmlReportV1 = true
});
});
Task("__CopyOutputToNugetFolder")
.Does(() =>
{
foreach(var project in projectToNugetFolderMap.Keys) {
var sourceDir = srcDir + Directory(projectName + "." + project) + Directory("bin") + Directory(configuration);
foreach(var targetFolder in projectToNugetFolderMap[project]) {
var destDir = buildDir + Directory("lib") + Directory(targetFolder);
Information("Copying {0} -> {1}.", sourceDir, destDir);
CopyDirectory(sourceDir, destDir);
}
}
CopyFile(nuspecSrcFile, nuspecDestFile);
});
Task("__AddDotNetReferencesToNuspecFile")
.Does(() =>
{
// see: https://github.com/onovotny/ReferenceGenerator
var pclProjectName = projectName + ".Pcl";
var pclDirectory = srcDir + Directory(pclProjectName);
var projectFile = pclDirectory + File(pclProjectName + ".csproj");
var projectDll = pclDirectory + Directory("bin") + Directory(configuration) + File(projectName + ".dll");
var refGenSettings = new ProcessSettings()
.WithArguments(args => args
.AppendQuoted(".NETPortable,Version=v4.5,Profile=Profile259")
.AppendQuoted("dotnet")
.AppendQuoted(nuspecDestFile)
.AppendQuoted(projectFile)
.AppendQuoted(projectDll));
StartProcess(refGenPath, refGenSettings);
});
Task("__CreateNugetPackage")
.Does(() =>
{
var nugetVersion = gitVersionOutput["NuGetVersion"].ToString();
var packageName = projectName;
Information("Building {0}.{1}.nupkg", packageName, nugetVersion);
var nuGetPackSettings = new NuGetPackSettings {
Id = packageName,
Title = packageName,
Version = nugetVersion,
OutputDirectory = nupkgDestDir
};
NuGetPack(nuspecDestFile, nuGetPackSettings);
});
Task("__StronglySignAssemblies")
.Does(() =>
{
//see: https://github.com/brutaldev/StrongNameSigner
var strongNameSignerSettings = new ProcessSettings()
.WithArguments(args => args
.Append("-in")
.AppendQuoted(buildDir)
.Append("-k")
.AppendQuoted(snkFile)
.Append("-l")
.AppendQuoted("Changes"));
StartProcess(strongNameSignerPath, strongNameSignerSettings);
});
Task("__CreateSignedNugetPackage")
.Does(() =>
{
var nugetVersion = gitVersionOutput["NuGetVersion"].ToString();
var packageName = projectName + "-Signed";
Information("Building {0}.{1}.nupkg", packageName, nugetVersion);
var nuGetPackSettings = new NuGetPackSettings {
Id = packageName,
Title = packageName,
Version = nugetVersion,
OutputDirectory = nupkgDestDir
};
NuGetPack(nuspecDestFile, nuGetPackSettings);
});
//////////////////////////////////////////////////////////////////////
// BUILD TASKS
//////////////////////////////////////////////////////////////////////
Task("Build")
.IsDependentOn("__Clean")
.IsDependentOn("__RestoreNugetPackages")
.IsDependentOn("__UpdateAssemblyVersionInformation")
.IsDependentOn("__UpdateAppVeyorBuildNumber")
.IsDependentOn("__BuildSolutions")
.IsDependentOn("__RunTests")
.IsDependentOn("__CopyOutputToNugetFolder")
.IsDependentOn("__AddDotNetReferencesToNuspecFile")
.IsDependentOn("__CreateNugetPackage")
.IsDependentOn("__StronglySignAssemblies")
.IsDependentOn("__CreateSignedNugetPackage");
///////////////////////////////////////////////////////////////////////////////
// PRIMARY TARGETS
///////////////////////////////////////////////////////////////////////////////
Task("Default")
.IsDependentOn("Build");
///////////////////////////////////////////////////////////////////////////////
// EXECUTION
///////////////////////////////////////////////////////////////////////////////
RunTarget(target);
//////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS
//////////////////////////////////////////////////////////////////////
string ToolsExePath(string exeFileName) {
var exePath = System.IO.Directory.GetFiles(@".\Tools", exeFileName, SearchOption.AllDirectories).FirstOrDefault();
return exePath;
}

132
build.ps1 Normal file
Просмотреть файл

@ -0,0 +1,132 @@
<#
.SYNOPSIS
This is a Powershell script to bootstrap a Cake build.
.DESCRIPTION
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
and execute your Cake build script with the parameters you provide.
.PARAMETER Script
The build script to execute.
.PARAMETER Target
The build script target to run.
.PARAMETER Configuration
The build configuration to use.
.PARAMETER Verbosity
Specifies the amount of information to be displayed.
.PARAMETER Experimental
Tells Cake to use the latest Roslyn release.
.PARAMETER WhatIf
Performs a dry run of the build script.
No tasks will be executed.
.PARAMETER Mono
Tells Cake to use the Mono scripting engine.
.LINK
http://cakebuild.net
#>
Param(
[string]$Script = "build.cake",
[string]$Target = "Default",
[string]$Configuration = "Release",
[ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
[string]$Verbosity = "Verbose",
[switch]$Experimental,
[Alias("DryRun","Noop")]
[switch]$WhatIf,
[switch]$Mono,
[switch]$SkipToolPackageRestore,
[switch]$Verbose
)
Write-Host "Preparing to run build script..."
# Should we show verbose messages?
if($Verbose.IsPresent)
{
$VerbosePreference = "continue"
}
$TOOLS_DIR = Join-Path $PSScriptRoot "tools"
$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
# Should we use mono?
$UseMono = "";
if($Mono.IsPresent) {
Write-Verbose -Message "Using the Mono based scripting engine."
$UseMono = "-mono"
}
# Should we use the new Roslyn?
$UseExperimental = "";
if($Experimental.IsPresent -and !($Mono.IsPresent)) {
Write-Verbose -Message "Using experimental version of Roslyn."
$UseExperimental = "-experimental"
}
# Is this a dry run?
$UseDryRun = "";
if($WhatIf.IsPresent) {
$UseDryRun = "-dryrun"
}
# Make sure tools folder exists
if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
New-Item -Path $TOOLS_DIR -Type directory | out-null
}
# Try download NuGet.exe if not exists
if (!(Test-Path $NUGET_EXE)) {
Write-Verbose -Message "Downloading NuGet.exe..."
Invoke-WebRequest -Uri http://nuget.org/nuget.exe -OutFile $NUGET_EXE
}
# Make sure NuGet exists where we expect it.
if (!(Test-Path $NUGET_EXE)) {
Throw "Could not find NuGet.exe"
}
# Save nuget.exe path to environment to be available to child processed
$ENV:NUGET_EXE = $NUGET_EXE
# Restore tools from NuGet?
if(-Not $SkipToolPackageRestore.IsPresent)
{
# Restore tools from NuGet.
Push-Location
Set-Location $TOOLS_DIR
Write-Verbose -Message "Restoring tools from NuGet..."
# Restore packages
if (Test-Path $PACKAGES_CONFIG)
{
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion"
Write-Verbose ($NuGetOutput | Out-String)
}
# Install just Cake if missing config
else
{
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install Cake -ExcludeVersion"
Write-Verbose ($NuGetOutput | Out-String)
}
Pop-Location
if ($LASTEXITCODE -ne 0)
{
exit $LASTEXITCODE
}
}
# Make sure that Cake has been installed.
if (!(Test-Path $CAKE_EXE)) {
Throw "Could not find Cake.exe"
}
# Start Cake
Write-Host "Running build script..."
Invoke-Expression "$CAKE_EXE `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental"
exit $LASTEXITCODE