LEFT | RIGHT |
(no file at all) | |
| 1 /* |
| 2 Copyright 2013 Google Inc |
| 3 |
| 4 Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 you may not use this file except in compliance with the License. |
| 6 You may obtain a copy of the License at |
| 7 |
| 8 http://www.apache.org/licenses/LICENSE-2.0 |
| 9 |
| 10 Unless required by applicable law or agreed to in writing, software |
| 11 distributed under the License is distributed on an "AS IS" BASIS, |
| 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 See the License for the specific language governing permissions and |
| 14 limitations under the License. |
| 15 */ |
| 16 |
| 17 using System; |
| 18 using System.Diagnostics; |
| 19 using System.IO; |
| 20 using System.Linq; |
| 21 using System.Net; |
| 22 using System.Text.RegularExpressions; |
| 23 using System.Threading.Tasks; |
| 24 |
| 25 using Microsoft.Build.Evaluation; |
| 26 using Microsoft.Build.Framework; |
| 27 using Microsoft.Build.Logging; |
| 28 using NuGet; |
| 29 |
| 30 using Google.Apis.NuGet.Publisher.Discovery; |
| 31 using Google.Apis.Utils; |
| 32 |
| 33 namespace Google.Apis.NuGet.Publisher |
| 34 { |
| 35 /// <summary>This publisher publishes Google API packages to NuGet main repo
sitory.</summary> |
| 36 public class NuGetApiPublisher |
| 37 { |
| 38 private static TraceSource TraceSource = new TraceSource("Google.Apis"); |
| 39 |
| 40 private readonly DiscoveryItem item; |
| 41 |
| 42 /// <summary>Gets or sets the working directory which the source will be
downloaded to.</summary> |
| 43 public string BundleDirectory { get; set; } |
| 44 |
| 45 /// <summary>Gets or sets the bundle URI. The API's bundle is going to b
e downloaded from this URI.</summary> |
| 46 public Uri BundleUri { get; set; } |
| 47 |
| 48 /// <summary>Gets or sets the NuGet API key.</summary> |
| 49 public string NuGetApiKey { get; set; } |
| 50 |
| 51 /// <summary>Gets or sets the template directory which contains the '.nu
get' directory and the necessary·· |
| 52 /// 'Microsoft.Bcl.Build.targets' file.</summary> |
| 53 public string TemplateDirectory { get; set; } |
| 54 |
| 55 /// <summary>The regex to extract the id version of the nuspec in the so
urce folder.</summary> |
| 56 private static readonly Regex IdPattern = new Regex(@"<id>(.*)</id>"); |
| 57 |
| 58 /// <summary>The regex to extract the version of the nuspec in the sourc
e folder.</summary> |
| 59 private static readonly Regex VersionPattern = new Regex(@"<version>(.*)
</version>"); |
| 60 |
| 61 /// <summary>Constructs a new logic item.</summary> |
| 62 public NuGetApiPublisher(DiscoveryItem item) |
| 63 { |
| 64 this.item = item; |
| 65 } |
| 66 |
| 67 /// <summary>This is the main logic, which does the following: |
| 68 /// <list type="number"> |
| 69 /// <item><description> |
| 70 /// Download the API's bundle from "https://google-api-client-libraries.
appspot.com/" |
| 71 /// </description></item> |
| 72 /// <item><description>Extract the API's sources</description></item> |
| 73 /// <item><description>Build the sources</description></item> |
| 74 /// <item><description>Create a NuGet package</description></item> |
| 75 /// <item><description>Publish the package to NuGet main repository</des
cription></item> |
| 76 /// </list> |
| 77 /// </summary> |
| 78 /// <remarks>Leave the <see cref="NuGetApiKey"/> empty to avoid publishi
ng to NuGet main repository</remarks> |
| 79 /// <returns>In case there is already a NuGet package with the same name
and version, we won't build, create |
| 80 /// a new package or publish to the main repository</returns> |
| 81 public async Task Run() |
| 82 { |
| 83 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t start working.
..", item); |
| 84 |
| 85 string zipFile = await DownloadBundle(); |
| 86 string sourceFolder = ExtractSources(zipFile); |
| 87 if (!string.IsNullOrEmpty(sourceFolder)) |
| 88 { |
| 89 var buildDirectory = await Build(sourceFolder); |
| 90 if (!string.IsNullOrEmpty(buildDirectory)) |
| 91 { |
| 92 var packagePath = CreateLocalNupkgFile(buildDirectory); |
| 93 if (!string.IsNullOrEmpty(NuGetApiKey)) |
| 94 { |
| 95 NuGetUtilities.PublishToNuget(packagePath, NuGetApiKey); |
| 96 } |
| 97 } |
| 98 Directory.Delete(buildDirectory, true); |
| 99 } |
| 100 } |
| 101 |
| 102 /// <summary>Tests the main logic and does the following: |
| 103 /// <list type="number"> |
| 104 /// <item><description>Build the source files which specified in the inp
ut directory</description></item> |
| 105 /// <item><description>Create a local NuGet package</description></item> |
| 106 /// </list> |
| 107 /// </summary> |
| 108 public async Task Test(string directory) |
| 109 { |
| 110 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t start working
on ...", item); |
| 111 |
| 112 var sourceFolder = directory + item; |
| 113 if (!string.IsNullOrEmpty(sourceFolder)) |
| 114 { |
| 115 var buildDirectory = await Build(sourceFolder); |
| 116 CreateLocalNupkgFile(buildDirectory); |
| 117 Directory.Delete(buildDirectory, true); |
| 118 } |
| 119 } |
| 120 |
| 121 #region Download Sources |
| 122 |
| 123 /// <summary>Downloads the API's bundle.</summary> |
| 124 /// <returns>The path to the bundle file</returns> |
| 125 private async Task<string> DownloadBundle() |
| 126 { |
| 127 var outputFile = string.Format(Path.Combine(BundleDirectory, item +
".zip")); |
| 128 |
| 129 // Downloading the bundle |
| 130 using (var client = new WebClient()) |
| 131 { |
| 132 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Downloadin
g \"{1}\"", item, BundleUri); |
| 133 await client.DownloadFileTaskAsync(BundleUri, outputFile); |
| 134 TraceSource.TraceEvent(TraceEventType.Information, "{0}\t \"{1}\
" was downloaded successfully", item, |
| 135 BundleUri); |
| 136 |
| 137 return outputFile; |
| 138 } |
| 139 } |
| 140 |
| 141 /// <summary> |
| 142 /// Extracts the sources. This method first extracts the bundle and then
checks by the source zip if a NuGet· |
| 143 /// package already exists for the specific API version.· |
| 144 /// If not, the method extracts also the source zip to the returned fold
er path. |
| 145 /// </summary> |
| 146 /// <param name="zipFile">The bundle zip file which contains the sources
</param> |
| 147 /// <returns>The path to the source folder. <c>null</c> if a NuGet packa
ge already exists for this bundle· |
| 148 /// version</returns> |
| 149 private string ExtractSources(string zipFile) |
| 150 { |
| 151 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Extracting sou
rces", item); |
| 152 |
| 153 System.IO.Compression.ZipFile.ExtractToDirectory(zipFile, BundleDire
ctory); |
| 154 var apiFolder = Path.Combine(BundleDirectory, item.Name); |
| 155 |
| 156 // gets the zip file which contains a "src.zip" suffix |
| 157 var sourceZip = Directory.GetFiles(apiFolder).FirstOrDefault(f => f.
EndsWith("src.zip")); |
| 158 var sourceFolder = Path.Combine(BundleDirectory, "Source"); |
| 159 System.IO.Compression.ZipFile.ExtractToDirectory(sourceZip, sourceFo
lder); |
| 160 |
| 161 // gets the nuget id and version of the package |
| 162 var nuspecFile = Directory.GetFiles(sourceFolder, "*.nuspec").Single
(); |
| 163 var content = File.ReadAllText(nuspecFile); |
| 164 var id = IdPattern.Match(content).Groups[1].Value; |
| 165 var version = VersionPattern.Match(content).Groups[1].Value; |
| 166 |
| 167 // If a NuGet package already exists for this id and version - we do
n't need to continue with the process |
| 168 bool exists = NuGetUtilities.DoesNugetPackageExist(id, version); |
| 169 if (exists) |
| 170 { |
| 171 TraceSource.TraceEvent(TraceEventType.Information, "{0}\t A NuGe
t package already exists for {1}", |
| 172 item, version); |
| 173 return null; |
| 174 } |
| 175 |
| 176 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Extracting sou
rces in \"{1}\"", item, |
| 177 sourceFolder); |
| 178 |
| 179 return sourceFolder; |
| 180 } |
| 181 |
| 182 #endregion |
| 183 |
| 184 #region Build |
| 185 |
| 186 /// <summary> |
| 187 /// Builds the source folder. First it copies all the sources into the t
emplate folder and then build the· |
| 188 /// project file. |
| 189 /// </summary> |
| 190 /// <returns>The build directory</returns> |
| 191 private Task<string> Build(string sourceFolder) |
| 192 { |
| 193 var buildDirectory = Path.Combine(TemplateDirectory, "Build"); |
| 194 if (Directory.Exists(buildDirectory)) |
| 195 { |
| 196 Directory.Delete(buildDirectory, true); |
| 197 } |
| 198 DirectoryUtilities.CopyDirectory(sourceFolder, buildDirectory); |
| 199 |
| 200 var projectFile = Directory.GetFiles(buildDirectory, "*.csproj").Sin
gle(); |
| 201 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Building \"{1}
\"", item, projectFile); |
| 202 |
| 203 // create a MS project instance and configure it to build 'Release' |
| 204 Project project = new Project(projectFile); |
| 205 project.SetProperty("Configuration", "Release"); |
| 206 |
| 207 bool success = project.Build("Build", new[] { new ConsoleLogger(Logg
erVerbosity.Quiet) }); |
| 208 if (success) |
| 209 { |
| 210 TraceSource.TraceEvent(TraceEventType.Information, "{0}\t \"{1}\
" was built successfully!", item, |
| 211 projectFile); |
| 212 } |
| 213 else |
| 214 { |
| 215 TraceSource.TraceEvent(TraceEventType.Error, "{0}\t \"{1}\" ERRO
R IN BUILDING THE PROJECT!", item, |
| 216 projectFile); |
| 217 buildDirectory = null; |
| 218 } |
| 219 |
| 220 TaskCompletionSource<string> tcs = new TaskCompletionSource<string>(
); |
| 221 tcs.SetResult(buildDirectory); |
| 222 return tcs.Task; |
| 223 } |
| 224 |
| 225 #endregion |
| 226 |
| 227 #region NuGet |
| 228 |
| 229 /// <summary>Creates a local nupkg file.</summary> |
| 230 /// <param name="buildDirectoryPath">Path to build directory which conta
ins the dll, pdb , etc</param> |
| 231 /// <returns>The path to the nupkg file</returns> |
| 232 private string CreateLocalNupkgFile(string buildDirectoryPath) |
| 233 { |
| 234 TraceSource.TraceEvent(TraceEventType.Verbose, "{0}\t Start creating
.nupkg file", item); |
| 235 var nuspec = Directory.GetFiles(buildDirectoryPath, "*.nuspec").Sing
le(); |
| 236 return NuGetUtilities.CreateLocalNupkgFile(nuspec, buildDirectoryPat
h); |
| 237 } |
| 238 |
| 239 #endregion |
| 240 } |
| 241 } |
LEFT | RIGHT |