Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ BeforeAll {
'export', 'fetch', 'find', 'format-feature-baseline', 'format-manifest', 'hash', 'help', 'install', 'integrate',
'license-report', 'list', 'new', 'owns', 'portsdiff', 'remove', 'search', 'update', 'upgrade', 'use', 'version',
'x-add-version', 'x-check-support', 'x-init-registry', 'x-package-info', 'x-regenerate', 'x-set-installed',
'x-test-features', 'x-update-baseline', 'x-update-registry', 'x-vsinstances'
'x-test-features', 'x-update-baseline', 'x-update-registry', 'x-vsinstances', 'x-baseline-diff'
)
CommonParameterList = @()
CommandOptionList = @{
Expand Down
12 changes: 12 additions & 0 deletions include/vcpkg/base/message-data.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,10 @@ DECLARE_MESSAGE(BaselineConflict,
"",
"Specifying vcpkg-configuration.default-registry in a manifest file conflicts with built-in "
"baseline.\nPlease remove one of these conflicting settings.")
DECLARE_MESSAGE(BaselineDiffNoChange,
(),
"commit is a git commit here",
"No package that would have been installed was updated between the two commits")
DECLARE_MESSAGE(BaselineGitShowFailed,
(msg::commit_sha),
"",
Expand Down Expand Up @@ -599,6 +603,11 @@ DECLARE_MESSAGE(CmdAddVersionOptOverwriteVersion, (), "", "Overwrites git-tree o
DECLARE_MESSAGE(CmdAddVersionOptSkipFormatChk, (), "", "Skips the formatting check of vcpkg.json files")
DECLARE_MESSAGE(CmdAddVersionOptSkipVersionFormatChk, (), "", "Skips the version format check")
DECLARE_MESSAGE(CmdAddVersionOptVerbose, (), "", "Prints success messages rather than only errors")
DECLARE_MESSAGE(CmdBaselineDiffSynopsis,
(),
"",
"Computes the set of packages installed for different baselines and compares the versions that "
"would be installed")
DECLARE_MESSAGE(CmdBootstrapStandaloneSynopsis, (), "", "Bootstraps a vcpkg root from only a vcpkg binary")
DECLARE_MESSAGE(CmdBuildExternalExample1,
(),
Expand Down Expand Up @@ -1066,6 +1075,7 @@ DECLARE_MESSAGE(DependencyWillFail,
"'cascade' is a keyword and should not be translated",
"Dependency {feature_spec} will not build => cascade")
DECLARE_MESSAGE(DetectCompilerHash, (msg::triplet), "", "Detecting compiler hash for triplet {triplet}...")
DECLARE_MESSAGE(DirectDependencies, (), "", "Direct dependencies")
DECLARE_MESSAGE(DirectoriesRelativeToThePackageDirectoryHere,
(),
"",
Expand Down Expand Up @@ -2180,6 +2190,7 @@ DECLARE_MESSAGE(MissingDependency,
(msg::spec, msg::package_name),
"",
"Package {spec} is installed, but dependency {package_name} is not.")
DECLARE_MESSAGE(MissingManifestFile, (), "", "Could not find manifest file (vcpkg.json file)")
DECLARE_MESSAGE(MissingOption, (msg::option), "", "This command requires --{option}")
DECLARE_MESSAGE(MissingOrInvalidIdentifer, (), "", "missing or invalid identifier")
DECLARE_MESSAGE(MissingPortSuggestPullRequest,
Expand Down Expand Up @@ -2870,6 +2881,7 @@ DECLARE_MESSAGE(ToUpdatePackages,
"To update these packages and all dependencies, run\n{command_name} upgrade'")
DECLARE_MESSAGE(TrailingCommaInArray, (), "", "Trailing comma in array")
DECLARE_MESSAGE(TrailingCommaInObj, (), "", "Trailing comma in an object")
DECLARE_MESSAGE(TransitiveDependencies, (), "", "Transitive dependencies")
DECLARE_MESSAGE(TripletLabel, (), "", "Triplet:")
DECLARE_MESSAGE(TripletFileNotFound, (msg::triplet), "", "Triplet file {triplet}.cmake not found")
DECLARE_MESSAGE(TwoFeatureFlagsSpecified,
Expand Down
14 changes: 14 additions & 0 deletions include/vcpkg/commands.baseline-diff.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <vcpkg/fwd/triplet.h>
#include <vcpkg/fwd/vcpkgcmdarguments.h>
#include <vcpkg/fwd/vcpkgpaths.h>

namespace vcpkg
Comment thread
autoantwort marked this conversation as resolved.
{
extern const CommandMetadata CommandBaselineDiffMetadata;
void command_baseline_diff_and_exit(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
vcpkg::Triplet default_triplet,
vcpkg::Triplet host_triplet);
}
6 changes: 6 additions & 0 deletions locales/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@
"AzcopyFailedToPutBlob": "azcopy failed to upload a file to {url} with exit code {exit_code} and http code {value}.",
"_AzcopyFailedToPutBlob.comment": "azcopy is the name of a program. {value} is an HTTP status code. An example of {exit_code} is 127. An example of {url} is https://github.com/microsoft/vcpkg.",
"BaselineConflict": "Specifying vcpkg-configuration.default-registry in a manifest file conflicts with built-in baseline.\nPlease remove one of these conflicting settings.",
"BaselineDiffNoChange": "No package that would have been installed was updated between the two commits",
"_BaselineDiffNoChange.comment": "commit is a git commit here",
"BaselineGitShowFailed": "while checking out baseline from commit '{commit_sha}', failed to `git show` versions/baseline.json. This may be fixed by fetching commits with `git fetch`.",
"_BaselineGitShowFailed.comment": "An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949.",
"BaselineMissing": "{package_name} is not assigned a version",
Expand Down Expand Up @@ -346,6 +348,7 @@
"CmdAddVersionOptSkipVersionFormatChk": "Skips the version format check",
"CmdAddVersionOptVerbose": "Prints success messages rather than only errors",
"CmdAddVersionSynopsis": "Adds a version to the version database",
"CmdBaselineDiffSynopsis": "Computes the set of packages installed for different baselines and compares the versions that would be installed",
"CmdBootstrapStandaloneSynopsis": "Bootstraps a vcpkg root from only a vcpkg binary",
"CmdBuildExample1": "vcpkg build <port spec>",
"_CmdBuildExample1.comment": "This is a command line, only the <>s part should be localized",
Expand Down Expand Up @@ -613,6 +616,7 @@
"_DependencyWillFail.comment": "'cascade' is a keyword and should not be translated An example of {feature_spec} is zlib[featurea,featureb].",
"DetectCompilerHash": "Detecting compiler hash for triplet {triplet}...",
"_DetectCompilerHash.comment": "An example of {triplet} is x64-windows.",
"DirectDependencies": "Direct dependencies",
"DirectoriesRelativeToThePackageDirectoryHere": "the directories are relative to ${{CURRENT_PACKAGES_DIR}} here",
"DllsRelativeToThePackageDirectoryHere": "the DLLs are relative to ${{CURRENT_PACKAGES_DIR}} here",
"DocumentedFieldsSuggestUpdate": "If these are documented fields that should be recognized try updating the vcpkg tool.",
Expand Down Expand Up @@ -1183,6 +1187,7 @@
"MissingClosingParen": "missing closing )",
"MissingDependency": "Package {spec} is installed, but dependency {package_name} is not.",
"_MissingDependency.comment": "An example of {spec} is zlib:x64-windows. An example of {package_name} is zlib.",
"MissingManifestFile": "Could not find manifest file (vcpkg.json file)",
"MissingOption": "This command requires --{option}",
"_MissingOption.comment": "An example of {option} is editable.",
"MissingOrInvalidIdentifer": "missing or invalid identifier",
Expand Down Expand Up @@ -1492,6 +1497,7 @@
"_TotalInstallTimeSuccess.comment": "An example of {elapsed} is 3.532 min.",
"TrailingCommaInArray": "Trailing comma in array",
"TrailingCommaInObj": "Trailing comma in an object",
"TransitiveDependencies": "Transitive dependencies",
"TripletFileNotFound": "Triplet file {triplet}.cmake not found",
"_TripletFileNotFound.comment": "An example of {triplet} is x64-windows.",
"TripletLabel": "Triplet:",
Expand Down
184 changes: 184 additions & 0 deletions src/vcpkg/commands.baseline-diff.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#include <vcpkg/base/fwd/message_sinks.h>

#include <vcpkg/base/contractual-constants.h>
#include <vcpkg/base/files.h>
#include <vcpkg/base/messages.h>
#include <vcpkg/base/parse.h>
#include <vcpkg/base/path.h>
#include <vcpkg/base/strings.h>
#include <vcpkg/base/util.h>

#include <vcpkg/binarycaching.h>
#include <vcpkg/cmakevars.h>
#include <vcpkg/commands.baseline-diff.h>
#include <vcpkg/commands.install.h>
#include <vcpkg/configuration.h>
#include <vcpkg/dependencies.h>
#include <vcpkg/installeddatabase.h>
#include <vcpkg/installedpaths.h>
#include <vcpkg/paragraphs.h>
#include <vcpkg/portfileprovider.h>
#include <vcpkg/vcpkgcmdarguments.h>
#include <vcpkg/vcpkgpaths.h>

#include <map>
#include <memory>
#include <string>
#include <vector>

using namespace vcpkg;

namespace
{
constexpr CommandSwitch switches[] = {
{SwitchXNoDefaultFeatures, msgHelpTxtOptManifestNoDefault},
};

static constexpr CommandMultiSetting multisettings[] = {
{SwitchXFeature, msgHelpTxtOptManifestFeature},
};

bool print_lines(const msg::MessageT<>& header, std::vector<std::string>&& lines)
{
if (lines.empty())
{
return false;
}

Util::sort_unique_erase(lines);
msg::print(msg::format(header).append_raw(":\n"));
for (const auto& line : lines)
{
msg::write_unlocalized_text(Color::none, line);
msg::write_unlocalized_text(Color::none, "\n");
}
msg::write_unlocalized_text(Color::none, "\n");
return true;
}

void check_for_valid_sha(StringView sha)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this use check_commit_exists (from git.h) instead?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we can't do that in the general case because this kinda just blindly overwrites the baseline with a SHA and we don't necessarily have a git repo present for that.

However that makes this kinda broken because filesystem registries' baselines are not SHAs. We should only be checking that the input is a SHA when we know that registry has that constraint.

{
if (sha.size() < 7 || !Util::all_of(sha, ParserBase::is_hex_digit_lower))
{
Checks::msg_exit_with_error(VCPKG_LINE_INFO, msgInvalidCommitId, msg::commit_sha = sha);
}
Comment thread
autoantwort marked this conversation as resolved.
}
Comment thread
autoantwort marked this conversation as resolved.

} // unnamed namespace

namespace vcpkg
{
constexpr CommandMetadata CommandBaselineDiffMetadata{
"x-baseline-diff",
msgCmdBaselineDiffSynopsis,
{"vcpkg x-baseline-diff <old_commit_sha> <newer_commit_sha>",
"vcpkg x-baseline-diff $(git rev-parse 2026.02.27) $(git rev-parse 2026.03.18)"},
Comment on lines +74 to +75
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per docs/command-guidelines.md, new commands should provide localized example messages (CmdBaselineDiffExample1, etc.) rather than only raw string literals in the examples list. This ensures examples appear localized/consistent in vcpkg help. Consider adding the example message keys to the message map and referencing them here (similar to other commands like x-add-version).

Suggested change
{"vcpkg x-baseline-diff <old_commit_sha> <newer_commit_sha>",
"vcpkg x-baseline-diff $(git rev-parse 2026.02.27) $(git rev-parse 2026.03.18)"},
{msgCmdBaselineDiffExample1, msgCmdBaselineDiffExample2},

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must say that i am always very confused if such examples gets translated. Also only old and new would be translated here (The people that uses git also understand git without translations...).

Copy link
Copy Markdown
Member

@BillyONeal BillyONeal Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general if there was "English" in the example we made it be translated, and if there was not we did not. So for instance, remove has one that is translated (vcpkg remove <package name>... because "package name" is translatable) and two that are not:

{msgCmdRemoveExample1, "vcpkg remove zlib zlib:x64-windows curl boost", "vcpkg remove --outdated"},

So I believe in this case the one that says <old_commit_sha> should get translated but the one with rev-parse should not. (However I'm not sure we should show the rev-parse example at all as that syntax makes shell assumptions)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just accept the tags here rather than needing the user to say rev-parse? (I fixed a similar bug in #1935 )

Undocumented,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a docs page for this.

AutocompletePriority::Public,
2,
2,
{switches, {}, multisettings},
nullptr,
};
Comment thread
autoantwort marked this conversation as resolved.

void command_baseline_diff_and_exit(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
Triplet default_triplet,
Triplet host_triplet)
{
const auto* manifest = paths.get_manifest();
if (manifest == nullptr)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I agree with this design: Because the user is explicitly passing in multiple baseline SHAs, it seems to really be more of a classic mode command as other registries aren't accounted for.

It seems like what you actually wanted is effectively this same diff but before/after what x-update-baseline does?

If this stays manifest only, it seems like one of the SHAs should be the one already in the manifest?

{
Checks::msg_exit_with_message(VCPKG_LINE_INFO, msgMissingManifestFile);
}
auto options = args.parse_arguments(CommandBaselineDiffMetadata);
check_for_valid_sha(options.command_arguments.at(0));
check_for_valid_sha(options.command_arguments.at(1));
Comment on lines +95 to +96
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
check_for_valid_sha(options.command_arguments.at(0));
check_for_valid_sha(options.command_arguments.at(1));
check_for_valid_sha(options.command_arguments[0]);
check_for_valid_sha(options.command_arguments[1]);


auto& fs = paths.get_filesystem();
InstalledDatabaseLock installed_lock{fs, paths.installed(), args.wait_for_lock, args.ignore_lock_failures};
auto var_provider_storage = CMakeVars::make_triplet_cmake_var_provider(paths, installed_lock);

Check failure on line 100 in src/vcpkg/commands.baseline-diff.cpp

View workflow job for this annotation

GitHub Actions / builds / build (ubuntu-24.04-arm, linux-arm64-ci)

invalid initialization of reference of type ‘const vcpkg::InstallAndBuildDatabaseLock&’ from expression of type ‘vcpkg::InstalledDatabaseLock’

Check failure on line 100 in src/vcpkg/commands.baseline-diff.cpp

View workflow job for this annotation

GitHub Actions / builds / build (macos-26, macos-ci)

no viable conversion from 'InstalledDatabaseLock' to 'const InstallAndBuildDatabaseLock'

Check failure on line 100 in src/vcpkg/commands.baseline-diff.cpp

View workflow job for this annotation

GitHub Actions / builds / build (windows-2025, windows-ci)

'std::unique_ptr<vcpkg::CMakeVars::CMakeVarProvider,std::default_delete<vcpkg::CMakeVars::CMakeVarProvider>> vcpkg::CMakeVars::make_triplet_cmake_var_provider(const vcpkg::VcpkgPaths &,const vcpkg::InstallAndBuildDatabaseLock &)': cannot convert argument 2 from 'vcpkg::InstalledDatabaseLock' to 'const vcpkg::InstallAndBuildDatabaseLock &'

Check failure on line 100 in src/vcpkg/commands.baseline-diff.cpp

View workflow job for this annotation

GitHub Actions / builds / build (ubuntu-24.04, linux-ci)

invalid initialization of reference of type ‘const vcpkg::InstallAndBuildDatabaseLock&’ from expression of type ‘vcpkg::InstalledDatabaseLock’
auto& var_provider = *var_provider_storage;

auto configuration = paths.get_configuration();
bool is_default_builtin = configuration.instantiate_registry_set(paths)->is_default_builtin_registry();
auto manifest_scf = parse_manifest_scf_or_exit(*manifest, paths, is_default_builtin);

const auto& manifest_core = *manifest_scf->core_paragraph;
PackageSpec toplevel{manifest_core.name, default_triplet};
auto features = get_manifest_features(options, manifest_core, var_provider, toplevel, host_triplet);

auto dependencies = get_manifest_dependencies(*manifest_scf, features);

ActionPlan plan[2];
for (int i = 0; i < 2; ++i)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (int i = 0; i < 2; ++i)
for (size_t i = 0; i < 2; ++i)

to avoid any sugned/unsigned mismatch warnings from vector.

{
if (auto default_reg = configuration.config.default_reg.get())
{
default_reg->baseline = options.command_arguments.at(i);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
default_reg->baseline = options.command_arguments.at(i);
default_reg->baseline = options.command_arguments[i];

}
else
{
RegistryConfig synthesized_registry;
synthesized_registry.kind = JsonIdBuiltin.to_string();
synthesized_registry.baseline = options.command_arguments.at(i);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
synthesized_registry.baseline = options.command_arguments.at(i);
synthesized_registry.baseline = options.command_arguments[i];

configuration.config.default_reg.emplace(synthesized_registry);
}

auto registry_set = configuration.instantiate_registry_set(paths);
auto verprovider = make_versioned_portfile_provider(*registry_set);
auto baseprovider = make_baseline_provider(*registry_set);

auto extended_overlay_port_directories = paths.overlay_ports;

auto oprovider = make_manifest_provider(fs,
extended_overlay_port_directories,
manifest->path,
std::make_unique<SourceControlFile>(manifest_scf->clone()));
PackagesDirAssigner packages_dir_assigner{paths.packages()};
Comment thread
autoantwort marked this conversation as resolved.
Comment thread
autoantwort marked this conversation as resolved.
const CreateInstallPlanOptions create_options{
nullptr, host_triplet, UnsupportedPortAction::Warn, UseHeadVersion::No, Editable::No};
plan[i] = create_versioned_install_plan(*verprovider,
*baseprovider,
*oprovider,
var_provider,
dependencies,
manifest_core.overrides,
toplevel,
packages_dir_assigner,
create_options)
.value_or_exit(VCPKG_LINE_INFO);
Comment thread
BillyONeal marked this conversation as resolved.
}

std::map<PackageSpec, std::string> versions;
for (const auto& action : plan[0].install_actions)
{
versions[action.spec] = action.version.to_string();
}
std::vector<std::string> user_requested;
std::vector<std::string> transitive;
for (const auto& action : plan[1].install_actions)
{
auto oldIter = versions.find(action.spec);
auto newVersion = action.version.to_string();
auto& vec = action.request_type == RequestType::USER_REQUESTED ? user_requested : transitive;
if (oldIter == versions.end())
{
vec.push_back(fmt::format("{}: new: {}", action.spec.name(), newVersion));
}
else if (oldIter->second != newVersion)
{
vec.push_back(fmt::format("{}: {} -> {}", action.spec.name(), oldIter->second, newVersion));
Comment thread
BillyONeal marked this conversation as resolved.
}
}
Comment thread
BillyONeal marked this conversation as resolved.
bool any_changes = false;
any_changes |= print_lines(msgDirectDependencies, std::move(user_requested));
any_changes |= print_lines(msgTransitiveDependencies, std::move(transitive));
if (!any_changes)
{
msg::println(msgBaselineDiffNoChange);
}

Checks::exit_success(VCPKG_LINE_INFO);
}
} // namespace vcpkg
2 changes: 2 additions & 0 deletions src/vcpkg/commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <vcpkg/commands.add-version.h>
#include <vcpkg/commands.add.h>
#include <vcpkg/commands.autocomplete.h>
#include <vcpkg/commands.baseline-diff.h>
#include <vcpkg/commands.bootstrap-standalone.h>
#include <vcpkg/commands.build-external.h>
#include <vcpkg/commands.build.h>
Expand Down Expand Up @@ -127,6 +128,7 @@ namespace vcpkg
{CommandInstallMetadata, command_install_and_exit},
{CommandRemoveMetadata, command_remove_and_exit},
{CommandTestFeaturesMetadata, command_test_features_and_exit},
{CommandBaselineDiffMetadata, command_baseline_diff_and_exit},
{CommandSetInstalledMetadata, command_set_installed_and_exit},
{CommandUpgradeMetadata, command_upgrade_and_exit},
{CommandZPrintConfigMetadata, command_z_print_config_and_exit},
Expand Down
Loading