Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1516)

Unified Diff: Tools/Google.Apis.NuGet.Publisher/Google.Apis.NuGet.Publisher/NuGetApiPublisher.cs

Issue 12662047: Issue 376: Generate NuGet pacakges for generated APIs (Closed) Base URL: https://google-api-dotnet-client.googlecode.com/hg/
Patch Set: David final comments Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Tools/Google.Apis.NuGet.Publisher/Google.Apis.NuGet.Publisher/NuGetApiPublisher.cs
===================================================================
new file mode 100644
--- /dev/null
b/Tools/Google.Apis.NuGet.Publisher/Google.Apis.NuGet.Publisher/NuGetApiPublisher.cs
@@ -0,0 1,241 @@
/*
Copyright 2013 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using NuGet;
using Google.Apis.NuGet.Publisher.Discovery;
using Google.Apis.Utils;
namespace Google.Apis.NuGet.Publisher
{
/// <summary>This publisher publishes Google API packages to NuGet main repository.</summary>
public class NuGetApiPublisher
{
private static TraceSource TraceSource = new TraceSource("Google.Apis");
private readonly DiscoveryItem item;
/// <summary>Gets or sets the working directory which the source will be downloaded to.</summary>
public string BundleDirectory { get; set; }
/// <summary>Gets or sets the bundle URI. The API's bundle is going to be downloaded from this URI.</summary>
public Uri BundleUri { get; set; }
/// <summary>Gets or sets the NuGet API key.</summary>
public string NuGetApiKey { get; set; }
/// <summary>Gets or sets the template directory which contains the '.nuget' directory and the necessary
/// 'Microsoft.Bcl.Build.targets' file.</summary>
public string TemplateDirectory { get; set; }
/// <summary>The regex to extract the id version of the nuspec in the source folder.</summary>
private static readonly Regex IdPattern = new Regex(@"<id>(.*)</id>");
/// <summary>The regex to extract the version of the nuspec in the source folder.</summary>
private static readonly Regex VersionPattern = new Regex(@"<version>(.*)</version>");
/// <summary>Constructs a new logic item.</summary>
public NuGetApiPublisher(DiscoveryItem item)
{
this.item = item;
}
/// <summary>This is the main logic, which does the following:
/// <list type="number">
/// <item><description>
/// Download the API's bundle from "https://google-api-client-libraries.appspot.com/"
/// </description></item>
/// <item><description>Extract the API's sources</description></item>
/// <item><description>Build the sources</description></item>
/// <item><description>Create a NuGet package</description></item>
/// <item><description>Publish the package to NuGet main repository</description></item>
/// </list>
/// </summary>
/// <remarks>Leave the <see cref="NuGetApiKey"/> empty to avoid publishing to NuGet main repository</remarks>
/// <returns>In case there is already a NuGet package with the same name and version, we won't build, create
/// a new package or publish to the main repository</returns>
public async Task Run()
{
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t start working...", item);
string zipFile = await DownloadBundle();
string sourceFolder = ExtractSources(zipFile);
if (!string.IsNullOrEmpty(sourceFolder))
{
var buildDirectory = await Build(sourceFolder);
if (!string.IsNullOrEmpty(buildDirectory))
{
var packagePath = CreateLocalNupkgFile(buildDirectory);
if (!string.IsNullOrEmpty(NuGetApiKey))
{
NuGetUtilities.PublishToNuget(packagePath, NuGetApiKey);
}
}
Directory.Delete(buildDirectory, true);
}
}
/// <summary>Tests the main logic and does the following:
/// <list type="number">
/// <item><description>Build the source files which specified in the input directory</description></item>
/// <item><description>Create a local NuGet package</description></item>
/// </list>
/// </summary>
public async Task Test(string directory)
{
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t start working on ...", item);
var sourceFolder = directory item;
if (!string.IsNullOrEmpty(sourceFolder))
{
var buildDirectory = await Build(sourceFolder);
CreateLocalNupkgFile(buildDirectory);
Directory.Delete(buildDirectory, true);
}
}
#region Download Sources
/// <summary>Downloads the API's bundle.</summary>
/// <returns>The path to the bundle file</returns>
private async Task<string> DownloadBundle()
{
var outputFile = string.Format(Path.Combine(BundleDirectory, item ".zip"));
// Downloading the bundle
using (var client = new WebClient())
{
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Downloading \"{1}\"", item, BundleUri);
await client.DownloadFileTaskAsync(BundleUri, outputFile);
TraceSource.TraceEvent(TraceEventType.Information, "{0}\t \"{1}\" was downloaded successfully", item,
BundleUri);
return outputFile;
}
}
/// <summary>
/// Extracts the sources. This method first extracts the bundle and then checks by the source zip if a NuGet
/// package already exists for the specific API version.
/// If not, the method extracts also the source zip to the returned folder path.
/// </summary>
/// <param name="zipFile">The bundle zip file which contains the sources</param>
/// <returns>The path to the source folder. <c>null</c> if a NuGet package already exists for this bundle
/// version</returns>
private string ExtractSources(string zipFile)
{
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Extracting sources", item);
System.IO.Compression.ZipFile.ExtractToDirectory(zipFile, BundleDirectory);
var apiFolder = Path.Combine(BundleDirectory, item.Name);
// gets the zip file which contains a "src.zip" suffix
var sourceZip = Directory.GetFiles(apiFolder).FirstOrDefault(f => f.EndsWith("src.zip"));
var sourceFolder = Path.Combine(BundleDirectory, "Source");
System.IO.Compression.ZipFile.ExtractToDirectory(sourceZip, sourceFolder);
// gets the nuget id and version of the package
var nuspecFile = Directory.GetFiles(sourceFolder, "*.nuspec").Single();
var content = File.ReadAllText(nuspecFile);
var id = IdPattern.Match(content).Groups[1].Value;
var version = VersionPattern.Match(content).Groups[1].Value;
// If a NuGet package already exists for this id and version - we don't need to continue with the process
bool exists = NuGetUtilities.DoesNugetPackageExist(id, version);
if (exists)
{
TraceSource.TraceEvent(TraceEventType.Information, "{0}\t A NuGet package already exists for {1}",
item, version);
return null;
}
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Extracting sources in \"{1}\"", item,
sourceFolder);
return sourceFolder;
}
#endregion
#region Build
/// <summary>
/// Builds the source folder. First it copies all the sources into the template folder and then build the
/// project file.
/// </summary>
/// <returns>The build directory</returns>
private Task<string> Build(string sourceFolder)
{
var buildDirectory = Path.Combine(TemplateDirectory, "Build");
if (Directory.Exists(buildDirectory))
{
Directory.Delete(buildDirectory, true);
}
DirectoryUtilities.CopyDirectory(sourceFolder, buildDirectory);
var projectFile = Directory.GetFiles(buildDirectory, "*.csproj").Single();
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Building \"{1}\"", item, projectFile);
// create a MS project instance and configure it to build 'Release'
Project project = new Project(projectFile);
project.SetProperty("Configuration", "Release");
bool success = project.Build("Build", new[] { new ConsoleLogger(LoggerVerbosity.Quiet) });
if (success)
{
TraceSource.TraceEvent(TraceEventType.Information, "{0}\t \"{1}\" was built successfully!", item,
projectFile);
}
else
{
TraceSource.TraceEvent(TraceEventType.Error, "{0}\t \"{1}\" ERROR IN BUILDING THE PROJECT!", item,
projectFile);
buildDirectory = null;
}
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
tcs.SetResult(buildDirectory);
return tcs.Task;
}
#endregion
#region NuGet
/// <summary>Creates a local nupkg file.</summary>
/// <param name="buildDirectoryPath">Path to build directory which contains the dll, pdb , etc</param>
/// <returns>The path to the nupkg file</returns>
private string CreateLocalNupkgFile(string buildDirectoryPath)
{
TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Start creating .nupkg file", item);
var nuspec = Directory.GetFiles(buildDirectoryPath, "*.nuspec").Single();
return NuGetUtilities.CreateLocalNupkgFile(nuspec, buildDirectoryPath);
}
#endregion
}
}

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b