Skip to content

Commit

Permalink
(GH-357) Add Export Command
Browse files Browse the repository at this point in the history
This will allow the creation of a packages.config file of all the
currently installed packages on the machine.  Usage of this command
will be:

choco export -o c:/temp/packages.config --include-version-numbers

This command is particularly useful when re-building a machine.  i.e.
First export all packages currently installed on machine, and then
replay this packages.config via choco install packages.config on new
machine.
  • Loading branch information
gep13 committed May 28, 2020
1 parent 8050215 commit a0df909
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/chocolatey/chocolatey.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
<Link>Properties\SolutionVersion.cs</Link>
</Compile>
<Compile Include="AssemblyExtensions.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyExportCommand.cs" />
<Compile Include="infrastructure.app\commands\ChocolateyInfoCommand.cs" />
<Compile Include="infrastructure\cryptography\DefaultEncryptionUtility.cs" />
<Compile Include="infrastructure\adapters\IEncryptionUtility.cs" />
Expand Down
185 changes: 185 additions & 0 deletions src/chocolatey/infrastructure.app/commands/ChocolateyExportCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright © 2017 - 2018 Chocolatey Software, Inc
// Copyright © 2011 - 2017 RealDimensions Software, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace chocolatey.infrastructure.app.commands
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using attributes;
using commandline;
using configuration;
using filesystem;
using infrastructure.commands;
using logging;
using services;
using tolerance;

[CommandFor("export", "exports list of currently installed packages")]
public class ChocolateyExportCommand : ICommand
{
private readonly INugetService _nugetService;
private readonly IFileSystem _fileSystem;

public ChocolateyExportCommand(INugetService nugetService, IFileSystem fileSystem)
{
_nugetService = nugetService;
_fileSystem = fileSystem;
}

public void configure_argument_parser(OptionSet optionSet, ChocolateyConfiguration configuration)
{
optionSet
.Add("o=|output-file-path=",
"Output File Path - the path to where the list of currently installed packages should be saved. Defaults to packages.config.",
option => configuration.ExportCommand.OutputFilePath = option.remove_surrounding_quotes())
.Add("include-version-numbers",
"Include Version Numbers - controls whether or not version numbers for each package appear in generated file. Defaults to false.",
option => configuration.ExportCommand.IncludeVersionNumbers = option != null)
;
}

public void handle_additional_argument_parsing(IList<string> unparsedArguments, ChocolateyConfiguration configuration)
{
if (unparsedArguments.Count > 0)
{
throw new ApplicationException("Please see the help menu for the export command");
}
}

public void handle_validation(ChocolateyConfiguration configuration)
{
// Currently, no additional validation is required.
}

public void help_message(ChocolateyConfiguration configuration)
{
this.Log().Info(ChocolateyLoggers.Important, "Export Command");
this.Log().Info(@"
Export all currently installed packages to a file.
This is especially helpful when re-building a machine that was created
using Chocolatey. Export all packages to a file, and then re-install
those packages onto new machine using `choco install packages.config`.
");
"chocolatey".Log().Info(ChocolateyLoggers.Important, "Usage");
"chocolatey".Log().Info(@"
choco export [<options/switches>]
");

"chocolatey".Log().Info(ChocolateyLoggers.Important, "Examples");
"chocolatey".Log().Info(@"
choco export
choco export --include-version-numbers
choco export --output-file-path=""c:\temp\packages.config""
choco export --output-file-path=""c:\temp\packages.config"" --include-version-numbers
NOTE: See scripting in the command reference (`choco -?`) for how to
write proper scripts and integrations.
");

"chocolatey".Log().Info(ChocolateyLoggers.Important, "Exit Codes");
"chocolatey".Log().Info(@"
Exit codes that normally result from running this command.
Normal:
- 0: operation was successful, no issues detected
- -1 or 1: an error has occurred
If you find other exit codes that we have not yet documented, please
file a ticket so we can document it at
https://github.com/chocolatey/choco/issues/new/choose.
");

"chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches");
}

public bool may_require_admin_access()
{
return false;
}

public void noop(ChocolateyConfiguration configuration)
{
this.Log().Info("Export would have been with options: {0} Output File Path={1}{0} Include Version Numbers:{2}".format_with(Environment.NewLine, configuration.ExportCommand.OutputFilePath, configuration.ExportCommand.IncludeVersionNumbers));
}

public void run(ChocolateyConfiguration configuration)
{
var packageResults = _nugetService.get_all_installed_packages(configuration);
var settings = new XmlWriterSettings { Indent = true, Encoding = new UTF8Encoding(false) };

FaultTolerance.try_catch_with_logging_exception(
() =>
{
using (var stringWriter = new StringWriter())
{
using (var xw = XmlWriter.Create(stringWriter, settings))
{
xw.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\"");
xw.WriteStartElement("packages");

foreach (var packageResult in packageResults)
{
xw.WriteStartElement("package");
xw.WriteAttributeString("id", packageResult.Package.Id);

if (configuration.ExportCommand.IncludeVersionNumbers)
{
xw.WriteAttributeString("version", packageResult.Package.Version.ToString());
}

xw.WriteEndElement();
}

xw.WriteEndElement();
xw.Flush();
}

var fileExists = _fileSystem.file_exists(configuration.ExportCommand.OutputFilePath);

// If the file doesn't already exist, just write the new one out directly
if (!fileExists)
{
_fileSystem.write_file(
configuration.ExportCommand.OutputFilePath,
stringWriter.GetStringBuilder().ToString(),
new UTF8Encoding(false));

return;
}


// Otherwise, create an update file, and resiliently move it into place.
var tempUpdateFile = configuration.ExportCommand.OutputFilePath + "." + Process.GetCurrentProcess().Id + ".update";
_fileSystem.write_file(tempUpdateFile,
stringWriter.GetStringBuilder().ToString(),
new UTF8Encoding(false));

_fileSystem.replace_file(tempUpdateFile, configuration.ExportCommand.OutputFilePath, configuration.ExportCommand.OutputFilePath + ".backup");
}
},
errorMessage: "Error exporting currently installed packages",
throwError: true
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public ChocolateyConfiguration()
PinCommand = new PinCommandConfiguration();
OutdatedCommand = new OutdatedCommandConfiguration();
Proxy = new ProxyConfiguration();
ExportCommand = new ExportCommandConfiguration();
#if DEBUG
AllowUnofficialBuild = true;
#endif
Expand Down Expand Up @@ -334,6 +335,8 @@ private void append_output(StringBuilder propertyValues, string append)
/// </remarks>
public OutdatedCommandConfiguration OutdatedCommand { get; set; }

public ExportCommandConfiguration ExportCommand { get; set; }

/// <summary>
/// Configuration related specifically to proxies.
/// </summary>
Expand Down Expand Up @@ -545,4 +548,17 @@ public sealed class ProxyConfiguration
public string BypassList { get; set; }
public bool BypassOnLocal { get; set; }
}

[Serializable]
public sealed class ExportCommandConfiguration
{
public ExportCommandConfiguration()
{
OutputFilePath = "packages.config";
}

public bool IncludeVersionNumbers { get; set; }

public string OutputFilePath { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ public void RegisterComponents(Container container)
new ChocolateyApiKeyCommand(container.GetInstance<IChocolateyConfigSettingsService>()),
new ChocolateyUnpackSelfCommand(container.GetInstance<IFileSystem>()),
new ChocolateyVersionCommand(container.GetInstance<IChocolateyPackageService>()),
new ChocolateyUpdateCommand(container.GetInstance<IChocolateyPackageService>())
new ChocolateyUpdateCommand(container.GetInstance<IChocolateyPackageService>()),
new ChocolateyExportCommand(container.GetInstance<INugetService>(), container.GetInstance<IFileSystem>())
};
return list.AsReadOnly();
}, Lifestyle.Singleton);
Expand Down

0 comments on commit a0df909

Please sign in to comment.