Skip to content

Commit

Permalink
Use 7zr to unpack 7zip (#1477)
Browse files Browse the repository at this point in the history
* first take, use 7zr to unpack 7za instead of cmake, remove cmake dance

* fix merge issues

* fix unit tests

* update vcpkg-scripts-sha.txt

* update vcpkg-scripts-sha.txt

* fix self extracting

* use 7zr for zip formats as well

* undo zip

* use cmake for tar since 7zr needs to unpack twice for .tar.gz

* undo changes to tar

* use cmake for tar decompression

* update vcpkg-scripts-sha

* Make the upgrade test always use the current vcpkgTools.xml.

* use 7zr for zip

* 7zr doesn't work on zip formats

---------

Co-authored-by: Javier Matos <[email protected]>
Co-authored-by: Billy Robert O'Neal III <[email protected]>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent e2f895e commit a47c79f
Show file tree
Hide file tree
Showing 7 changed files with 18 additions and 73 deletions.
3 changes: 3 additions & 0 deletions azure-pipelines/end-to-end-tests-dir/upgrade.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ try
{
$env:VCPKG_ROOT = "$TestingRoot/temp-repo"
git -C "$TestingRoot/temp-repo" switch -d e1934f4a2a0c58bb75099d89ed980832379907fa # vcpkg-cmake @ 2022-12-22
Copy-Item "$VcpkgRoot/scripts/vcpkgTools.xml" "$TestingRoot/temp-repo/scripts/vcpkgTools.xml" -Force
$output = Run-VcpkgAndCaptureOutput install vcpkg-cmake
Throw-IfFailed
if (-Not ($output -match 'vcpkg-cmake:[^ ]+@2022-12-22'))
{
throw 'Unexpected vcpkg-cmake install'
}

git -C "$TestingRoot/temp-repo" checkout -- 'scripts/vcpkgTools.xml'
git -C "$TestingRoot/temp-repo" switch -d f6a5d4e8eb7476b8d7fc12a56dff300c1c986131 # vcpkg-cmake @ 2023-05-04
Copy-Item "$VcpkgRoot/scripts/vcpkgTools.xml" "$TestingRoot/temp-repo/scripts/vcpkgTools.xml" -Force
$output = Run-VcpkgAndCaptureOutput upgrade
Throw-IfNotFailed
if (-Not ($output -match 'If you are sure you want to rebuild the above packages, run this command with the --no-dry-run option.'))
Expand Down
8 changes: 1 addition & 7 deletions include/vcpkg/archives.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace vcpkg
Unknown,
Tar,
Zip,
SevenZip,
Nupkg,
Msi,
Exe
Expand Down Expand Up @@ -48,13 +49,6 @@ namespace vcpkg
#ifdef _WIN32
// Extract the 7z archive part of a self extracting 7z installer
void win32_extract_self_extracting_7z(const Filesystem& fs, const Path& archive, const Path& to_path);
// Extract `archive` to `to_path`, deleting `to_path` first. `archive` must be a zip file.
// This function will use potentially less performant tools that are reliably available on any machine.
void win32_extract_bootstrap_zip(const Filesystem& fs,
const ToolCache& tools,
MessageSink& status_sink,
const Path& archive,
const Path& to_path);
#endif

struct ZipTool
Expand Down
3 changes: 1 addition & 2 deletions include/vcpkg/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace vcpkg
{
static constexpr StringLiteral SEVEN_ZIP = "7zip";
static constexpr StringLiteral SEVEN_ZIP_ALT = "7z";
static constexpr StringLiteral SEVEN_ZIP_R = "7zr";
static constexpr StringLiteral TAR = "tar";
static constexpr StringLiteral MAVEN = "mvn";
static constexpr StringLiteral CMAKE = "cmake";
Expand All @@ -32,8 +33,6 @@ namespace vcpkg
static constexpr StringLiteral IFW_INSTALLER_BASE = "ifw_installerbase";
// This duplicate of CMake should only be used as a fallback to unpack
static constexpr StringLiteral CMAKE_SYSTEM = "cmake_system";
// This duplicate of 7zip uses msiexec to unpack, which is a fallback for Windows 7.
static constexpr StringLiteral SEVEN_ZIP_MSI = "7zip_msi";
static constexpr StringLiteral PYTHON3 = "python3";
static constexpr StringLiteral PYTHON3_WITH_VENV = "python3_with_venv";
}
Expand Down
2 changes: 1 addition & 1 deletion src/vcpkg-test/archives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ TEST_CASE ("Testing guess_extraction_type", "[z-extract]")
REQUIRE(guess_extraction_type(Path("path/to/archive.nupkg")) == ExtractionType::Nupkg);
REQUIRE(guess_extraction_type(Path("/path/to/archive.msi")) == ExtractionType::Msi);
REQUIRE(guess_extraction_type(Path("/path/to/archive.zip")) == ExtractionType::Zip);
REQUIRE(guess_extraction_type(Path("/path/to/archive.7z")) == ExtractionType::Zip);
REQUIRE(guess_extraction_type(Path("/path/to/archive.7z")) == ExtractionType::SevenZip);
REQUIRE(guess_extraction_type(Path("/path/to/archive.gz")) == ExtractionType::Tar);
REQUIRE(guess_extraction_type(Path("/path/to/archive.bz2")) == ExtractionType::Tar);
REQUIRE(guess_extraction_type(Path("/path/to/archive.tgz")) == ExtractionType::Tar);
Expand Down
60 changes: 10 additions & 50 deletions src/vcpkg/archives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ namespace
static bool recursion_limiter_sevenzip = false;
Checks::check_exit(VCPKG_LINE_INFO, !recursion_limiter_sevenzip);
recursion_limiter_sevenzip = true;

const auto maybe_output = flatten(cmd_execute_and_capture_output(Command{seven_zip}
.string_arg("x")
.string_arg(archive)
Expand Down Expand Up @@ -141,8 +142,11 @@ namespace vcpkg
{
return ExtractionType::Msi;
}
else if (Strings::case_insensitive_ascii_equals(ext, ".zip") ||
Strings::case_insensitive_ascii_equals(ext, ".7z"))
else if (Strings::case_insensitive_ascii_equals(ext, ".7z"))
{
return ExtractionType::SevenZip;
}
else if (Strings::case_insensitive_ascii_equals(ext, ".zip"))
{
return ExtractionType::Zip;
}
Expand Down Expand Up @@ -174,8 +178,11 @@ namespace vcpkg
case ExtractionType::Unknown: break;
case ExtractionType::Nupkg: win32_extract_nupkg(tools, status_sink, archive, to_path); break;
case ExtractionType::Msi: win32_extract_msi(archive, to_path); break;
case ExtractionType::SevenZip:
win32_extract_with_seven_zip(tools.get_tool_path(Tools::SEVEN_ZIP_R, status_sink), archive, to_path);
break;
case ExtractionType::Zip:
extract_tar_cmake(tools.get_tool_path(Tools::CMAKE, status_sink), archive, to_path);
win32_extract_with_seven_zip(tools.get_tool_path(Tools::SEVEN_ZIP, status_sink), archive, to_path);
break;
case ExtractionType::Tar:
extract_tar(tools.get_tool_path(Tools::TAR, status_sink), archive, to_path);
Expand Down Expand Up @@ -236,7 +243,6 @@ namespace vcpkg
void win32_extract_self_extracting_7z(const Filesystem& fs, const Path& archive, const Path& to_path)
{
constexpr static const char header_7z[] = "7z\xBC\xAF\x27\x1C";

const Path stem = archive.stem();
const auto subext = stem.extension();
Checks::msg_check_exit(VCPKG_LINE_INFO,
Expand All @@ -254,52 +260,6 @@ namespace vcpkg
contents = contents.substr(pos);
fs.write_contents(to_path, contents, VCPKG_LINE_INFO);
}

// We are trying to bootstrap vcpkg's copy of CMake which comes in a zipped file.
// If this is successful, we'll use the downloaded CMake for most extractions.
// We will also extract a portable 7z (using the bootstrapped CMake) to use when performance is required.
//
// We use the following methods to attempt this bootstrap, in order:
// 1) Search for a System32/tar.exe (available on Windows 10+)
// tar.exe unpacks cmake.zip -> cmake.exe unpacks 7z.7z
// 2) Search for a user installed CMake on PATH and Program Files [(x86)]
// (user) cmake.exe unpacks cmake.zip -> (vcpkg) cmake.exe unpacks 7z.7z
// 3) As a last resource, install 7zip using a MSI installer
// msiexec installs 7zip.msi -> 7zip unpacks cmake.zip -> cmake.exe unpacks 7z.7z
void win32_extract_bootstrap_zip(const Filesystem& fs,
const ToolCache& tools,
MessageSink& status_sink,
const Path& archive,
const Path& to_path)
{
fs.remove_all(to_path, VCPKG_LINE_INFO);
Path to_path_partial = to_path + ".partial." + std::to_string(GetCurrentProcessId());

fs.remove_all(to_path_partial, VCPKG_LINE_INFO);
fs.create_directories(to_path_partial, VCPKG_LINE_INFO);
const auto tar_path = get_system32().value_or_exit(VCPKG_LINE_INFO) / "tar.exe";
if (fs.exists(tar_path, IgnoreErrors{}))
{
// On Windows 10, tar.exe is in the box.
extract_tar(tar_path, archive, to_path_partial);
}
else
{
auto maybe_cmake_tool = find_system_cmake(fs);
if (maybe_cmake_tool)
{
// If the user has a CMake version installed we can use that to unpack.
extract_tar_cmake(maybe_cmake_tool.value_or_exit(VCPKG_LINE_INFO), archive, to_path_partial);
}
else
{
// On Windows <10, we attempt to use msiexec to unpack 7zip.
win32_extract_with_seven_zip(
tools.get_tool_path(Tools::SEVEN_ZIP_MSI, status_sink), archive, to_path_partial);
}
}
fs.rename_with_retry(to_path_partial, to_path, VCPKG_LINE_INFO);
}
#endif

void extract_tar(const Path& tar_tool, const Path& archive, const Path& to_path)
Expand Down
13 changes: 1 addition & 12 deletions src/vcpkg/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,18 +691,7 @@ namespace vcpkg
if (tool_data.is_archive)
{
status_sink.println(Color::none, msgExtractingTool, msg::tool_name = tool_data.name);
#if defined(_WIN32)
if (tool_data.name == "cmake")
{
// We use cmake as the core extractor on Windows, so we need to perform a special dance when
// extracting it.
win32_extract_bootstrap_zip(fs, *this, status_sink, download_path, tool_dir_path);
}
else
#endif // ^^^ _WIN32
{
set_directory_to_archive_contents(fs, *this, status_sink, download_path, tool_dir_path);
}
set_directory_to_archive_contents(fs, *this, status_sink, download_path, tool_dir_path);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion vcpkg-init/vcpkg-scripts-sha.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5c7d3a872dd861817fc812647176d5076085a7eb
9f11f2df35f60fb483e0f11667653974ddb880ee

0 comments on commit a47c79f

Please sign in to comment.