From 042d9e56c9db6b7abdd23b8cd01fc8f888147b0d Mon Sep 17 00:00:00 2001 From: Christian Fiebrig Date: Sat, 28 Mar 2015 19:37:36 +0100 Subject: [PATCH 1/4] make alternative download via nuget possible with just using nuget api call --- .../Paket.Bootstrapper.csproj | 3 +- src/Paket.Bootstrapper/Program.cs | 28 ++++++++----------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj b/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj index e8bd95ab61..f737c386ce 100644 --- a/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj +++ b/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj @@ -9,7 +9,7 @@ Properties Paket.Bootstrapper paket.bootstrapper - v4.0 + v4.5 512 @@ -35,6 +35,7 @@ + diff --git a/src/Paket.Bootstrapper/Program.cs b/src/Paket.Bootstrapper/Program.cs index fffcd09d26..25c75e7342 100644 --- a/src/Paket.Bootstrapper/Program.cs +++ b/src/Paket.Bootstrapper/Program.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.IO.Compression; using System.Net; using System.Reflection; @@ -139,25 +140,20 @@ private static void NugetAlternativeDownload(string folder, string target) { using (WebClient client = new WebClient()) { - var nugetExeUrl = "https://nuget.org/nuget.exe"; - - PrepareWebClient(client, nugetExeUrl); + var getLatestFromNugetUrl = "https://www.nuget.org/api/v2/package/Paket"; + var paketDownloadUrl = getLatestFromNugetUrl; + var paketNupkgFile = "paket.latest.nupkg"; + + PrepareWebClient(client, paketDownloadUrl); var randomFullPath = Path.Combine(folder, Path.GetRandomFileName()); Directory.CreateDirectory(randomFullPath); - var nugetExePath = Path.Combine(randomFullPath, "nuget.exe"); - client.DownloadFile(nugetExeUrl, nugetExePath); - - var psi = new ProcessStartInfo(nugetExePath, String.Format("install Paket -ExcludeVersion -SolutionDirectory \"{0}\"", randomFullPath)); - psi.CreateNoWindow = true; - psi.WindowStyle = ProcessWindowStyle.Hidden; - var process = Process.Start(psi); - process.WaitForExit(); - if (process.ExitCode == 0) - { - var paketSourceFile = Path.Combine(randomFullPath, "packages", "Paket", "Tools", "Paket.exe"); - File.Copy(paketSourceFile, target); - } + var paketPackageFile = Path.Combine(randomFullPath, paketNupkgFile); + client.DownloadFile(paketDownloadUrl, paketPackageFile); + + ZipFile.ExtractToDirectory(paketPackageFile, randomFullPath); + var paketSourceFile = Path.Combine(randomFullPath, "Tools", "Paket.exe"); + File.Copy(paketSourceFile, target); Directory.Delete(randomFullPath, true); } } From c38993dc40afa9f0f1baa125c781bb80805f50dd Mon Sep 17 00:00:00 2001 From: Christian Fiebrig Date: Sat, 28 Mar 2015 20:04:34 +0100 Subject: [PATCH 2/4] evaluated arguments are now used for nuget fallback download --- src/Paket.Bootstrapper/Program.cs | 43 +++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/Paket.Bootstrapper/Program.cs b/src/Paket.Bootstrapper/Program.cs index 25c75e7342..b2ee1c492c 100644 --- a/src/Paket.Bootstrapper/Program.cs +++ b/src/Paket.Bootstrapper/Program.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.IO.Compression; +using System.Linq; using System.Net; using System.Reflection; @@ -28,11 +29,11 @@ static void Main(string[] args) { var folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var target = Path.Combine(folder, "paket.exe"); - + var latestVersion = ""; + var ignorePrerelease = true; + try - { var latestVersion = ""; - var ignorePrerelease = true; - + { if (args.Length >= 1) { if (args[0] == "prerelease") @@ -123,7 +124,7 @@ static void Main(string[] args) if (!File.Exists(target)) { Console.WriteLine("Github download failed. Try downloading Paket directly from 'nuget.org'."); - NugetAlternativeDownload(folder, target); + NugetAlternativeDownload(folder, target, latestVersion, ignorePrerelease); } } catch (Exception exn) @@ -134,21 +135,41 @@ static void Main(string[] args) } } - private static void NugetAlternativeDownload(string folder, string target) + private static void NugetAlternativeDownload(string folder, string target, string latestVersion, bool ignorePrereleases) { try { using (WebClient client = new WebClient()) { - var getLatestFromNugetUrl = "https://www.nuget.org/api/v2/package/Paket"; + const string getLatestFromNugetUrl = "https://www.nuget.org/api/v2/package/Paket"; + const string getVersionsFromNugetUrl = "https://www.nuget.org/api/v2/package-versions/Paket?includePrereleases=true"; + const string getSpecificFromNugetUrlTemplate = "https://www.nuget.org/api/v2/package/Paket/{0}"; + const string paketNupkgFile = "paket.latest.nupkg"; + const string paketNupkgFileTemplate = "paket.{0}.nupkg"; + var paketDownloadUrl = getLatestFromNugetUrl; - var paketNupkgFile = "paket.latest.nupkg"; - - PrepareWebClient(client, paketDownloadUrl); + var paketFile = paketNupkgFile; + if (latestVersion == "" && !ignorePrereleases) + { + PrepareWebClient(client, getVersionsFromNugetUrl); + var versions = client.DownloadString(getVersionsFromNugetUrl); + latestVersion = versions. + Trim('[', ']'). + Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries). + Select(x => x.Trim('"')). + LastOrDefault(x => !String.IsNullOrWhiteSpace(x)) ?? String.Empty; + } + if (latestVersion != "") + { + paketDownloadUrl = String.Format(getSpecificFromNugetUrlTemplate, latestVersion); + paketFile = String.Format(paketNupkgFileTemplate, latestVersion); + } var randomFullPath = Path.Combine(folder, Path.GetRandomFileName()); Directory.CreateDirectory(randomFullPath); - var paketPackageFile = Path.Combine(randomFullPath, paketNupkgFile); + var paketPackageFile = Path.Combine(randomFullPath, paketFile); + Console.WriteLine("Starting download from {0}", paketDownloadUrl); + PrepareWebClient(client, paketDownloadUrl); client.DownloadFile(paketDownloadUrl, paketPackageFile); ZipFile.ExtractToDirectory(paketPackageFile, randomFullPath); From c6dfa2d3c99645593cd4b80333ecc2a62d5f7c18 Mon Sep 17 00:00:00 2001 From: Christian Fiebrig Date: Sun, 29 Mar 2015 11:42:29 +0200 Subject: [PATCH 3/4] new bootstrapper parameter --prefer-nuget to prefer nuget over github - refactored download pattern with strategies - command parameter evaluation separated --- docs/content/bootstrapper.md | 4 +- src/Paket.Bootstrapper/DownloadArguments.cs | 18 ++ .../GitHubDownloadStrategy.cs | 73 ++++++ src/Paket.Bootstrapper/IDownloadStrategy.cs | 15 ++ .../NugetDownloadStrategy.cs | 86 +++++++ .../Paket.Bootstrapper.csproj | 4 + src/Paket.Bootstrapper/Program.cs | 229 ++++++++---------- 7 files changed, 300 insertions(+), 129 deletions(-) create mode 100644 src/Paket.Bootstrapper/DownloadArguments.cs create mode 100644 src/Paket.Bootstrapper/GitHubDownloadStrategy.cs create mode 100644 src/Paket.Bootstrapper/IDownloadStrategy.cs create mode 100644 src/Paket.Bootstrapper/NugetDownloadStrategy.cs diff --git a/docs/content/bootstrapper.md b/docs/content/bootstrapper.md index 860d671403..b204c436e0 100644 --- a/docs/content/bootstrapper.md +++ b/docs/content/bootstrapper.md @@ -3,10 +3,12 @@ Downloads the latest stable paket.exe from github.com. [lang=batchfile] - $ paket.bootstrapper.exe [prerelease|version] + $ paket.bootstrapper.exe [prerelease|version] [--prefer-nuget] Options: `prerelease`: Downloads the latest paket.exe from github.com and includes prerelease versions. `version`: Downloads the given version of paket.exe from github.com. + + `--prefer-nuget`: Downloads the given version of paket.exe from nuget.org instead of github.com. diff --git a/src/Paket.Bootstrapper/DownloadArguments.cs b/src/Paket.Bootstrapper/DownloadArguments.cs new file mode 100644 index 0000000000..8bea2d6c55 --- /dev/null +++ b/src/Paket.Bootstrapper/DownloadArguments.cs @@ -0,0 +1,18 @@ +namespace Paket.Bootstrapper +{ + internal class DownloadArguments + { + public string Folder { get; private set; } + public string Target { get; private set; } + public string LatestVersion { get; private set; } + public bool IgnorePrerelease { get; private set; } + + public DownloadArguments(string latestVersion, bool ignorePrerelease, string folder, string target) + { + LatestVersion = latestVersion; + IgnorePrerelease = ignorePrerelease; + Folder = folder; + Target = target; + } + } +} \ No newline at end of file diff --git a/src/Paket.Bootstrapper/GitHubDownloadStrategy.cs b/src/Paket.Bootstrapper/GitHubDownloadStrategy.cs new file mode 100644 index 0000000000..95a656d141 --- /dev/null +++ b/src/Paket.Bootstrapper/GitHubDownloadStrategy.cs @@ -0,0 +1,73 @@ +using System; +using System.IO; +using System.Net; + +namespace Paket.Bootstrapper +{ + internal class GitHubDownloadStrategy : IDownloadStrategy + { + private PrepareWebClientDelegate PrepareWebClient { get; set; } + private GetDefaultWebProxyForDelegate GetDefaultWebProxyFor { get; set; } + public string Name { get { return "Github"; } } + public IDownloadStrategy FallbackStrategy { get; set; } + + public GitHubDownloadStrategy(PrepareWebClientDelegate prepareWebClient, GetDefaultWebProxyForDelegate getDefaultWebProxyFor) + { + PrepareWebClient = prepareWebClient; + GetDefaultWebProxyFor = getDefaultWebProxyFor; + } + + public string GetLatestVersion(bool ignorePrerelease) + { + string latestVersion = ""; + using (WebClient client = new WebClient()) + { + const string releasesUrl = "https://github.com/fsprojects/Paket/releases"; + PrepareWebClient(client, releasesUrl); + + var data = client.DownloadString(releasesUrl); + var start = 0; + while (latestVersion == "") + { + start = data.IndexOf("Paket/tree/", start) + 11; + var end = data.IndexOf("\"", start); + latestVersion = data.Substring(start, end - start); + if (latestVersion.Contains("-") && ignorePrerelease) + latestVersion = ""; + } + } + return latestVersion; + } + + public void DownloadVersion(string latestVersion, string target) + { + var url = String.Format("https://github.com/fsprojects/Paket/releases/download/{0}/paket.exe", latestVersion); + + Console.WriteLine("Starting download from {0}", url); + + var request = (HttpWebRequest)HttpWebRequest.Create(url); + + request.UseDefaultCredentials = true; + request.Proxy = GetDefaultWebProxyFor(url); + request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + + using (HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse()) + { + using (Stream httpResponseStream = httpResponse.GetResponseStream()) + { + const int bufferSize = 4096; + byte[] buffer = new byte[bufferSize]; + int bytesRead = 0; + + using (FileStream fileStream = File.Create(target)) + { + while ((bytesRead = httpResponseStream.Read(buffer, 0, bufferSize)) != 0) + { + fileStream.Write(buffer, 0, bytesRead); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/Paket.Bootstrapper/IDownloadStrategy.cs b/src/Paket.Bootstrapper/IDownloadStrategy.cs new file mode 100644 index 0000000000..dae2003dad --- /dev/null +++ b/src/Paket.Bootstrapper/IDownloadStrategy.cs @@ -0,0 +1,15 @@ +using System.Net; + +namespace Paket.Bootstrapper +{ + internal interface IDownloadStrategy + { + string Name { get; } + IDownloadStrategy FallbackStrategy { get; set; } + string GetLatestVersion(bool ignorePrerelease); + void DownloadVersion(string latestVersion, string target); + } + + public delegate void PrepareWebClientDelegate(WebClient client, string url); + public delegate IWebProxy GetDefaultWebProxyForDelegate(string url); +} \ No newline at end of file diff --git a/src/Paket.Bootstrapper/NugetDownloadStrategy.cs b/src/Paket.Bootstrapper/NugetDownloadStrategy.cs new file mode 100644 index 0000000000..6bd7eb0040 --- /dev/null +++ b/src/Paket.Bootstrapper/NugetDownloadStrategy.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; + +namespace Paket.Bootstrapper +{ + internal class NugetDownloadStrategy : IDownloadStrategy + { + private PrepareWebClientDelegate PrepareWebClient { get; set; } + private GetDefaultWebProxyForDelegate GetDefaultWebProxyFor { get; set; } + private string Folder { get; set; } + + public NugetDownloadStrategy(PrepareWebClientDelegate prepareWebClient, GetDefaultWebProxyForDelegate getDefaultWebProxyFor, string folder) + { + PrepareWebClient = prepareWebClient; + GetDefaultWebProxyFor = getDefaultWebProxyFor; + Folder = folder; + } + + public string Name + { + get { return "Nuget"; } + } + + public IDownloadStrategy FallbackStrategy + { + get; + set; + } + + public string GetLatestVersion(bool ignorePrerelease) + { + using (WebClient client = new WebClient()) + { + const string getVersionsFromNugetUrl = "https://www.nuget.org/api/v2/package-versions/Paket"; + const string withPrereleases = "?includePrereleases=true"; + + var versionRequestUrl = getVersionsFromNugetUrl; + if (!ignorePrerelease) + versionRequestUrl += withPrereleases; + PrepareWebClient(client, versionRequestUrl); + var versions = client.DownloadString(versionRequestUrl); + var latestVersion = versions. + Trim('[', ']'). + Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries). + Select(x => x.Trim('"')). + LastOrDefault(x => !String.IsNullOrWhiteSpace(x)) ?? String.Empty; + return latestVersion; + } + } + + public void DownloadVersion(string latestVersion, string target) + { + using (WebClient client = new WebClient()) + { + const string getLatestFromNugetUrl = "https://www.nuget.org/api/v2/package/Paket"; + const string getSpecificFromNugetUrlTemplate = "https://www.nuget.org/api/v2/package/Paket/{0}"; + const string paketNupkgFile = "paket.latest.nupkg"; + const string paketNupkgFileTemplate = "paket.{0}.nupkg"; + + var paketDownloadUrl = getLatestFromNugetUrl; + var paketFile = paketNupkgFile; + if (latestVersion != "") + { + paketDownloadUrl = String.Format(getSpecificFromNugetUrlTemplate, latestVersion); + paketFile = String.Format(paketNupkgFileTemplate, latestVersion); + } + + var randomFullPath = Path.Combine(Folder, Path.GetRandomFileName()); + Directory.CreateDirectory(randomFullPath); + var paketPackageFile = Path.Combine(randomFullPath, paketFile); + Console.WriteLine("Starting download from {0}", paketDownloadUrl); + PrepareWebClient(client, paketDownloadUrl); + client.DownloadFile(paketDownloadUrl, paketPackageFile); + + ZipFile.ExtractToDirectory(paketPackageFile, randomFullPath); + var paketSourceFile = Path.Combine(randomFullPath, "Tools", "Paket.exe"); + File.Copy(paketSourceFile, target, true); + Directory.Delete(randomFullPath, true); + } + } + + } +} \ No newline at end of file diff --git a/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj b/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj index f737c386ce..ab5d946832 100644 --- a/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj +++ b/src/Paket.Bootstrapper/Paket.Bootstrapper.csproj @@ -39,6 +39,10 @@ + + + + diff --git a/src/Paket.Bootstrapper/Program.cs b/src/Paket.Bootstrapper/Program.cs index b2ee1c492c..564dae8750 100644 --- a/src/Paket.Bootstrapper/Program.cs +++ b/src/Paket.Bootstrapper/Program.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics; using System.IO; -using System.IO.Compression; using System.Linq; using System.Net; using System.Reflection; @@ -10,6 +9,9 @@ namespace Paket.Bootstrapper { class Program { + const string PreferNugetCommandArg = "--prefer-nuget"; + const string PrereleaseCommandArg = "prerelease"; + static IWebProxy GetDefaultWebProxyFor(String url) { IWebProxy result = WebRequest.GetSystemWebProxy(); @@ -19,7 +21,8 @@ static IWebProxy GetDefaultWebProxyFor(String url) if (address == uri) return null; - return new WebProxy(address) { + return new WebProxy(address) + { Credentials = CredentialCache.DefaultCredentials, BypassProxyOnLocal = true }; @@ -27,163 +30,132 @@ static IWebProxy GetDefaultWebProxyFor(String url) static void Main(string[] args) { - var folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - var target = Path.Combine(folder, "paket.exe"); - var latestVersion = ""; - var ignorePrerelease = true; - - try + var commandArgs = args; + bool preferNuget = false; + if (commandArgs.Contains(PreferNugetCommandArg)) { - if (args.Length >= 1) - { - if (args[0] == "prerelease") - { - ignorePrerelease = false; - Console.WriteLine("Prerelease requested. Looking for latest prerelease."); - } - else - { - latestVersion = args[0]; - Console.WriteLine("Version {0} requested.", latestVersion); - } - } - else Console.WriteLine("No version specified. Downloading latest stable."); - var localVersion = ""; + preferNuget = true; + commandArgs = args.Where(x => x != PreferNugetCommandArg).ToArray(); + } + var dlArgs = EvaluateCommandArgs(commandArgs); - if (File.Exists(target)) - { - try - { - FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(target); - if (fvi.FileVersion != null) - localVersion = fvi.FileVersion; - } - catch (Exception) - { - } - } + var effectiveStrategy = GetEffectiveDownloadStrategy(dlArgs, preferNuget); + + StartPaketBootstrapping(effectiveStrategy, dlArgs); + } + + private static void StartPaketBootstrapping(IDownloadStrategy downloadStrategy, DownloadArguments dlArgs) + { + Action handleException = exception => + { + if (!File.Exists(dlArgs.Target)) + Environment.ExitCode = 1; + WriteConsoleError(String.Format("{0} ({1})", exception.Message, downloadStrategy.Name)); + }; + try + { + var localVersion = GetLocalFileVersion(dlArgs.Target); + var latestVersion = dlArgs.LatestVersion; if (latestVersion == "") { - using (WebClient client = new WebClient()) - { - var releasesUrl = "https://github.com/fsprojects/Paket/releases"; - - PrepareWebClient(client, releasesUrl); - - var data = client.DownloadString(releasesUrl); - var start = 0; - while (latestVersion == "") - { - start = data.IndexOf("Paket/tree/", start) + 11; - var end = data.IndexOf("\"", start); - latestVersion = data.Substring(start, end - start); - if (latestVersion.Contains("-") && ignorePrerelease) - latestVersion = ""; - } - } + latestVersion = downloadStrategy.GetLatestVersion(dlArgs.IgnorePrerelease); } if (!localVersion.StartsWith(latestVersion)) { - var url = String.Format("https://github.com/fsprojects/Paket/releases/download/{0}/paket.exe", latestVersion); - - Console.WriteLine("Starting download from {0}", url); - - var request = (HttpWebRequest)HttpWebRequest.Create(url); - - request.UseDefaultCredentials = true; - request.Proxy = GetDefaultWebProxyFor(url); - - request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; - using (HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse()) - { - using (Stream httpResponseStream = httpResponse.GetResponseStream()) - { - const int bufferSize = 4096; - byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - - using (FileStream fileStream = File.Create(target)) - { - while ((bytesRead = httpResponseStream.Read(buffer, 0, bufferSize)) != 0) - { - fileStream.Write(buffer, 0, bytesRead); - } - } - } - } + downloadStrategy.DownloadVersion(latestVersion, dlArgs.Target); } else { Console.WriteLine("Paket.exe {0} is up to date.", localVersion); } } - catch (WebException) + catch (WebException exn) { - if (!File.Exists(target)) + var shouldHandleException = true; + if (!File.Exists(dlArgs.Target)) { - Console.WriteLine("Github download failed. Try downloading Paket directly from 'nuget.org'."); - NugetAlternativeDownload(folder, target, latestVersion, ignorePrerelease); + if (downloadStrategy.FallbackStrategy != null) + { + var fallbackStrategy = downloadStrategy.FallbackStrategy; + Console.WriteLine("'{0}' download failed. Try fallback download from '{1}'.", downloadStrategy.Name, fallbackStrategy.Name); + StartPaketBootstrapping(fallbackStrategy, dlArgs); + shouldHandleException = !File.Exists(dlArgs.Target); + } } + if (shouldHandleException) + handleException(exn); } catch (Exception exn) { - if (!File.Exists(target)) - Environment.ExitCode = 1; - WriteConsoleError(exn.Message); + handleException(exn); } } - private static void NugetAlternativeDownload(string folder, string target, string latestVersion, bool ignorePrereleases) + private static IDownloadStrategy GetEffectiveDownloadStrategy(DownloadArguments dlArgs, bool preferNuget) { - try + var gitHubDownloadStrategy = new GitHubDownloadStrategy(PrepareWebClient, GetDefaultWebProxyFor); + var nugetDownloadStrategy = new NugetDownloadStrategy(PrepareWebClient, GetDefaultWebProxyFor, dlArgs.Folder); + + IDownloadStrategy effectiveStrategy; + if (preferNuget) { - using (WebClient client = new WebClient()) - { - const string getLatestFromNugetUrl = "https://www.nuget.org/api/v2/package/Paket"; - const string getVersionsFromNugetUrl = "https://www.nuget.org/api/v2/package-versions/Paket?includePrereleases=true"; - const string getSpecificFromNugetUrlTemplate = "https://www.nuget.org/api/v2/package/Paket/{0}"; - const string paketNupkgFile = "paket.latest.nupkg"; - const string paketNupkgFileTemplate = "paket.{0}.nupkg"; - - var paketDownloadUrl = getLatestFromNugetUrl; - var paketFile = paketNupkgFile; - if (latestVersion == "" && !ignorePrereleases) - { - PrepareWebClient(client, getVersionsFromNugetUrl); - var versions = client.DownloadString(getVersionsFromNugetUrl); - latestVersion = versions. - Trim('[', ']'). - Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries). - Select(x => x.Trim('"')). - LastOrDefault(x => !String.IsNullOrWhiteSpace(x)) ?? String.Empty; - } - if (latestVersion != "") - { - paketDownloadUrl = String.Format(getSpecificFromNugetUrlTemplate, latestVersion); - paketFile = String.Format(paketNupkgFileTemplate, latestVersion); - } + effectiveStrategy = nugetDownloadStrategy; + nugetDownloadStrategy.FallbackStrategy = gitHubDownloadStrategy; + } + else + { + effectiveStrategy = gitHubDownloadStrategy; + gitHubDownloadStrategy.FallbackStrategy = nugetDownloadStrategy; + } + return effectiveStrategy; + } + + private static string GetLocalFileVersion(string target) + { + var localVersion = ""; - var randomFullPath = Path.Combine(folder, Path.GetRandomFileName()); - Directory.CreateDirectory(randomFullPath); - var paketPackageFile = Path.Combine(randomFullPath, paketFile); - Console.WriteLine("Starting download from {0}", paketDownloadUrl); - PrepareWebClient(client, paketDownloadUrl); - client.DownloadFile(paketDownloadUrl, paketPackageFile); - - ZipFile.ExtractToDirectory(paketPackageFile, randomFullPath); - var paketSourceFile = Path.Combine(randomFullPath, "Tools", "Paket.exe"); - File.Copy(paketSourceFile, target); - Directory.Delete(randomFullPath, true); + if (File.Exists(target)) + { + try + { + FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(target); + if (fvi.FileVersion != null) + localVersion = fvi.FileVersion; + } + catch (Exception) + { } } - catch (Exception exn) + return localVersion; + } + + private static DownloadArguments EvaluateCommandArgs(string[] args) + { + var folder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var target = Path.Combine(folder, "paket.exe"); + + var latestVersion = ""; + var ignorePrerelease = true; + + if (args.Length >= 1) { - if (!File.Exists(target)) - Environment.ExitCode = 1; - WriteConsoleError(exn.Message); + if (args[0] == PrereleaseCommandArg) + { + ignorePrerelease = false; + Console.WriteLine("Prerelease requested. Looking for latest prerelease."); + } + else + { + latestVersion = args[0]; + Console.WriteLine("Version {0} requested.", latestVersion); + } } + else Console.WriteLine("No version specified. Downloading latest stable."); + + + return new DownloadArguments(latestVersion, ignorePrerelease, folder, target); } private static void PrepareWebClient(WebClient client, string url) @@ -201,4 +173,5 @@ private static void WriteConsoleError(string message) Console.ForegroundColor = oldColor; } } + } \ No newline at end of file From e642f01b33338250777330a6b056a9048fa643e0 Mon Sep 17 00:00:00 2001 From: Christian Fiebrig Date: Sun, 29 Mar 2015 14:29:14 +0200 Subject: [PATCH 4/4] fixing prerelease detection from nuget parsing nuget versions with SemVer SemVer impl transformed from fs in paket.core --- .../NugetDownloadStrategy.cs | 125 ++++++++++++++++-- 1 file changed, 117 insertions(+), 8 deletions(-) diff --git a/src/Paket.Bootstrapper/NugetDownloadStrategy.cs b/src/Paket.Bootstrapper/NugetDownloadStrategy.cs index 6bd7eb0040..68aa7a2dc4 100644 --- a/src/Paket.Bootstrapper/NugetDownloadStrategy.cs +++ b/src/Paket.Bootstrapper/NugetDownloadStrategy.cs @@ -3,6 +3,7 @@ using System.IO.Compression; using System.Linq; using System.Net; +using System.Text.RegularExpressions; namespace Paket.Bootstrapper { @@ -24,18 +25,14 @@ public string Name get { return "Nuget"; } } - public IDownloadStrategy FallbackStrategy - { - get; - set; - } + public IDownloadStrategy FallbackStrategy { get; set; } public string GetLatestVersion(bool ignorePrerelease) { using (WebClient client = new WebClient()) { const string getVersionsFromNugetUrl = "https://www.nuget.org/api/v2/package-versions/Paket"; - const string withPrereleases = "?includePrereleases=true"; + const string withPrereleases = "?includePrerelease=true"; var versionRequestUrl = getVersionsFromNugetUrl; if (!ignorePrerelease) @@ -46,11 +43,33 @@ public string GetLatestVersion(bool ignorePrerelease) Trim('[', ']'). Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries). Select(x => x.Trim('"')). - LastOrDefault(x => !String.IsNullOrWhiteSpace(x)) ?? String.Empty; - return latestVersion; + Select(x => GetSemVer(x)). + OrderBy(x => x). + LastOrDefault(x => !String.IsNullOrWhiteSpace(x.Original)); + return latestVersion != null ? latestVersion.Original : String.Empty; } } + private SemVer GetSemVer(string version) + { + var dashSplitted = version.Split('-', '+'); + var splitted = dashSplitted[0].Split('.'); + var l = splitted.Length; + + var prereleaseBuild = dashSplitted.Length > 1 && dashSplitted[1].Split('.').Length > 1 ? dashSplitted[1].Split('.')[1] : "0"; + + return new SemVer + { + Major = l > 0 ? Int32.Parse(splitted[0]) : 0, + Minor = l > 1 ? Int32.Parse(splitted[1]) : 0, + Patch = l > 2 ? Int32.Parse(splitted[2]) : 0, + PreRelease = PreRelease.TryParse(dashSplitted.Length > 1 ? dashSplitted[1].Split('.')[0] : String.Empty), + Build = l > 3 ? splitted[3] : "0", + PreReleaseBuild = prereleaseBuild, + Original = version + }; + } + public void DownloadVersion(string latestVersion, string target) { using (WebClient client = new WebClient()) @@ -82,5 +101,95 @@ public void DownloadVersion(string latestVersion, string target) } } + private class SemVer : IComparable + { + public int Major { get; set; } + public int Minor { get; set; } + public int Patch { get; set; } + public PreRelease PreRelease { get; set; } + public string Original { get; set; } + public string PreReleaseBuild { get; set; } + public string Build { get; set; } + + public int CompareTo(object obj) + { + var y = obj as SemVer; + if (y == null) + throw new ArgumentException("cannot compare values of different types", "obj"); + var x = this; + if (x.Major != y.Major) return x.Major.CompareTo(y.Major); + else if (x.Minor != y.Minor) return x.Minor.CompareTo(y.Minor); + else if (x.Patch != y.Patch) return x.Patch.CompareTo(y.Patch); + else if (x.Build != y.Build) + { + int buildx, buildy; + var parseResultx = Int32.TryParse(x.Build, out buildx); + var parseResulty = Int32.TryParse(y.Build, out buildy); + if (parseResultx && parseResulty) + return buildx.CompareTo(buildy); + return x.Build.CompareTo(y.Build); + } + else if (x.PreRelease == y.PreRelease && x.PreReleaseBuild == y.PreReleaseBuild) return 0; + else if (x.PreRelease == null && y.PreRelease != null && x.PreReleaseBuild == "0") return 1; + else if (y.PreRelease == null && x.PreRelease != null && y.PreReleaseBuild == "0") return -1; + else if (x.PreRelease != y.PreRelease) return x.PreRelease.CompareTo(y.PreRelease); + else if (x.PreReleaseBuild != y.PreReleaseBuild) + { + int prereleaseBuildx, prereleaseBuildy; + var parseResultx = Int32.TryParse(x.PreReleaseBuild, out prereleaseBuildx); + var parseResulty = Int32.TryParse(y.PreReleaseBuild, out prereleaseBuildy); + if (parseResultx && parseResulty) + return prereleaseBuildx.CompareTo(prereleaseBuildy); + return x.PreReleaseBuild.CompareTo(y.PreReleaseBuild); + } + else return 0; + } + + public override bool Equals(object obj) + { + var y = obj as SemVer; + if (y == null) + return false; + return Major == y.Major && Minor == y.Minor && Patch == y.Patch && PreRelease == y.PreRelease && Build == y.Build && PreReleaseBuild == y.PreReleaseBuild; + } + } + + private class PreRelease : IComparable + { + public string Origin { get; set; } + public string Name { get; set; } + public long? Number { get; set; } + + public static PreRelease TryParse(string str) + { + var m = new Regex(@"^(?[a-zA-Z]+)(?\d*)$").Match(str); + if (m.Success) + { + long? number = null; + if (m.Groups["number"].Value != "") + number = long.Parse(m.Groups["number"].Value); + + return new PreRelease { Origin = str, Name = m.Groups["name"].Value, Number = number }; + } + return null; + } + + public int CompareTo(object obj) + { + var yObj = obj as PreRelease; + if (yObj == null) + throw new ArgumentException("cannot compare values of different types", "obj"); + var x = this; + if (x.Name != yObj.Name) return x.Name.CompareTo(yObj.Name); + else if (!x.Number.HasValue && yObj.Number.HasValue) + return 1; + else if (x.Number.HasValue && !yObj.Number.HasValue) + return -1; + else if (!x.Number.HasValue && !yObj.Number.HasValue) + return 0; + else + return x.Number.Value.CompareTo(yObj.Number.Value); + } + } } } \ No newline at end of file