private static void AddPackage(string folder, string packageName, string version = null, bool restore = false)
        {
            var packagesFolder = Path.Combine(folder, "packages");

            if (!Directory.Exists(packagesFolder))
            {
                Directory.CreateDirectory(packagesFolder);
            }

            bool hasVersion = !string.IsNullOrWhiteSpace(version);

            string name      = packageName + (hasVersion ? "." + version : "");
            string localFile = Path.Combine(packagesFolder, name + ".nupkg");

            if (File.Exists(localFile))
            {
                File.Delete(localFile);
            }

            var msg = $"Installing {packageName} ";

            if (!ConsoleSpinner.DumbTerm)
            {
                if (msg.Length <= 29)
                {
                    msg = msg.PadRight(29);
                }
            }

            Console.Write(msg);
            if (Directory.Exists(Path.Combine(packagesFolder, name)))
            {
                Warn("skipped (already exists)");

                return;
            }

            try
            {
                string packageFolder        = null;
                bool   exists               = false;
                bool   success              = false;
                var    repos                = GetRepos();
                PackageRequestResult result = null;
                using (var spinner = new ConsoleSpinner())
                {
                    spinner.Start();
                    foreach (var repo in repos)
                    {
                        result = RequestPackage(repo, packageName, version, localFile, packagesFolder);
                        if (result.Success)
                        {
                            exists        = result.Exists;
                            packageFolder = result.Folder;
                            success       = true;
                            break;
                        }
                    }
                }

                if (!success)
                {
                    if (result != null && result.Exception != null)
                    {
                        Error("failed.");
                        throw result.Exception;
                    }
                    else
                    {
                        Error("not found.");
                    }
                }
                else if (exists)
                {
                    Warn("skipped (already exists)");
                }
                else
                {
                    Info("done.");

                    if (!restore)
                    {
                        RemovePackage(folder, packageName);
                    }

                    Directory.CreateDirectory(packageFolder);
                    ZipFile.ExtractToDirectory(localFile, packageFolder);
                    File.Move(localFile, Path.Combine(packageFolder, Path.GetFileName(packageFolder) + ".nupkg"));

                    PackageInfo info = null;

                    if (!restore)
                    {
                        info = ReadPackageInfo(packageName, packageFolder);
                        AddPackageToConfig(folder, info.Id, info.Version);
                    }

                    CleanPackageAfterDownload(packageFolder);

                    if (info != null && !restore)
                    {
                        DownloadDependencies(folder, info);
                    }
                }
            }
            catch (Exception e)
            {
                var exceptionChain = "";
                var currException  = e;

                while (currException != null)
                {
                    exceptionChain += "- " + currException.Message + nl;
                    currException   = currException.InnerException;
                }
                Error("Error: " + nl + exceptionChain);
#if DEBUG
                throw e;
#endif
            }
        }
        private static PackageRequestResult RequestPackage(string repoPath, string packageName, string version, string localFile, string packagesFolder)
        {
            var  result     = new PackageRequestResult();
            bool hasVersion = !string.IsNullOrWhiteSpace(version);

            try
            {
                if (Directory.Exists(repoPath))
                {
                    string name = null;
                    if (hasVersion)
                    {
                        name = packageName + "." + version;
                    }
                    else
                    {
                        var packages    = Directory.GetFiles(repoPath, "*.nupkg", SearchOption.TopDirectoryOnly);
                        var escapedName = packageName.Replace(".", @"\.");

                        string pattern = "\\A" + escapedName + "\\.\\d+(\\.\\d+){2}\\z";

                        // Prerelease-aware pattern
                        if (Program.EnablePrerelease)
                        {
                            pattern = "\\A" + escapedName + "\\.\\d+(\\.\\d+){2}(|-.*)\\z";
                        }

                        version = null;
                        InformationalVersion latestVersion = null;

                        foreach (var p in packages)
                        {
                            var pName = Path.GetFileNameWithoutExtension(p);
                            if (Regex.IsMatch(pName, pattern, RegexOptions.IgnoreCase))
                            {
                                var pVersion = new InformationalVersion(pName.Substring(packageName.Length + 1));

                                if (latestVersion == null)
                                {
                                    latestVersion = pVersion;
                                }
                                else if (pVersion > latestVersion)
                                {
                                    latestVersion = pVersion;
                                }
                            }
                        }

                        if (latestVersion == null)
                        {
                            return(result);
                        }

                        BridgeVersion.ValidatePackageVersion(packageName, repoPath, latestVersion);

                        name = packageName + "." + latestVersion;
                    }

                    name = name[0].ToString().ToUpper() + name.Substring(1);
                    var packageFolder = Path.Combine(packagesFolder, name);

                    result.Folder = packageFolder;
                    if (Directory.Exists(packageFolder))
                    {
                        result.Exists  = true;
                        result.Success = true;
                    }
                    else
                    {
                        var packageFile = Path.Combine(repoPath, name + ".nupkg");

                        if (File.Exists(packageFile))
                        {
                            File.Copy(packageFile, localFile, true);
                            result.Success = true;
                        }
                        else
                        {
                            result.Success = false;
                        }
                    }
                }
                else
                {
                    var isFile = true;

                    try
                    {
                        var uri = new Uri(repoPath);
                        isFile = uri.IsFile;
                    }
                    catch (Exception)
                    {
                    }

                    if (!isFile)
                    {
                        if (!repoPath.EndsWith("/"))
                        {
                            repoPath += "/";
                        }

                        string uri  = repoPath + packageName + (hasVersion ? "/" + version : "");
                        string name = null;

                        if (hasVersion)
                        {
                            name = packageName + "." + version;
                        }
                        else
                        {
                            var webRequest = (HttpWebRequest)WebRequest.Create(uri + "?" + new Random().Next());
                            webRequest.AllowAutoRedirect = false;
                            var webResponse = (HttpWebResponse)webRequest.GetResponse();

                            if (!String.IsNullOrEmpty(webResponse.Headers["Location"]))
                            {
                                var fileName = System.IO.Path.GetFileName(webResponse.Headers["Location"]);
                                name = Path.GetFileNameWithoutExtension(fileName);
                            }

                            BridgeVersion.ValidatePackageVersion(packageName, repoPath, name.Substring(packageName.Length + 1));

                            webResponse.Dispose();
                        }

                        name = name[0].ToString().ToUpper() + name.Substring(1);
                        var packageFolder = Path.Combine(packagesFolder, name);

                        result.Folder = packageFolder;
                        if (Directory.Exists(packageFolder))
                        {
                            result.Exists  = true;
                            result.Success = true;
                        }
                        else
                        {
                            WebClient client = new WebClient();
                            client.DownloadFile(uri, localFile);
                            client.Dispose();
                            result.Success = true;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                result.Success   = false;
                result.Exception = new Exception("Package request failed.", e);
            }

            return(result);
        }