public async Task<TempPackage> FetchAsync(Package pkg, Progress progress) { var user = pkg.Location.Host; var project = pkg.Location.Segments.Skip(1).SingleOrDefault()?.Trim('/'); var props = pkg.Location.ParseQueryString(); var url = $"https://api.github.com/repos/{user}/{project}/releases/latest"; using (var httpClient = NetUtils.HttpClient()) { var content = await httpClient.GetStringAsync(url); var json = fastJSON.JSON.Parse(content) as IDictionary<string, object>; var assets = json["assets"] as IList<object>; var asset = NarrowAssets(assets, props); var pkgUrlString = asset["browser_download_url"] as string; Uri pkgUri; if (!Uri.TryCreate(pkgUrlString, UriKind.Absolute, out pkgUri)) { throw new UriFormatException($"Could not parse output from Github API, failed to parse URI: '{pkgUrlString}'"); } var result = new TempPackage { Package = pkg, WorkDirectory = new TempDirectory("winston"), FileName = pkgUri.LastSegment() }; using (var download = File.Open(result.FullPath, FileMode.Create, FileAccess.ReadWrite)) { await httpClient.DownloadFileAsync(pkgUri, download, progress); } progress?.CompletedDownload(); return result; } }
public async Task<TempPackage> FetchAsync(Package pkg, Progress progress) { var result = new TempPackage { WorkDirectory = new TempDirectory("winston") }; using (var handler = new HttpClientHandler { AllowAutoRedirect = true }) using (var client = NetUtils.HttpClient(handler)) using (var response = await client.GetAsync(pkg.Location, HttpCompletionOption.ResponseHeadersRead)) { result.MimeType = response.Content.Headers.ContentType?.MediaType; var uriFileName = pkg.Location.LastSegment(); // Heuristic: assume the last path segment is a file name if it contains a dot for the file extension if (!uriFileName.Contains('.')) { uriFileName = null; } // Try to get the right file name to give hints about the file type to the extractor result.FileName = response.Content.Headers.ContentDisposition?.FileName?.Trim('\"', '\\', '\'') ?? uriFileName ?? "package"; var total = response.Content.Headers.ContentLength ?? -1L; using (var stream = await response.Content.ReadAsStreamAsync()) using (var output = File.Open(result.FullPath, FileMode.Create, FileAccess.ReadWrite)) { var totalRead = 0L; var buffer = new byte[81920]; // Default size from .NET docs on CopyTo while (true) { var read = await stream.ReadAsync(buffer, 0, buffer.Length); if (read == 0) { break; } await output.WriteAsync(buffer, 0, read); totalRead += read; // Can't report progress if there was no Content-Length if (total > 0) { progress?.Report(totalRead * 1d / (total * 1d) * 100); } } progress?.Report(100); progress?.CompletedDownload(); } } var hash = await FileSystem.GetSha1Async(result.FullPath); // Only check when Sha1 is specified in the package metadata if (!string.IsNullOrWhiteSpace(pkg.Sha1) && !string.Equals(hash, pkg.Sha1, StringComparison.OrdinalIgnoreCase)) { throw new InvalidDataException($"SHA1 hash of remote file {pkg.Location} did not match {pkg.Sha1}"); } return result; }
public async Task<TempPackage> FetchAsync(Package pkg, Progress progress) { var result = new TempPackage { FileName = Path.GetFileName(pkg.Location.LocalPath), Package = pkg, WorkDirectory = new NonTempItem(pkg.Location.LocalPath) }; return await Task.FromResult(result); }
public async Task<string> AddAsync(Package pkg, bool inject = true, bool writeRegistryPath = true) { var pkgDir = Path.Combine(RepoPath, pkg.Name); var client = new PackageClient(pkg, pkgDir); var progress = user.NewProgress(pkg.Name); var installDir = await client.InstallAsync(progress); var junctionPath = CreateCurrentJunction(pkgDir, installDir.FullName); var path = UpdatePaths(pkg, inject, writeRegistryPath, junctionPath); progress.CompletedInstall(); return path; }
public async Task CanFetchLatestVersion(string namePattern) { var fetcher = new GithubFetcher(); var pkg = new Package { Name = "Test", Location = new Uri($"github://mattolenik/winston-test/?name={namePattern}") }; var tmpPkg = await fetcher.FetchAsync(pkg, null); var ext = new ArchiveExtractor(); using (var tmpDir = new TempDirectory("winston-test-")) { await ext.ExtractAsync(tmpPkg, tmpDir, null); Directory.GetFiles(tmpDir).Should().Contain(f => f.Contains("test.exe")); } }
public Package Merge(Package other) { return new Package { Name = Name ?? other.Name, Description = Description ?? other.Description, Maintainer = Maintainer ?? other.Maintainer, Location = Location ?? other.Location, Path = Path ?? other.Path, Type = Type != PackageType.Unspecified ? Type : other.Type, Preserve = Preserve ?? other.Preserve, Ignore = Ignore ?? other.Ignore, Platform = Platform != Platform.Nil ? Platform : other.Platform, Variants = Variants ?? other.Variants, Version = Version ?? other.Version }; }
static string UpdatePaths(Package pkg, bool inject, bool writeRegistryPath, string junctionPath) { var matches = Paths.ResolveGlobPath(junctionPath, pkg.Path); if (matches.Count() > 1) { throw new NotSupportedException("Only globbing which results in a single path result is supported at this time"); } var path = matches.SingleOrDefault(); if (path == null) { throw new ArgumentException("Package path did not resolve to any path on disk"); } // resolve wildcard here if (writeRegistryPath) { UpdateRegistryPath(path); } if (inject) { InjectPathIntoParent(path); } return path; }
public bool IsMatch(Package pkg) { return pkg.Location.Scheme == "http" || pkg.Location.Scheme == "https"; }
public bool IsMatch(Package pkg) { // TODO: check for a pkg.json to verify this directory is really a package? return Directory.Exists(pkg?.Location?.LocalPath ?? ":"); }
public bool IsMatch(Package pkg) { return pkg.Location.Scheme == "github"; }
public PackageClient(Package pkg, string pkgDir) { this.pkg = pkg; this.pkgDir = pkgDir; }