public void run(PackageResult packageResult, ChocolateyConfiguration config)
        {
            var installDirectory = packageResult != null ? packageResult.InstallLocation : string.Empty;

            if (string.IsNullOrWhiteSpace(installDirectory) || installDirectory.is_equal_to(ApplicationParameters.InstallLocation) || installDirectory.is_equal_to(ApplicationParameters.PackagesLocation))
            {
                var logMessage = "Install location is not specific enough, cannot capture files:{0} Erroneous install location captured as '{1}'".format_with(Environment.NewLine, installDirectory);
                if (packageResult != null)
                {
                    packageResult.Messages.Add(new ResultMessage(ResultType.Warn, logMessage));
                }
                this.Log().Error(logMessage);
                return;
            }

            var transformFiles = _fileSystem.get_files(installDirectory, "*" + ApplicationParameters.ConfigFileTransformExtension, SearchOption.AllDirectories);

            foreach (var transformFile in transformFiles.or_empty_list_if_null())
            {
                this.Log().Debug(() => "Preparing transform for '{0}'".format_with(transformFile));
                var targetFileName = _fileSystem.get_file_name(transformFile.Replace(ApplicationParameters.ConfigFileTransformExtension, string.Empty));
                // target files must exist, otherwise one is added next to the transform
                var targetFiles = _fileSystem.get_files(installDirectory, targetFileName, SearchOption.AllDirectories);

                var targetFilesTest = targetFiles as IList <string> ?? targetFiles.ToList();
                if (!targetFilesTest.Any())
                {
                    targetFiles = new[] { transformFile.Replace(ApplicationParameters.ConfigFileTransformExtension, string.Empty) };
                    this.Log().Debug(() => "No matching files found for transform {0}.{1} Creating '{2}'".format_with(_fileSystem.get_file_name(transformFile), Environment.NewLine, targetFiles.FirstOrDefault()));
                }

                foreach (var targetFile in targetFilesTest.or_empty_list_if_null())
                {
                    GlobalMutex.enter(
                        () =>
                    {
                        var backupTargetFile = targetFile.Replace(ApplicationParameters.PackagesLocation, ApplicationParameters.PackageBackupLocation);

                        FaultTolerance.try_catch_with_logging_exception(
                            () =>
                        {
                            // if there is a backup, we need to put it back in place
                            // the user has indicated they are using transforms by putting
                            // the transform file into the folder, so we will override
                            // the replacement of the file and instead pull from the last
                            // backup and let the transform to its thing instead.
                            if (_fileSystem.file_exists(backupTargetFile))
                            {
                                this.Log().Debug(() => "Restoring backup configuration file for '{0}'.".format_with(targetFile));
                                _fileSystem.copy_file(backupTargetFile, targetFile, overwriteExisting: true);
                            }
                        },
                            "Error replacing backup config file",
                            throwError: false,
                            logWarningInsteadOfError: true);

                        try
                        {
                            this.Log().Info(() => "Transforming '{0}' with the data from '{1}'".format_with(_fileSystem.get_file_name(targetFile), _fileSystem.get_file_name(transformFile)));

                            using (var transformation = new XmlTransformation(_fileSystem.read_file(transformFile), isTransformAFile: false, logger: null))
                            {
                                using (var document = new XmlTransformableDocument {
                                    PreserveWhitespace = true
                                })
                                {
                                    using (var inputStream = _fileSystem.open_file_readonly(targetFile))
                                    {
                                        document.Load(inputStream);
                                    }

                                    // before applying the XDT transformation, let's make a
                                    // backup of the file that should be transformed, in case
                                    // things don't go correctly
                                    this.Log().Debug(() => "Creating backup configuration file for '{0}'.".format_with(targetFile));
                                    _fileSystem.copy_file(targetFile, backupTargetFile, overwriteExisting: true);

                                    bool succeeded = transformation.Apply(document);
                                    if (succeeded)
                                    {
                                        this.Log().Debug(() => "Transform applied successfully for '{0}'".format_with(targetFile));
                                        using (var memoryStream = new MemoryStream())
                                        {
                                            document.Save(memoryStream);
                                            memoryStream.Seek(0, SeekOrigin.Begin);
                                            using (var fileStream = _fileSystem.create_file(targetFile))
                                            {
                                                fileStream.SetLength(0);
                                                memoryStream.CopyTo(fileStream);
                                            }
                                        }

                                        // need to test that the transformed configuration file is valid
                                        // XML.  We can test this by trying to load it again into an XML document
                                        try
                                        {
                                            this.Log().Debug(() => "Verifying transformed configuration file...");
                                            document.Load(targetFile);
                                            this.Log().Debug(() => "Transformed configuration file verified.");
                                        }
                                        catch (Exception)
                                        {
                                            this.Log().Warn(() => "Transformed configuration file doesn't contain valid XML.  Restoring backup file...");
                                            _fileSystem.copy_file(backupTargetFile, targetFile, overwriteExisting: true);
                                            this.Log().Debug(() => "Backup file restored.");
                                        }
                                    }
                                    else
                                    {
                                        // at this point, there is no need to restore the backup file,
                                        // as the resulting transform hasn't actually been written to disk.
                                        this.Log().Warn(() => "Transform failed for '{0}'".format_with(targetFile));
                                    }
                                }
                            }
                        }
                        catch (Exception)
                        {
                            FaultTolerance.try_catch_with_logging_exception(
                                () =>
                            {
                                // something went wrong with the transformation, so we should restore
                                // the original configuration file from the backup
                                this.Log().Warn(() => "There was a problem transforming configuration file, restoring backup file...");
                                _fileSystem.copy_file(backupTargetFile, targetFile, overwriteExisting: true);
                                this.Log().Debug(() => "Backup file restored.");
                            },
                                "Error restoring backup configuration file.");
                        }
                    }, MUTEX_TIMEOUT);
                }
            }
        }
Esempio n. 2
0
        public XmlType deserialize <XmlType>(string xmlFilePath, int retryCount)
        {
            return(FaultTolerance.retry(retryCount, () => GlobalMutex.enter(
                                            () =>
            {
                this.Log().Trace("Entered mutex to deserialize '{0}'".format_with(xmlFilePath));

                return FaultTolerance.try_catch_with_logging_exception(
                    () =>
                {
                    var xmlSerializer = new XmlSerializer(typeof(XmlType));
                    using (var fileStream = _fileSystem.open_file_readonly(xmlFilePath))
                        using (var fileReader = new StreamReader(fileStream))
                            using (var xmlReader = XmlReader.Create(fileReader))
                            {
                                if (!xmlSerializer.CanDeserialize(xmlReader))
                                {
                                    this.Log().Warn("Cannot deserialize response of type {0}", typeof(XmlType));
                                    return default(XmlType);
                                }

                                try
                                {
                                    return (XmlType)xmlSerializer.Deserialize(xmlReader);
                                }
                                catch (InvalidOperationException ex)
                                {
                                    // Check if its just a malformed document.
                                    if (ex.Message.Contains("There is an error in XML document"))
                                    {
                                        // If so, check for a backup file and try an parse that.
                                        if (_fileSystem.file_exists(xmlFilePath + ".backup"))
                                        {
                                            using (var backupStream = _fileSystem.open_file_readonly(xmlFilePath + ".backup"))
                                                using (var backupReader = new StreamReader(backupStream))
                                                    using (var backupXmlReader = XmlReader.Create(backupReader))
                                                    {
                                                        var validConfig = (XmlType)xmlSerializer.Deserialize(backupXmlReader);

                                                        // If there's no errors and it's valid, go ahead and replace the bad file with the backup.
                                                        if (validConfig != null)
                                                        {
                                                            // Close fileReader so that we can copy the file without it being locked.
                                                            fileReader.Close();
                                                            _fileSystem.copy_file(xmlFilePath + ".backup", xmlFilePath, overwriteExisting: true);
                                                        }

                                                        return validConfig;
                                                    }
                                        }
                                    }

                                    throw;
                                }
                                finally
                                {
                                    foreach (var updateFile in _fileSystem.get_files(_fileSystem.get_directory_name(xmlFilePath), "*.update").or_empty_list_if_null())
                                    {
                                        this.Log().Debug("Removing '{0}'".format_with(updateFile));
                                        FaultTolerance.try_catch_with_logging_exception(
                                            () => _fileSystem.delete_file(updateFile),
                                            errorMessage: "Unable to remove update file",
                                            logDebugInsteadOfError: true,
                                            isSilent: true
                                            );
                                    }
                                }
                            }
                },
                    "Error deserializing response of type {0}".format_with(typeof(XmlType)),
                    throwError: true);
            }, MUTEX_TIMEOUT),
                                        waitDurationMilliseconds: 200,
                                        increaseRetryByMilliseconds: 200));
        }
Esempio n. 3
0
 public static GetChocolatey GetChocolatey()
 {
     return(GlobalMutex.enter(() => set_up(), 10));
 }
Esempio n. 4
0
        public void serialize <XmlType>(XmlType xmlType, string xmlFilePath, bool isSilent)
        {
            _fileSystem.create_directory_if_not_exists(_fileSystem.get_directory_name(xmlFilePath));

            FaultTolerance.retry(3, () => GlobalMutex.enter(
                                     () =>
            {
                this.Log().Trace("Entered mutex to serialize '{0}'".format_with(xmlFilePath));
                FaultTolerance.try_catch_with_logging_exception(
                    () =>
                {
                    var xmlSerializer = new XmlSerializer(typeof(XmlType));

                    this.Log().Trace("Opening memory stream for xml file creation.");
                    using (var memoryStream = new MemoryStream())
                        using (var streamWriter = new StreamWriter(memoryStream, encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: true))
                        {
                            AutoFlush = true
                        }
                               ){
                            xmlSerializer.Serialize(streamWriter, xmlType);
                            streamWriter.Flush();

                            // Grab the hash of both files and compare them.
                            this.Log().Trace("Hashing original file at '{0}'".format_with(xmlFilePath));
                            var originalFileHash  = _hashProvider.hash_file(xmlFilePath);
                            memoryStream.Position = 0;
                            if (!originalFileHash.is_equal_to(_hashProvider.hash_stream(memoryStream)))
                            {
                                this.Log().Trace("The hashes were different.");
                                // If there wasn't a file there in the first place, just write the new one out directly.
                                if (string.IsNullOrEmpty(originalFileHash))
                                {
                                    this.Log().Debug("There was no original file at '{0}'".format_with(xmlFilePath));
                                    memoryStream.Position = 0;
                                    _fileSystem.write_file(xmlFilePath, () => memoryStream);

                                    this.Log().Trace("Closing xml memory stream.");
                                    memoryStream.Close();
                                    streamWriter.Close();

                                    return;
                                }

                                // Otherwise, create an update file, and resiliently move it into place.
                                var tempUpdateFile = xmlFilePath + "." + Process.GetCurrentProcess().Id + ".update";
                                this.Log().Trace("Creating a temp file at '{0}'".format_with(tempUpdateFile));
                                memoryStream.Position = 0;
                                this.Log().Trace("Writing file '{0}'".format_with(tempUpdateFile));
                                _fileSystem.write_file(tempUpdateFile, () => memoryStream);

                                memoryStream.Close();
                                streamWriter.Close();

                                this.Log().Trace("Replacing file '{0}' with '{1}'.".format_with(xmlFilePath, tempUpdateFile));
                                _fileSystem.replace_file(tempUpdateFile, xmlFilePath, xmlFilePath + ".backup");
                            }
                        }
                },
                    errorMessage: "Error serializing type {0}".format_with(typeof(XmlType)),
                    throwError: true,
                    isSilent: isSilent);
            }, MUTEX_TIMEOUT),
                                 waitDurationMilliseconds: 200,
                                 increaseRetryByMilliseconds: 200);
        }
Esempio n. 5
0
 public static GetChocolatey GetChocolatey(bool initializeLogging)
 {
     return(GlobalMutex.enter(() => set_up(initializeLogging), 10));
 }