public async Task DownloadAndExtractTS(string dir, string versionString) { _logger.Info($"Downloading and extracting TypeScript {versionString}"); var version = new SemVer.Version(versionString); var npmr = new NpmRepositoryAccessor(); var packageEtagAndContent = await npmr.GetPackageInfo("typescript", null); var task = null as Task <byte[]>; try { var packageInfo = new PackageInfo(packageEtagAndContent.content); packageInfo.LazyParseVersions(v => v == version, reader => { var j = PackageJson.Parse(reader); var tgzName = PathUtils.SplitDirAndFile(j.Dist.Tarball).Item2; _logger.Info($"Downloading Tarball {tgzName}"); task = npmr.GetPackageTgz("typescript", tgzName); }); } catch (Exception) { _logger.Error("Failed to parse TypeScript package info: " + packageEtagAndContent.content.Substring(0, Math.Min(1000, packageEtagAndContent.content.Length))); throw; } if (task != null) { var bytes = await task; _logger.Info($"Extracting {bytes.Length} bytes"); await TarExtractor.ExtractTgzAsync(bytes, async (name, stream, size) => { if (name.StartsWith("package/")) { name = name.Substring("package/".Length); } var fn = PathUtils.Join(dir, name); Directory.CreateDirectory(PathUtils.Parent(fn)); using (var targetStream = File.Create(fn)) { var buf = new byte[4096]; while (size > 0) { var read = await stream.ReadAsync(buf, 0, (int)Math.Min((ulong)buf.Length, size)); if (read == 0) { throw new IOException($"Reading {name} failed"); } await targetStream.WriteAsync(buf, 0, read); size -= (ulong)read; } } return(true); }); } else { throw new Exception($"TypeScript version {version} does not exists"); } }