Пример #1
0
        public DeployerCollection GrabServices(ILoggerInterface logger)
        {
            Dictionary <string, Type> serviceTypes = new Dictionary <string, Type>()
            {
                { "sqlsrv", typeof(Services.SQLService) },
                { "disk", typeof(Services.DiskService) },
                { "couchbase", typeof(Services.CouchbaseService) },
                { "scheduler", typeof(Services.ScheduleService) }
            };

            var services = new DeployerCollection(this.globalSettings, this, logger, this.parentInstalledApplicationSettings);

            foreach (var d in this.appSettings.getServices())
            {
                var type = (string)d.Value["type"];

                if (!serviceTypes.ContainsKey(type))
                {
                    throw new Exception("Service type not found:" + type);
                }

                Type serviceType = serviceTypes[type];
                services.AddItem(serviceType, (JObject)d.Value);
            }

            return(services);
        }
Пример #2
0
        /// <summary>
        /// Grab the deployers for an application
        /// </summary>
        /// <returns></returns>
        public DeployerCollection GrabDeployers(ILoggerInterface logger)
        {
            Dictionary <string, Type> deployerTypes = new Dictionary <string, Type>()
            {
                { "php", typeof(Php.PhpDeployer) },
                { "iis", typeof(IIS.IISDeployer) },
                { "app", typeof(Storage.AppBaseStorageDeployer) },
            };

            var deployers = new DeployerCollection(this.globalSettings, this, logger, this.parentInstalledApplicationSettings);

            foreach (var d in this.appSettings.getDeployers())
            {
                var type = (string)d.Value["type"];

                if (type == null || !deployerTypes.ContainsKey(type))
                {
                    throw new Exception($"Deployer type '{type}' not found.");
                }

                Type deployertype = deployerTypes[type];

                deployers.AddItem(deployertype, (JObject)d.Value);
            }

            return(deployers);
        }
Пример #3
0
        /// <summary>
        /// Get an instance of SslCertificateProviderService
        /// </summary>
        public SslCertificateProviderService(
            ILoggerInterface logger,
            string appId,
            EnvironmentSettings globalSettings,
            Deployment deployment)
        {
            this.AppPoolUtils    = new UtilsAppPool(logger);
            this.UtilsHosts      = new UtilsHosts(logger);
            this.MockEnvironment = UtilsSystem.RunningInContinuousIntegration() || UnitTestDetector.IsRunningInTests || Debugger.IsAttached;

            // Everything performed against the staging API needs to be kept apart, including signer, etc...
            this.StoragePath = Path.Combine(globalSettings.GetDefaultContentStorage().path, "letsencrypt" + (this.MockEnvironment ? "_mock" : null));
            UtilsSystem.EnsureDirectoryExists(this.StoragePath, true);

            // If CCS is available, use that, otherwise use the central content storage
            string sslRenewalStateStorePath = UtilsIis.CentralStoreEnabled()
                ? UtilsIis.CentralStorePath(logger)
                : globalSettings.GetDefaultContentStorage().path;

            this.SimpleStoreRenewalStatus = new SimpleStore(Path.Combine(sslRenewalStateStorePath, "_ssl_renewal_state_store"), true);

            this.Logger         = logger;
            this.AppId          = appId;
            this.Deployment     = deployment;
            this.GlobalSettings = globalSettings;
        }
        /// <summary>
        /// Get a deployer for the installed application.
        /// </summary>
        /// <param name="globalSettings">The global settings.</param>
        /// <param name="installedApplicationSettings">The installed application settings.</param>
        /// <param name="logger">The logger.</param>
        public ApplicationDeployer(
            EnvironmentSettings globalSettings,
            InstalledApplication installedApplicationSettings,
            ILoggerInterface logger)
        {
            this.GlobalSettings       = globalSettings;
            this.installedAppSettings = installedApplicationSettings;
            this.Logger = logger;

            if (this.GlobalSettings == null)
            {
                throw new InvalidDataException("settings argument cannot be null.");
            }

            if (this.installedAppSettings == null)
            {
                throw new Exception("installedApplicationSettings argument cannot be null.");
            }

            // Try to grab previous deployment...
            this.activeDeploymentPathStorage = UtilsSystem.CombinePaths(globalSettings.activeDeploymentDir, "active." + this.installedAppSettings.GetId() + ".json");

            if (File.Exists(this.activeDeploymentPathStorage))
            {
                this.DeploymentActive = Deployment.InstanceFromPath(this.activeDeploymentPathStorage, globalSettings);
            }
        }
Пример #5
0
        /// <summary>
        /// Get a setting
        /// </summary>
        /// <typeparam name="TType"></typeparam>
        /// <param name="name"></param>
        /// <param name="defaultValue"></param>
        /// <param name="logger"></param>
        /// <param name="isEnum"></param>
        /// <returns></returns>
        public TType GetSettingPersistent <TType>(string name, TType defaultValue, ILoggerInterface logger, bool isEnum = false)
        {
            this.privateDataPersistent = this.privateDataPersistent ?? new Dictionary <string, object>();

            TType result = defaultValue;

            if (!this.privateDataPersistent.ContainsKey(name))
            {
                return(defaultValue);
            }

            try
            {
                if (isEnum)
                {
                    result = (TType)Enum.Parse(typeof(TType), Convert.ToString(this.privateDataPersistent[name]));
                }
                else
                {
                    result = (TType)this.privateDataPersistent[name];
                }
            }
            catch (Exception e)
            {
                logger.LogInfo(false, "source value: '" + Convert.ToString(this.privateDataPersistent[name]) + "'");
                logger.LogException(e);
            }

            return(result);
        }
Пример #6
0
        /// <summary>
        /// Get an instance of Application
        /// </summary>
        /// <param name="parentLogger">Logger implementation</param>
        public Application(ILoggerInterface parentLogger)
        {
            NewRelic.Api.Agent.NewRelic.SetApplicationName("IisChef");

            NewRelicAgentExtensions.AddCustomParameter("server", Environment.MachineName);
            NewRelicAgentExtensions.AddCustomParameter("user", Environment.UserName);

            BindingRedirectHandler.DoBindingRedirects(AppDomain.CurrentDomain);

            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol  = SecurityProtocolType.Tls
                                                    | SecurityProtocolType.Tls11
                                                    | SecurityProtocolType.Tls12
                                                    | SecurityProtocolType.Ssl3;

            // Check current account
            var identity  = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(identity);

            parentLogger.LogInfo(false, $"Chef app started with identity '{identity.Name}'");

            if (!principal.IsInRole(WindowsBuiltInRole.Administrator))
            {
                parentLogger.LogError("Not running under full admin privileges.");

                if (Debugger.IsAttached)
                {
                    throw new Exception("You must run the deployer with full privileges.");
                }
            }

            // Use the parent logger, at least until we can build a file based one...
            this.Logger = parentLogger;
        }
Пример #7
0
        /// <summary>
        /// Central store path for certificates. Returns exception if not configured or cannot be returned.
        /// </summary>
        public static string CentralStorePath(ILoggerInterface logger)
        {
            if (!CentralStoreEnabled())
            {
                throw new Exception(
                          "IIS Central store path not enabled or installed. Please check https://blogs.msdn.microsoft.com/kaushal/2012/10/11/central-certificate-store-ccs-with-iis-8-windows-server-2012/");
            }

            string certStoreLocation = Convert.ToString(UtilsRegistry.GetRegistryKeyValue64(
                                                            RegistryHive.LocalMachine,
                                                            "SOFTWARE\\Microsoft\\IIS\\CentralCertProvider",
                                                            "CertStoreLocation",
                                                            string.Empty));

            if (string.IsNullOrWhiteSpace(certStoreLocation))
            {
                throw new Exception("IIS Central store location not configured");
            }

            var resolvedCertStoreLocation = certStoreLocation;

            if (UtilsJunction.IsJunctionOrSymlink(certStoreLocation))
            {
                resolvedCertStoreLocation = UtilsJunction.ResolvePath(resolvedCertStoreLocation);
            }

            if (UtilsSystem.IsNetworkPath(resolvedCertStoreLocation))
            {
                logger.LogWarning(true, "Central Certificate Store Path is located on a network share [{0}]. This has proven to be unstable as CCS will cache corrupted certificates when it is unable to read from the network share.", certStoreLocation);
            }

            return(certStoreLocation);
        }
Пример #8
0
 public CourseService(IDataInterface _dataSource, IConfiguration _config, ILoggerInterface _logger)
 {
     config     = _config;
     dataSource = _dataSource;
     data       = dataSource.GetDataSource();
     logger     = _logger;
 }
Пример #9
0
        public static void DeleteFile(
            string file,
            ILoggerInterface logger,
            int waitTimeIfInUse = 10)
        {
            ValidateDirectoryDepthDeletion(file);
            file = EnsureLongPathSupportIfAvailable(file);

            if (!File.Exists(file))
            {
                return;
            }

            RetryWhile(
                () =>
            {
                File.Delete(file);
            },
                ExceptionIsAccessDeniedOrFileInUse,
                waitTimeIfInUse * 1000,
                logger);

            if (File.Exists(file))
            {
                throw new Exception($"Could not delete file '{file}' see log for details.");
            }
        }
Пример #10
0
        /// <summary>
        /// Remove all rewrite rules that start with the given prefix.
        /// </summary>
        /// <param name="prefix"></param>
        /// <param name="logger"></param>
        public void RemoveRewriteRulesWithPrefix(string prefix, ILoggerInterface logger)
        {
            // If there is no CDN site, do nothing
            using (ServerManager manager = new ServerManager())
            {
                var site = UtilsIis.FindSiteWithName(manager, this.CstChefCndSiteName, logger).SingleOrDefault();

                if (site == null)
                {
                    return;
                }
            }

            var       webconfigfilepath = this.GetCdnWebConfigPathInitialized();
            XDocument webcfg            = XDocument.Parse(File.ReadAllText(webconfigfilepath));

            var rules = (from p in webcfg.Descendants("rule")
                         where p.Attribute("name")?.Value?.StartsWith(prefix) == true
                         select p).ToList();

            foreach (var rule in rules)
            {
                rule?.Remove();
            }

            UtilsIis.WriteWebConfig(webconfigfilepath, webcfg.ToString());
        }
Пример #11
0
        /// <summary>
        /// Grab from a settings file.
        /// </summary>
        /// <param name="path"></param>
        /// <param name="logger"></param>
        public void PopulateFromSettingsFile(string path, ILoggerInterface logger)
        {
            string file = UtilsSystem.CombinePaths(path, "artifact-settings.yml");

            if (!File.Exists(file))
            {
                return;
            }

            var configfile = new Configuration.YamlConfigurationFile();

            try
            {
                // This file might be malformed, do not crash and let other
                // environment information sources have their chance
                configfile.ParseFromFile(file);
            }
            catch (Exception e)
            {
                logger.LogException(new Exception("Error parsing file: " + file, e));
                return;
            }

            // Parse the artifact settings...
            this.branch     = configfile.GetStringValue("repo-branch", null);
            this.commit_sha = configfile.GetStringValue("repo-commit", null);
            this.version    = configfile.GetStringValue("build-id", null);
        }
        /// <summary>
        /// Add permissions to a directory if missing
        /// </summary>
        /// <param name="identity"></param>
        /// <param name="directory"></param>
        /// <param name="logger"></param>
        public static void RemoveAccessRulesForIdentity(
            IdentityReference identity,
            string directory,
            ILoggerInterface logger)
        {
            var directoryInfo = new DirectoryInfo(directory);

            // Get a DirectorySecurity object that represents the current security settings.
            DirectorySecurity dSecurity = directoryInfo.GetAccessControl();

            bool removed = false;

            var rules = dSecurity.GetAccessRules(true, true, typeof(SecurityIdentifier));

            foreach (AuthorizationRule r in rules)
            {
                if (r.IdentityReference == identity)
                {
                    var currentRule = (FileSystemAccessRule)r;
                    dSecurity.RemoveAccessRule(currentRule);
                    removed = true;
                }
            }

            if (removed)
            {
                directoryInfo.SetAccessControl(dSecurity);
            }
            else
            {
                logger.LogInfo(true, "Could not find any rule to remove for identity {0}", identity.Value);
            }
        }
Пример #13
0
        /// <summary>
        /// Get the executable path of a process from it's process id
        /// </summary>
        /// <param name="processId"></param>
        /// <returns></returns>
        public static ProcessInfo GetProcessInfo(int processId, ILoggerInterface logger)
        {
            ProcessInfo result = new ProcessInfo();

            result.ProcessId = processId;

            try
            {
                string query = "SELECT ExecutablePath, Name, CommandLine FROM Win32_Process WHERE ProcessId = " + processId;

                using (ManagementObjectSearcher mos = new ManagementObjectSearcher(query))
                {
                    using (ManagementObjectCollection moc = mos.Get())
                    {
                        result.MainModulePath = (from mo in moc.Cast <ManagementObject>() select mo["ExecutablePath"]).First().ToString();
                        result.ProcessName    = (from mo in moc.Cast <ManagementObject>() select mo["Name"]).First().ToString();
                        result.CommandLine    = (from mo in moc.Cast <ManagementObject>() select mo["CommandLine"]).First().ToString();
                    }
                }
            }
            catch (Exception e)
            {
                logger.LogWarning(true, e.Message);
            }

            return(result);
        }
Пример #14
0
        public CSVThread(String Path, ILoggerInterface Logger, Salesforce.Salesforce Sfdc)
        {
            Header            = new Dictionary <int, string>();
            Columns           = new List <string>();
            Columns           = new List <string>();
            Row               = new Dictionary <string, string>();
            startLine         = new Dictionary <int, int>();
            sfdcs             = new List <Salesforce.Salesforce>();
            MinimumThreadSize = 1000;
            isInProgress      = false;
            _Processed        = 0;

            this.Logger = Logger;

            if (!File.Exists(Path))
            {
                throw new FileNotFoundException("File to parse: {0} not found!", Path);
            }

            this.Path = Path;

            CSV  = new StreamReader(Path);
            Size = File.ReadLines(Path).Count() - 1; //do not count header line

            Cores = (Size > MinimumThreadSize) ? Environment.ProcessorCount : 1;

            //get Header
            sfdcs.Add(Sfdc);
            GetHeader();
        }
Пример #15
0
 /// <summary>
 /// Delete a directory
 /// </summary>
 /// <param name="strDir"></param>
 /// <param name="logger"></param>
 /// <param name="waitTimeIfInUse"></param>
 public static void DeleteDirectory(
     string strDir,
     ILoggerInterface logger,
     int waitTimeIfInUse = 10)
 {
     DoDeleteDirectory(strDir, logger, null, waitTimeIfInUse);
 }
Пример #16
0
        /// <summary>
        /// Moves a directory (MOVE) if in same drive, or copies and deletes if between drives
        /// as MOVE operation is not supported in such scenario. Supports long path names.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <param name="logger"></param>
        /// <param name="ignoreOnDeployPattern"></param>
        public static void MoveDirectory(string source, string destination, ILoggerInterface logger, string ignoreOnDeployPattern = null)
        {
            try
            {
                source      = EnsureLongPathSupportIfAvailable(source);
                destination = EnsureLongPathSupportIfAvailable(destination);

                RetryWhile(
                    () => { Directory.Move(source, destination); },

                    // Retry while access to the path is denied, in move operations
                    // this might happen due to files being scanned by an antivirus
                    // or other transient locks
                    (e) => Convert.ToString((uint)e.HResult) == "2147942405",
                    10000,
                    logger);
            }
            catch (IOException e)
            {
                if (e.HResult != -2146232800)
                {
                    throw;
                }

                logger.LogInfo(
                    true,
                    $"Move operation cannot complete because source '{source}' and destination '{destination}' are on same drive, falling back to copy.");

                CopyFilesRecursivelyFast(source, destination, false, ignoreOnDeployPattern, logger);
                Directory.Delete(source, true);
            }
        }
Пример #17
0
        /// <summary>
        /// Retry an action while the exception meets the condition during the maximum wait specified
        /// </summary>
        /// <param name="task"></param>
        /// <param name="condition"></param>
        /// <param name="maxWait">Max milliseconds for the operation to complete</param>
        /// <param name="logger"></param>
        /// <param name="minRetries"></param>
        public static void RetryWhile(
            Action task,
            Func <Exception, bool> condition,
            int maxWait,
            ILoggerInterface logger,
            int minRetries = 2)
        {
            Stopwatch sw = Stopwatch.StartNew();

            sw.Start();
            int sleep     = 250;
            int sleepStep = 400;
            int failCount = 0;

            while (true)
            {
                try
                {
                    task();

                    if (failCount > 0)
                    {
                        logger?.LogInfo(true, "Operation completed.");
                    }

                    return;
                }
                catch (Exception e)
                {
                    // If the looping condition is not met, throw the exception.
                    if (!condition(e))
                    {
                        throw;
                    }

                    // If we have reached the maximum wait limit plus we have failed at least once, abort.
                    if (sw.ElapsedMilliseconds > maxWait && failCount >= minRetries)
                    {
                        throw new Exception($"Transient error did not go away after waiting for {maxWait}ms and failing {failCount} times...", e);
                    }

                    failCount++;

                    string errorMessage = e.Message;

                    if (e is AggregateException aggregateException)
                    {
                        errorMessage += "(" + string.Join(
                            ", ",
                            aggregateException.InnerExceptions.Select((i) => i.Message)) + ")";
                    }

                    logger?.LogInfo(true, "Found transient error: {0}", errorMessage);
                    logger?.LogInfo(true, "Retrying operation...");
                    Thread.Sleep(sleep);
                    sleep = sleep + sleepStep;
                }
            }
        }
Пример #18
0
        /// <summary>
        /// Delete the artifact's source if it is remote
        /// </summary>
        /// <param name="artifact"></param>
        /// <param name="logger"></param>
        public static void DeleteIfRemote(this Artifact artifact, ILoggerInterface logger)
        {
            if (!artifact.isRemote)
            {
                return;
            }

            UtilsSystem.DeleteDirectory(artifact.localPath, logger);
        }
Пример #19
0
 public Salesforce(String token, String instanceUrl, ILoggerInterface Logger)
 {
     Token        = "Bearer " + token;
     InstanceUrl  = instanceUrl;
     Client       = new RestClient(InstanceUrl);
     this.Logger  = Logger;
     this.Mapping = new Dictionary <int, MappingPayload.Mapping>();
     Meta         = new Dictionary <String, Metadata>();
 }
Пример #20
0
    /// <summary>
    /// Death also has to based on the object, either player or enemy
    /// </summary>
    /// <param name="loggerInterface"></param>
    public void Death(ILoggerInterface loggerInterfaces)
    {
        var enemies = GameObject.FindGameObjectsWithTag("Enemy");

        for (int i = 0; i < enemies.Length; i++)
        {
            Destroy(enemies[i]);
        }
    }
 /// <summary>
 /// Get an instance of LocalPathDownloader.
 /// </summary>
 /// <param name="settings"></param>
 /// <param name="globalSettings"></param>
 /// <param name="logger"></param>
 public LocalPathDownloader(
     LocalPathDownloaderSettings settings,
     EnvironmentSettings globalSettings,
     ILoggerInterface logger)
 {
     this.Settings       = settings;
     this.GlobalSettings = globalSettings;
     this.Logger         = logger;
 }
 /// <summary>
 /// Create an Application service
 /// </summary>
 /// <param name="settingsFile">The settings file. Will default to what is in appSettings.settingsFile
 /// in the application configuration file.</param>
 /// <param name="console"></param>
 public ApplicationService(
     string settingsFile = null,
     bool console        = false)
 {
     this.Console      = console;
     this.Logger       = new SystemLogger("ChefApp");
     this.SettingsFile = settingsFile ?? System.Configuration.ConfigurationManager.AppSettings["settingsFile"];
     this.Logger.LogInfo(false, "Chef service instantiated with settings file: {0}", settingsFile);
 }
Пример #23
0
 /// <summary>
 /// Get an instance of ItemDownloader
 /// </summary>
 public ItemDownloader(
     ILoggerInterface logger,
     ItemDownloaderConfig config,
     string localArtifactPath)
 {
     this.Logger            = logger;
     this.Config            = config;
     this.LocalArtifactPath = localArtifactPath;
 }
Пример #24
0
 /// <summary>
 /// Get an instance of AppVeyorMonitor
 /// </summary>
 /// <param name="settings"></param>
 /// <param name="app"></param>
 /// <param name="logger"></param>
 public AppVeyorMonitor(
     AppVeyorMonitorSettings settings,
     Application app,
     ILoggerInterface logger)
 {
     this.Settings = settings;
     this.client   = new utils.AppVeyor.Client(this.Settings.apitoken, "https://ci.appveyor.com", logger, app.GetGlobalSettings().GetDefaultTempStorage().path);
     this.app      = app;
     this.Logger   = logger;
 }
Пример #25
0
 public override void initialize(
     EnvironmentSettings globalSettings,
     JObject deployerSettings,
     Deployment deployment,
     ILoggerInterface logger,
     InstalledApplication inhertApp)
 {
     base.initialize(globalSettings, deployerSettings, deployment, logger, inhertApp);
     this.PhpSettings = deployerSettings.castTo <PhpEnvironment>();
 }
Пример #26
0
 public async Task InvokeAsync(HttpContext httpContext, ILoggerInterface loggerInterface)
 {
     try
     {
         await _next(httpContext);
     }
     catch (Exception ex)
     {
         await HandleExceptionAsync(httpContext, ex, loggerInterface);
     }
 }
Пример #27
0
        /// <summary>
        /// Delete a directory
        /// </summary>
        /// <param name="strDir">Directory to delete</param>
        /// <param name="logger"></param>
        /// <param name="closeProcesses">Force a process close if it cannot be deleted (i.e. in use)</param>
        /// <param name="waitTimeIfInUse">If in-use, time to wait (in seconds) before either failing or closing all processes if forceCloseProcesses is true.</param>
        private static void DoDeleteDirectory(
            string strDir,
            ILoggerInterface logger,
            List <string> closeProcesses = null,
            int waitTimeIfInUse          = 10)
        {
            if (string.IsNullOrWhiteSpace(strDir))
            {
                logger.LogWarning(true, "Empty directory name provided DoDeleteDirectory, skipping.");
                return;
            }

            ValidateDirectoryDepthDeletion(strDir);
            strDir = EnsureLongPathSupportIfAvailable(strDir);

            if (!Directory.Exists(strDir))
            {
                return;
            }

            logger.LogInfo(true, "Removing directory {0} with close processes {1}", strDir, closeProcesses == null ? string.Empty : string.Join(", ", closeProcesses));

            if (closeProcesses?.Any() == true)
            {
                var processes = UtilsProcess.GetPathProcessesInfo(strDir, logger, true);

                foreach (var p in processes.AsIterable())
                {
                    logger.LogWarning(
                        false,
                        "The following process might be blocking files in the directory: {0}",
                        p.CommandLine);
                }

                if (processes.Any())
                {
                    UtilsProcess.ClosePathProcesses(strDir, closeProcesses, logger);
                }
            }

            RetryWhile(
                () =>
            {
                DeleteDirectoryAndRemovePermissionsIfNeeded(strDir);
            },
                ExceptionIsAccessDeniedOrFileInUse,
                waitTimeIfInUse * 1000,
                logger);

            if (Directory.Exists(strDir))
            {
                throw new Exception($"Could not completely delete directory '{strDir}', see log for details.");
            }
        }
 /// <summary>
 /// Get an instance of DeployerCollection
 /// </summary>
 public DeployerCollection(
     EnvironmentSettings globalSettings,
     Deployment deployment,
     ILoggerInterface logger,
     InstalledApplication inhertApp)
 {
     this.GlobalSettings = globalSettings;
     this.Deployment     = deployment;
     this.Logger         = logger;
     this.InhertApp      = inhertApp;
 }
Пример #29
0
 /// <summary>
 /// Delete a directory, and detect and close any processes that might be holding a handle
 /// </summary>
 /// <param name="strDir"></param>
 /// <param name="logger"></param>
 /// <param name="closeProcesses"></param>
 /// <param name="waitTimeIfInUse"></param>
 public static void DeleteDirectoryAndCloseProcesses(
     string strDir,
     ILoggerInterface logger,
     List <string> closeProcesses,
     int waitTimeIfInUse = 10)
 {
     DoDeleteDirectory(
         strDir,
         logger,
         closeProcesses,
         waitTimeIfInUse);
 }
Пример #30
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="settings"></param>
 /// <param name="globalSettings"></param>
 /// <param name="logger"></param>
 /// <param name="tempDir">Directory to use for temporary storage.</param>
 /// <param name="applicationId">Application ID, this will be used to customize temp storage paths per application.</param>
 public AppVeyorDownloader(
     AppVeyorDownloaderSettings settings,
     EnvironmentSettings globalSettings,
     ILoggerInterface logger,
     string tempDir,
     string applicationId)
 {
     this.ApplicationId  = applicationId;
     this.Settings       = settings;
     this.Logger         = logger;
     this.GlobalSettings = globalSettings;
     this.Client         = new Client(settings.apitoken, "https://ci.appveyor.com", logger, tempDir);
 }