diff --git a/src/ChocolateStore/Arguments.cs b/src/ChocolateStore/Arguments.cs index 8c515b4..26f8c65 100644 --- a/src/ChocolateStore/Arguments.cs +++ b/src/ChocolateStore/Arguments.cs @@ -3,6 +3,6 @@ class Arguments { public string Directory { get; set; } - public string Url { get; set; } + public string PackageName { get; set; } } } diff --git a/src/ChocolateStore/ChocolateStore.csproj b/src/ChocolateStore/ChocolateStore.csproj index 5e5c0db..da1592c 100644 --- a/src/ChocolateStore/ChocolateStore.csproj +++ b/src/ChocolateStore/ChocolateStore.csproj @@ -34,6 +34,10 @@ 4 + + ..\..\packages\HtmlAgilityPack.1.6.17\lib\Net40-client\HtmlAgilityPack.dll + True + ..\..\packages\DotNetZip.1.9.3\lib\net20\Ionic.Zip.dll @@ -43,6 +47,7 @@ + diff --git a/src/ChocolateStore/PackageCacher.cs b/src/ChocolateStore/PackageCacher.cs index e5d9f47..acc1e57 100644 --- a/src/ChocolateStore/PackageCacher.cs +++ b/src/ChocolateStore/PackageCacher.cs @@ -1,101 +1,111 @@ -using System; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using Ionic.Zip; - -namespace ChocolateStore -{ - class PackageCacher - { - - private const string INSTALL_FILE = "tools/chocolateyInstall.ps1"; - - public delegate void FileHandler(string fileName); - public delegate void DownloadFailedHandler(string url, Exception ex); - - public event FileHandler SkippingFile = delegate { }; - public event FileHandler DownloadingFile = delegate { }; - public event DownloadFailedHandler DownloadFailed = delegate { }; - - public void CachePackage(string dir, string url) - { - var packagePath = DownloadFile(url, dir); - - using (var zip = ZipFile.Read(packagePath)) - { - var entry = zip.FirstOrDefault(x => string.Equals(x.FileName, INSTALL_FILE, StringComparison.OrdinalIgnoreCase)); - - if (entry != null) { - string content = null; - var packageName = Path.GetFileNameWithoutExtension(packagePath); - - using (MemoryStream ms = new MemoryStream()) { - entry.Extract(ms); +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using Ionic.Zip; +using HtmlAgilityPack; + +namespace ChocolateStore +{ + class PackageCacher + { + + private const string INSTALL_FILE = "tools/chocolateyInstall.ps1"; + + public delegate void FileHandler(string fileName); + public delegate void DownloadFailedHandler(string url, Exception ex); + + public event FileHandler SkippingFile = delegate { }; + public event FileHandler DownloadingFile = delegate { }; + public event DownloadFailedHandler DownloadFailed = delegate { }; + + public void CachePackage(string packageName, string directory) + { + var packageInfo = new PackageInfo(packageName); + + var packagePath = DownloadFile(packageInfo.url, directory); + + using (var zip = ZipFile.Read(packagePath)) + { + var entry = zip.FirstOrDefault(x => string.Equals(x.FileName, INSTALL_FILE, StringComparison.OrdinalIgnoreCase)); + + if (entry != null) { + string content = null; + + using (MemoryStream ms = new MemoryStream()) { + entry.Extract(ms); ms.Position = 0; using (StreamReader reader = new StreamReader(ms, true)) { content = reader.ReadToEnd(); } - } - - content = CacheUrlFiles(Path.Combine(dir, packageName), content); - zip.UpdateEntry(INSTALL_FILE, content); - zip.Save(); - - } - - } - - } - - private string CacheUrlFiles(string folder, string content) - { - - const string pattern = "(?<=['\"])http[\\S ]*(?=['\"])"; - - if (!Directory.Exists(folder)) { - Directory.CreateDirectory(folder); - } - - return Regex.Replace(content, pattern, new MatchEvaluator(m => DownloadFile(m.Value, folder))); - - } - - private string DownloadFile(string url, string destination) - { - - try - { - var request = WebRequest.Create(url); - var response = request.GetResponse(); - var fileName = Path.GetFileName(response.ResponseUri.LocalPath); - var filePath = Path.Combine(destination, fileName); - - if (File.Exists(filePath)) - { - SkippingFile(fileName); - } - else - { - DownloadingFile(fileName); - using (var fs = File.Create(filePath)) - { - response.GetResponseStream().CopyTo(fs); - } - } - - return filePath; - } - catch (Exception ex) - { - DownloadFailed(url, ex); - return url; - } - - } - - } + } + + content = CacheUrlFiles(Path.Combine(directory, packageName), content); + zip.UpdateEntry(INSTALL_FILE, content); + zip.Save(); + + } + + } + + if (packageInfo.dependencies != null) + { + foreach (var dep in packageInfo.dependencies) + { + CachePackage(dep, directory); + } + } + + } + + private string CacheUrlFiles(string folder, string content) + { + + const string pattern = "(?<=['\"])http[\\S ]*(?=['\"])"; + + if (!Directory.Exists(folder)) { + Directory.CreateDirectory(folder); + } + + return Regex.Replace(content, pattern, new MatchEvaluator(m => DownloadFile(m.Value, folder))); + + } + + private string DownloadFile(string url, string destination) + { + + try + { + var request = WebRequest.Create(url); + var response = request.GetResponse(); + var fileName = Path.GetFileName(response.ResponseUri.LocalPath); + var filePath = Path.Combine(destination, fileName); + + if (File.Exists(filePath)) + { + SkippingFile(fileName); + } + else + { + DownloadingFile(fileName); + using (var fs = File.Create(filePath)) + { + response.GetResponseStream().CopyTo(fs); + } + } + + return filePath; + } + catch (Exception ex) + { + DownloadFailed(url, ex); + return url; + } + + } + + } } \ No newline at end of file diff --git a/src/ChocolateStore/PackageInfo.cs b/src/ChocolateStore/PackageInfo.cs new file mode 100644 index 0000000..a3919d0 --- /dev/null +++ b/src/ChocolateStore/PackageInfo.cs @@ -0,0 +1,29 @@ +using System; +using System.Linq; +using HtmlAgilityPack; + +namespace ChocolateStore +{ + class PackageInfo + { + public string name { get; set; } + public string url { get; set; } + public string[] dependencies { get; set; } + public PackageInfo(string packageName) + { + Console.WriteLine("Reading package '{0}'", packageName); + this.name = packageName; + var web = new HtmlWeb(); + var doc = web.Load("https://chocolatey.org/packages/" + packageName); + this.url = doc.DocumentNode + .SelectSingleNode("//a[contains(@title, 'nupkg')]") + .Attributes["href"].Value; + Console.WriteLine("package URL: '{0}'", this.url); + try + { + this.dependencies = doc.DocumentNode.SelectNodes("//ul[@id='dependencySets']//a").Select(node => node.InnerText).ToArray(); + } catch (Exception) { } + + } + } +} diff --git a/src/ChocolateStore/Program.cs b/src/ChocolateStore/Program.cs index 50a2c94..3a9f5a7 100644 --- a/src/ChocolateStore/Program.cs +++ b/src/ChocolateStore/Program.cs @@ -21,7 +21,7 @@ static void Main(string[] args) if (arguments != null) { - cacher.CachePackage(arguments.Directory, arguments.Url); + cacher.CachePackage(arguments.PackageName, arguments.Directory); } } @@ -39,7 +39,7 @@ private static Arguments ParseArguments(string[] args) if (args.Length != 2) { - WriteError("USAGE: ChocolateStore "); + WriteError("USAGE: ChocolateStore "); return null; } @@ -47,17 +47,16 @@ private static Arguments ParseArguments(string[] args) if (!Directory.Exists(arguments.Directory)) { - WriteError("Directory '{0}' does not exist.", arguments.Directory); - return null; + if (!PromptConfirm("Directory '{0}' does not exist. Create?", arguments.Directory)) + { + WriteError("Directory '{0}' does not exist.", arguments.Directory); + return null; + } + Directory.CreateDirectory(arguments.Directory); + Console.WriteLine("Created Directory '{0}'", arguments.Directory); } - arguments.Url = args[1]; - - if (!Uri.IsWellFormedUriString(arguments.Url, UriKind.Absolute)) - { - WriteError("URL '{0}' is invalid.", arguments.Url); - return null; - } + arguments.PackageName = args[1]; return arguments; @@ -100,5 +99,15 @@ private static void WriteError(string format, params object[] arg) Console.ResetColor(); } + private static bool PromptConfirm(string format, params object[] arg) + { + Console.ForegroundColor = ConsoleColor.DarkCyan; + Console.Write(format + " [y/n] ", arg); + Console.ResetColor(); + ConsoleKey response = Console.ReadKey(false).Key; + Console.WriteLine(); + return response == ConsoleKey.Y; + } + } } diff --git a/src/ChocolateStore/packages.config b/src/ChocolateStore/packages.config index ed41fa3..0387b2e 100644 --- a/src/ChocolateStore/packages.config +++ b/src/ChocolateStore/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file