void DumpWarnings(IActivityMonitor m, HttpResponseHeaders responseHeaders) { if (responseHeaders.Contains("warning")) { foreach (string warning in responseHeaders.GetValues("warning")) { m.Warn($"NPM warning: {warning}"); var match = Regex.Match(warning, @"/^\s*(\d{3})\s+(\S+)\s+""(.*)""\s+""([^""]+)""/"); if (!int.TryParse(match.Groups[1].Value, out int code)) { m.Error("Incorrect warning header format."); continue; } string host = match.Groups[2].Value; string message = match.Groups[3].Value; DateTime date = JsonConvert.DeserializeObject <DateTime>(match.Groups[4].Value); if (code == 199) { if (message.Contains("ENOTFOUND")) { m.Warn($"registry: Using stale data from {RegistryUri.ToString()} because the host is inaccessible -- are you offline?"); m.Error("Npm.Net is not using any caches, so you should not see the previous warning."); } else { m.Warn($"Unexpected warning for {RegistryUri.ToString()}: {message}"); } } else if (code == 111) { m.Warn($"Using stale data from {RegistryUri.ToString()} due to a request error during revalidation."); } } } }
/// <summary> /// Publish a package to the repository /// </summary> /// <param name="m"></param> /// <param name="packageJson">The package.json of the package to push</param> /// <param name="tarball">This stream must be Seek-able. <see cref="Stream"/> of the tarball of the package to push.</param> /// <param name="distTag"></param> /// <returns></returns> public bool Publish(IActivityMonitor m, NormalizedPath tarballPath, bool isPublic, string scope = null, string distTag = null) { if (RegistryUri.IsFile) { var path = Path.Combine(RegistryUri.AbsolutePath, tarballPath.LastPart); if (File.Exists(path)) { return(true); } try { File.Copy(tarballPath, path); return(true); } catch (Exception e) { m.Error(e); } return(false); } string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); using (m.OpenInfo("Using 'npm publish'.")) { try { Directory.CreateDirectory(tempDirectory); m.Debug($"Creating temp directory {tempDirectory}."); using (m.OpenInfo("Creating .npmrc with content:")) using (StreamWriter w = File.CreateText(Path.Combine(tempDirectory, ".npmrc"))) { string uriString = RegistryUri.ToString(); w.WriteLine($"registry={uriString}"); m.Debug($"registry={uriString}"); string uriConfig = uriString.Remove(0, uriString.IndexOf('/')); if (_authHeader == null) { m.Error("Missing credentials to configure .npmrc file."); return(false); } if (_authHeader.Scheme == "Basic") { w.WriteLine($"{uriConfig}:always-auth=true"); m.Debug($"{uriConfig}:always-auth=true"); w.WriteLine($"{uriConfig}:_password={Convert.ToBase64String( Encoding.UTF8.GetBytes( _password ) )}"); m.Debug($"{uriConfig}:_password=[REDACTED]"); w.WriteLine($"{uriConfig}:username={_username}"); m.Debug($"{uriConfig}:username={_username}"); } else if (_authHeader.Scheme == "Bearer") { w.WriteLine($"{uriConfig}:always-auth=true"); m.Debug($"{uriConfig}:always-auth=true"); w.WriteLine($"{uriConfig}:_authToken={_authHeader.Parameter}"); m.Debug($"{uriConfig}:_authToken=[REDACTED]"); } if (!string.IsNullOrWhiteSpace(scope)) { w.WriteLine(scope + $":registry={RegistryUri.ToString()}"); m.Debug(scope + $":registry={RegistryUri.ToString()}"); } } string tarPath = Path.GetFullPath(tarballPath); string distTagArg = distTag != null ? $"--tag {distTag.ToLowerInvariant()}" : ""; string access = isPublic ? "public" : "private"; if (Environment.OSVersion.Platform != PlatformID.Win32NT) { throw new PlatformNotSupportedException("Linux not supported yet."); } return(ProcessRunner.Run(m, tempDirectory, "cmd.exe", $"/C npm publish \"{tarPath}\" --access {access} {distTagArg}", LogLevel.Info)); } catch (Exception ex) { m.Error(ex); return(false); } finally { try { Directory.Delete(tempDirectory, true); } catch (Exception ex) { m.Warn($"While destroying temporary folder: {tempDirectory}", ex); } } } }
public override string ToString() => RegistryUri.ToString();