mirror of
https://github.com/cemu-project/vcpkg.git
synced 2025-02-23 02:57:09 +01:00
Merge pull request #6891 from seanyen/vcpkg_nuget
[feature] add `vcpkg export --x-chocolatey` support
This commit is contained in:
commit
0791dbfc6b
19
toolsrc/include/vcpkg/export.chocolatey.h
Normal file
19
toolsrc/include/vcpkg/export.chocolatey.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <vcpkg/dependencies.h>
|
||||
#include <vcpkg/vcpkgpaths.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace vcpkg::Export::Chocolatey
|
||||
{
|
||||
struct Options
|
||||
{
|
||||
Optional<std::string> maybe_maintainer;
|
||||
Optional<std::string> maybe_version_suffix;
|
||||
};
|
||||
|
||||
void do_export(const std::vector<Dependencies::ExportPlanAction>& export_plan,
|
||||
const VcpkgPaths& paths,
|
||||
const Options& chocolatey_options);
|
||||
}
|
230
toolsrc/src/vcpkg/export.chocolatey.cpp
Normal file
230
toolsrc/src/vcpkg/export.chocolatey.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/system.print.h>
|
||||
#include <vcpkg/base/system.process.h>
|
||||
#include <vcpkg/commands.h>
|
||||
#include <vcpkg/export.chocolatey.h>
|
||||
#include <vcpkg/export.h>
|
||||
#include <vcpkg/install.h>
|
||||
|
||||
namespace vcpkg::Export::Chocolatey
|
||||
{
|
||||
using Dependencies::ExportPlanAction;
|
||||
using Dependencies::ExportPlanType;
|
||||
using Install::InstallDir;
|
||||
|
||||
static std::string create_nuspec_dependencies(const BinaryParagraph& binary_paragraph,
|
||||
const std::map<std::string, std::string>& packages_version)
|
||||
{
|
||||
static constexpr auto CONTENT_TEMPLATE = R"(<dependency id="@PACKAGE_ID@" version="[@PACKAGE_VERSION@]" />)";
|
||||
|
||||
std::string nuspec_dependencies;
|
||||
for (const std::string& depend : binary_paragraph.depends)
|
||||
{
|
||||
auto found = packages_version.find(depend);
|
||||
if (found == packages_version.end())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find desired dependency version.");
|
||||
}
|
||||
std::string nuspec_dependency = Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_ID@", depend);
|
||||
nuspec_dependency = Strings::replace_all(std::move(nuspec_dependency), "@PACKAGE_VERSION@", found->second);
|
||||
nuspec_dependencies += nuspec_dependency;
|
||||
}
|
||||
return nuspec_dependencies;
|
||||
}
|
||||
|
||||
static std::string create_nuspec_file_contents(const std::string& exported_root_dir,
|
||||
const BinaryParagraph& binary_paragraph,
|
||||
const std::map<std::string, std::string>& packages_version,
|
||||
const Options& chocolatey_options)
|
||||
{
|
||||
static constexpr auto CONTENT_TEMPLATE = R"(<?xml version="1.0" encoding="utf-8"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
|
||||
<metadata>
|
||||
<id>@PACKAGE_ID@</id>
|
||||
<version>@PACKAGE_VERSION@</version>
|
||||
<authors>@PACKAGE_MAINTAINER@</authors>
|
||||
<description><![CDATA[
|
||||
@PACKAGE_DESCRIPTION@
|
||||
]]></description>
|
||||
<dependencies>
|
||||
@PACKAGE_DEPENDENCIES@
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="@EXPORTED_ROOT_DIR@\installed\**" target="installed" />
|
||||
<file src="@EXPORTED_ROOT_DIR@\tools\**" target="tools" />
|
||||
</files>
|
||||
</package>
|
||||
)";
|
||||
auto package_version = packages_version.find(binary_paragraph.spec.name());
|
||||
if (package_version == packages_version.end())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Cannot find desired package version.");
|
||||
}
|
||||
std::string nuspec_file_content =
|
||||
Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_ID@", binary_paragraph.spec.name());
|
||||
nuspec_file_content =
|
||||
Strings::replace_all(std::move(nuspec_file_content), "@PACKAGE_VERSION@", package_version->second);
|
||||
nuspec_file_content = Strings::replace_all(
|
||||
std::move(nuspec_file_content), "@PACKAGE_MAINTAINER@", chocolatey_options.maybe_maintainer.value_or(""));
|
||||
nuspec_file_content =
|
||||
Strings::replace_all(std::move(nuspec_file_content), "@PACKAGE_DESCRIPTION@", binary_paragraph.description);
|
||||
nuspec_file_content =
|
||||
Strings::replace_all(std::move(nuspec_file_content), "@EXPORTED_ROOT_DIR@", exported_root_dir);
|
||||
nuspec_file_content = Strings::replace_all(std::move(nuspec_file_content),
|
||||
"@PACKAGE_DEPENDENCIES@",
|
||||
create_nuspec_dependencies(binary_paragraph, packages_version));
|
||||
return nuspec_file_content;
|
||||
}
|
||||
|
||||
static std::string create_chocolatey_install_contents()
|
||||
{
|
||||
static constexpr auto CONTENT_TEMPLATE = R"###(
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$packageName= $env:ChocolateyPackageName
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
$rootDir = "$(Split-Path -parent $toolsDir)"
|
||||
$installedDir = Join-Path $rootDir 'installed'
|
||||
|
||||
$whereToInstall = (pwd).path
|
||||
$whereToInstallCache = Join-Path $rootDir 'install.txt'
|
||||
Set-Content -Path $whereToInstallCache -Value $whereToInstall
|
||||
Copy-Item $installedDir -destination $whereToInstall -recurse -force
|
||||
)###";
|
||||
return CONTENT_TEMPLATE;
|
||||
}
|
||||
|
||||
static std::string create_chocolatey_uninstall_contents(const BinaryParagraph& binary_paragraph)
|
||||
{
|
||||
static constexpr auto CONTENT_TEMPLATE = R"###(
|
||||
$ErrorActionPreference = 'Stop';
|
||||
|
||||
$packageName= $env:ChocolateyPackageName
|
||||
$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
|
||||
$rootDir = "$(Split-Path -parent $toolsDir)"
|
||||
$listFile = Join-Path $rootDir 'installed\vcpkg\info\@PACKAGE_FULLSTEM@.list'
|
||||
|
||||
$whereToInstall = $null
|
||||
$whereToInstallCache = Join-Path $rootDir 'install.txt'
|
||||
Get-Content $whereToInstallCache | Foreach-Object {
|
||||
$whereToInstall = $_
|
||||
}
|
||||
|
||||
$installedDir = Join-Path $whereToInstall 'installed'
|
||||
Get-Content $listFile | Foreach-Object {
|
||||
$fileToRemove = Join-Path $installedDir $_
|
||||
if (Test-Path $fileToRemove -PathType Leaf) {
|
||||
Remove-Item $fileToRemove
|
||||
}
|
||||
}
|
||||
|
||||
Get-Content $listFile | Foreach-Object {
|
||||
$fileToRemove = Join-Path $installedDir $_
|
||||
if (Test-Path $fileToRemove -PathType Container) {
|
||||
$folderToDelete = Join-Path $fileToRemove *
|
||||
if (-Not (Test-Path $folderToDelete))
|
||||
{
|
||||
Remove-Item $fileToRemove
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$listFileToRemove = Join-Path $whereToInstall 'installed\vcpkg\info\@PACKAGE_FULLSTEM@.list'
|
||||
Remove-Item $listFileToRemove
|
||||
|
||||
if (Test-Path $installedDir)
|
||||
{
|
||||
while (
|
||||
$empties = Get-ChildItem $installedDir -recurse -Directory | Where-Object {
|
||||
$_.GetFiles().Count -eq 0 -and $_.GetDirectories().Count -eq 0
|
||||
}
|
||||
) { $empties | Remove-Item }
|
||||
}
|
||||
)###";
|
||||
std::string chocolatey_uninstall_content =
|
||||
Strings::replace_all(CONTENT_TEMPLATE, "@PACKAGE_FULLSTEM@", binary_paragraph.fullstem());
|
||||
return chocolatey_uninstall_content;
|
||||
}
|
||||
|
||||
void do_export(const std::vector<ExportPlanAction>& export_plan,
|
||||
const VcpkgPaths& paths,
|
||||
const Options& chocolatey_options)
|
||||
{
|
||||
Checks::check_exit(
|
||||
VCPKG_LINE_INFO, chocolatey_options.maybe_maintainer.has_value(), "--x-maintainer option is required.");
|
||||
|
||||
Files::Filesystem& fs = paths.get_filesystem();
|
||||
const fs::path vcpkg_root_path = paths.root;
|
||||
const fs::path raw_exported_dir_path = vcpkg_root_path / "chocolatey";
|
||||
const fs::path exported_dir_path = vcpkg_root_path / "chocolatey_exports";
|
||||
const fs::path& nuget_exe = paths.get_tool_exe(Tools::NUGET);
|
||||
|
||||
std::error_code ec;
|
||||
fs.remove_all(raw_exported_dir_path, VCPKG_LINE_INFO);
|
||||
fs.create_directory(raw_exported_dir_path, ec);
|
||||
fs.remove_all(exported_dir_path, VCPKG_LINE_INFO);
|
||||
fs.create_directory(exported_dir_path, ec);
|
||||
|
||||
// execute the plan
|
||||
std::map<std::string, std::string> packages_version;
|
||||
for (const ExportPlanAction& action : export_plan)
|
||||
{
|
||||
if (action.plan_type != ExportPlanType::ALREADY_BUILT)
|
||||
{
|
||||
Checks::unreachable(VCPKG_LINE_INFO);
|
||||
}
|
||||
|
||||
const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO);
|
||||
auto norm_version = binary_paragraph.version;
|
||||
|
||||
// normalize the version string to be separated by dots to be compliant with Nusepc.
|
||||
norm_version = Strings::replace_all(std::move(norm_version), "-", ".");
|
||||
norm_version = Strings::replace_all(std::move(norm_version), "_", ".");
|
||||
norm_version = norm_version + chocolatey_options.maybe_version_suffix.value_or("");
|
||||
packages_version.insert(std::make_pair(binary_paragraph.spec.name(), norm_version));
|
||||
}
|
||||
|
||||
for (const ExportPlanAction& action : export_plan)
|
||||
{
|
||||
const std::string display_name = action.spec.to_string();
|
||||
System::print2("Exporting package ", display_name, "...\n");
|
||||
|
||||
const fs::path per_package_dir_path = raw_exported_dir_path / action.spec.name();
|
||||
|
||||
const BinaryParagraph& binary_paragraph = action.core_paragraph().value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
const InstallDir dirs = InstallDir::from_destination_root(
|
||||
per_package_dir_path / "installed",
|
||||
action.spec.triplet().to_string(),
|
||||
per_package_dir_path / "installed" / "vcpkg" / "info" / (binary_paragraph.fullstem() + ".list"));
|
||||
|
||||
Install::install_files_and_write_listfile(paths.get_filesystem(), paths.package_dir(action.spec), dirs);
|
||||
|
||||
const std::string nuspec_file_content = create_nuspec_file_contents(
|
||||
per_package_dir_path.string(), binary_paragraph, packages_version, chocolatey_options);
|
||||
const fs::path nuspec_file_path =
|
||||
per_package_dir_path / Strings::concat(binary_paragraph.spec.name(), ".nuspec");
|
||||
fs.write_contents(nuspec_file_path, nuspec_file_content, VCPKG_LINE_INFO);
|
||||
|
||||
fs.create_directory(per_package_dir_path / "tools", ec);
|
||||
|
||||
const std::string chocolatey_install_content = create_chocolatey_install_contents();
|
||||
const fs::path chocolatey_install_file_path = per_package_dir_path / "tools" / "chocolateyInstall.ps1";
|
||||
fs.write_contents(chocolatey_install_file_path, chocolatey_install_content, VCPKG_LINE_INFO);
|
||||
|
||||
const std::string chocolatey_uninstall_content = create_chocolatey_uninstall_contents(binary_paragraph);
|
||||
const fs::path chocolatey_uninstall_file_path = per_package_dir_path / "tools" / "chocolateyUninstall.ps1";
|
||||
fs.write_contents(chocolatey_uninstall_file_path, chocolatey_uninstall_content, VCPKG_LINE_INFO);
|
||||
|
||||
const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes > nul)",
|
||||
nuget_exe.u8string(),
|
||||
exported_dir_path.u8string(),
|
||||
nuspec_file_path.u8string());
|
||||
|
||||
const int exit_code = System::cmd_execute_clean(cmd_line);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: NuGet package creation failed");
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include <vcpkg/dependencies.h>
|
||||
#include <vcpkg/export.h>
|
||||
#include <vcpkg/export.ifw.h>
|
||||
#include <vcpkg/export.chocolatey.h>
|
||||
#include <vcpkg/help.h>
|
||||
#include <vcpkg/input.h>
|
||||
#include <vcpkg/install.h>
|
||||
@ -257,6 +258,7 @@ namespace vcpkg::Export
|
||||
bool ifw = false;
|
||||
bool zip = false;
|
||||
bool seven_zip = false;
|
||||
bool chocolatey = false;
|
||||
|
||||
Optional<std::string> maybe_output;
|
||||
|
||||
@ -264,6 +266,7 @@ namespace vcpkg::Export
|
||||
Optional<std::string> maybe_nuget_version;
|
||||
|
||||
IFW::Options ifw_options;
|
||||
Chocolatey::Options chocolatey_options;
|
||||
std::vector<PackageSpec> specs;
|
||||
};
|
||||
|
||||
@ -281,17 +284,21 @@ namespace vcpkg::Export
|
||||
static constexpr StringLiteral OPTION_IFW_REPOSITORY_DIR_PATH = "--ifw-repository-directory-path";
|
||||
static constexpr StringLiteral OPTION_IFW_CONFIG_FILE_PATH = "--ifw-configuration-file-path";
|
||||
static constexpr StringLiteral OPTION_IFW_INSTALLER_FILE_PATH = "--ifw-installer-file-path";
|
||||
static constexpr StringLiteral OPTION_CHOCOLATEY = "--x-chocolatey";
|
||||
static constexpr StringLiteral OPTION_CHOCOLATEY_MAINTAINER = "--x-maintainer";
|
||||
static constexpr StringLiteral OPTION_CHOCOLATEY_VERSION_SUFFIX = "--x-version-suffix";
|
||||
|
||||
static constexpr std::array<CommandSwitch, 6> EXPORT_SWITCHES = {{
|
||||
static constexpr std::array<CommandSwitch, 7> EXPORT_SWITCHES = {{
|
||||
{OPTION_DRY_RUN, "Do not actually export"},
|
||||
{OPTION_RAW, "Export to an uncompressed directory"},
|
||||
{OPTION_NUGET, "Export a NuGet package"},
|
||||
{OPTION_IFW, "Export to an IFW-based installer"},
|
||||
{OPTION_ZIP, "Export to a zip file"},
|
||||
{OPTION_SEVEN_ZIP, "Export to a 7zip (.7z) file"},
|
||||
{OPTION_CHOCOLATEY, "Export a Chocolatey package (experimental feature)"},
|
||||
}};
|
||||
|
||||
static constexpr std::array<CommandSetting, 8> EXPORT_SETTINGS = {{
|
||||
static constexpr std::array<CommandSetting, 10> EXPORT_SETTINGS = {{
|
||||
{OPTION_OUTPUT, "Specify the output name (used to construct filename)"},
|
||||
{OPTION_NUGET_ID, "Specify the id for the exported NuGet package (overrides --output)"},
|
||||
{OPTION_NUGET_VERSION, "Specify the version for the exported NuGet package"},
|
||||
@ -300,6 +307,8 @@ namespace vcpkg::Export
|
||||
{OPTION_IFW_REPOSITORY_DIR_PATH, "Specify the directory path for the exported repository"},
|
||||
{OPTION_IFW_CONFIG_FILE_PATH, "Specify the temporary file path for the installer configuration"},
|
||||
{OPTION_IFW_INSTALLER_FILE_PATH, "Specify the file path for the exported installer"},
|
||||
{OPTION_CHOCOLATEY_MAINTAINER, "Specify the maintainer for the exported Chocolatey package (experimental feature)"},
|
||||
{OPTION_CHOCOLATEY_VERSION_SUFFIX, "Specify the version suffix to add for the exported Chocolatey package (experimental feature)"},
|
||||
}};
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
@ -327,13 +336,14 @@ namespace vcpkg::Export
|
||||
ret.ifw = options.switches.find(OPTION_IFW) != options.switches.cend();
|
||||
ret.zip = options.switches.find(OPTION_ZIP) != options.switches.cend();
|
||||
ret.seven_zip = options.switches.find(OPTION_SEVEN_ZIP) != options.switches.cend();
|
||||
ret.chocolatey = options.switches.find(OPTION_CHOCOLATEY) != options.switches.cend();
|
||||
|
||||
ret.maybe_output = maybe_lookup(options.settings, OPTION_OUTPUT);
|
||||
|
||||
if (!ret.raw && !ret.nuget && !ret.ifw && !ret.zip && !ret.seven_zip && !ret.dry_run)
|
||||
if (!ret.raw && !ret.nuget && !ret.ifw && !ret.zip && !ret.seven_zip && !ret.dry_run && !ret.chocolatey)
|
||||
{
|
||||
System::print2(System::Color::error,
|
||||
"Must provide at least one export type: --raw --nuget --ifw --zip --7zip\n");
|
||||
"Must provide at least one export type: --raw --nuget --ifw --zip --7zip --chocolatey\n");
|
||||
System::print2(COMMAND_STRUCTURE.example_text);
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
@ -384,6 +394,14 @@ namespace vcpkg::Export
|
||||
{OPTION_IFW_CONFIG_FILE_PATH, ret.ifw_options.maybe_config_file_path},
|
||||
{OPTION_IFW_INSTALLER_FILE_PATH, ret.ifw_options.maybe_installer_file_path},
|
||||
});
|
||||
|
||||
options_implies(OPTION_CHOCOLATEY,
|
||||
ret.chocolatey,
|
||||
{
|
||||
{OPTION_CHOCOLATEY_MAINTAINER, ret.chocolatey_options.maybe_maintainer},
|
||||
{OPTION_CHOCOLATEY_VERSION_SUFFIX, ret.chocolatey_options.maybe_version_suffix},
|
||||
});
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1900
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@ -560,6 +578,11 @@ With a project open, go to Tools->NuGet Package Manager->Package Manager Console
|
||||
print_next_step_info("@RootDir@/src/vcpkg");
|
||||
}
|
||||
|
||||
if (opts.chocolatey)
|
||||
{
|
||||
Chocolatey::do_export(export_plan, paths, opts.chocolatey_options);
|
||||
}
|
||||
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
@ -246,6 +246,7 @@
|
||||
<ClCompile Include="..\src\vcpkg\commands.xvsinstances.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\dependencies.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\export.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\export.chocolatey.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\globalstate.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\help.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\input.cpp" />
|
||||
|
@ -96,6 +96,9 @@
|
||||
<ClCompile Include="..\src\vcpkg\export.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\vcpkg\export.chocolatey.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\vcpkg\globalstate.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
|
Loading…
x
Reference in New Issue
Block a user