[x-download] teach to not need a sha512 (#142)
This commit is contained in:
Родитель
816d21f303
Коммит
1e4448e073
|
@ -55,7 +55,7 @@ namespace vcpkg::Downloads
|
|||
void download_file(Filesystem& fs,
|
||||
const std::string& url,
|
||||
const path& download_path,
|
||||
const std::string& sha512) const
|
||||
const Optional<std::string>& sha512) const
|
||||
{
|
||||
this->download_file(fs, url, {}, download_path, sha512);
|
||||
}
|
||||
|
@ -64,18 +64,16 @@ namespace vcpkg::Downloads
|
|||
const std::string& url,
|
||||
View<std::string> headers,
|
||||
const path& download_path,
|
||||
const std::string& sha512) const;
|
||||
const Optional<std::string>& sha512) const;
|
||||
|
||||
// Returns url that was successfully downloaded from
|
||||
std::string download_file(Filesystem& fs,
|
||||
View<std::string> urls,
|
||||
View<std::string> headers,
|
||||
const path& download_path,
|
||||
const std::string& sha512) const;
|
||||
const Optional<std::string>& sha512) const;
|
||||
|
||||
ExpectedS<int> put_file_to_mirror(const Filesystem& fs,
|
||||
const path& file_to_put,
|
||||
const std::string& sha512) const;
|
||||
ExpectedS<int> put_file_to_mirror(const Filesystem& fs, const path& file_to_put, StringView sha512) const;
|
||||
|
||||
private:
|
||||
DownloadManagerConfig m_config;
|
||||
|
|
|
@ -195,9 +195,9 @@ namespace vcpkg::Downloads
|
|||
}
|
||||
|
||||
static Optional<std::string> try_verify_downloaded_file_hash(const Filesystem& fs,
|
||||
const std::string& sanitized_url,
|
||||
StringView sanitized_url,
|
||||
const path& downloaded_path,
|
||||
const std::string& sha512)
|
||||
StringView sha512)
|
||||
{
|
||||
std::string actual_hash =
|
||||
vcpkg::Hash::get_file_hash(VCPKG_LINE_INFO, fs, downloaded_path, Hash::Algorithm::Sha512);
|
||||
|
@ -232,6 +232,24 @@ namespace vcpkg::Downloads
|
|||
}
|
||||
}
|
||||
|
||||
static bool check_downloaded_file_hash(Filesystem& fs,
|
||||
const Optional<std::string>& hash,
|
||||
StringView sanitized_url,
|
||||
const path& download_part_path,
|
||||
std::string& errors)
|
||||
{
|
||||
if (auto p = hash.get())
|
||||
{
|
||||
auto maybe_error = try_verify_downloaded_file_hash(fs, sanitized_url, download_part_path, *p);
|
||||
if (auto err = maybe_error.get())
|
||||
{
|
||||
Strings::append(errors, *err, '\n');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void url_heads_inner(View<std::string> urls, View<std::string> headers, std::vector<int>* out)
|
||||
{
|
||||
static constexpr StringLiteral guid_marker = "8a1db05f-a65d-419b-aa72-037fb4d0672e";
|
||||
|
@ -481,7 +499,7 @@ namespace vcpkg::Downloads
|
|||
const std::string& url,
|
||||
View<std::string> headers,
|
||||
const path& download_path,
|
||||
const std::string& sha512,
|
||||
const Optional<std::string>& sha512,
|
||||
const std::vector<std::string>& secrets,
|
||||
std::string& errors)
|
||||
{
|
||||
|
@ -504,22 +522,13 @@ namespace vcpkg::Downloads
|
|||
{
|
||||
if (download_winhttp(fs, download_path_part_path, split_uri, url, secrets, errors))
|
||||
{
|
||||
auto maybe_error = try_verify_downloaded_file_hash(fs, url, download_path_part_path, sha512);
|
||||
if (auto err = maybe_error.get())
|
||||
{
|
||||
Strings::append(errors, *err);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if (check_downloaded_file_hash(fs, sha512, url, download_path_part_path, errors))
|
||||
{
|
||||
fs.rename(download_path_part_path, download_path, VCPKG_LINE_INFO);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -544,24 +553,19 @@ namespace vcpkg::Downloads
|
|||
return false;
|
||||
}
|
||||
|
||||
auto maybe_error = try_verify_downloaded_file_hash(fs, sanitized_url, download_path_part_path, sha512);
|
||||
if (auto err = maybe_error.get())
|
||||
{
|
||||
Strings::append(errors, *err);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if (check_downloaded_file_hash(fs, sha512, sanitized_url, download_path_part_path, errors))
|
||||
{
|
||||
fs.rename(download_path_part_path, download_path, VCPKG_LINE_INFO);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Optional<const std::string&> try_download_files(vcpkg::Filesystem& fs,
|
||||
View<std::string> urls,
|
||||
View<std::string> headers,
|
||||
const path& download_path,
|
||||
const std::string& sha512,
|
||||
const Optional<std::string>& sha512,
|
||||
const std::vector<std::string>& secrets,
|
||||
std::string& errors)
|
||||
{
|
||||
|
@ -582,7 +586,7 @@ namespace vcpkg::Downloads
|
|||
const std::string& url,
|
||||
View<std::string> headers,
|
||||
const path& download_path,
|
||||
const std::string& sha512) const
|
||||
const Optional<std::string>& sha512) const
|
||||
{
|
||||
this->download_file(fs, View<std::string>(&url, 1), headers, download_path, sha512);
|
||||
}
|
||||
|
@ -591,22 +595,32 @@ namespace vcpkg::Downloads
|
|||
View<std::string> urls,
|
||||
View<std::string> headers,
|
||||
const path& download_path,
|
||||
const std::string& sha512) const
|
||||
const Optional<std::string>& sha512) const
|
||||
{
|
||||
std::string errors;
|
||||
if (auto read_template = m_config.m_read_url_template.get())
|
||||
if (auto hash = sha512.get())
|
||||
{
|
||||
auto read_url = Strings::replace_all(std::string(*read_template), "<SHA>", sha512);
|
||||
if (Downloads::try_download_file(
|
||||
fs, read_url, m_config.m_read_headers, download_path, sha512, m_config.m_secrets, errors))
|
||||
return read_url;
|
||||
if (auto read_template = m_config.m_read_url_template.get())
|
||||
{
|
||||
auto read_url = Strings::replace_all(std::string(*read_template), "<SHA>", *hash);
|
||||
if (Downloads::try_download_file(
|
||||
fs, read_url, m_config.m_read_headers, download_path, sha512, m_config.m_secrets, errors))
|
||||
return read_url;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_config.m_block_origin)
|
||||
{
|
||||
if (urls.size() == 0)
|
||||
{
|
||||
Strings::append(errors, "Error: No urls specified to download SHA: ", sha512);
|
||||
if (auto hash = sha512.get())
|
||||
{
|
||||
Strings::append(errors, "Error: No urls specified to download SHA: ", *hash, '\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
Strings::append(errors, "Error: No urls specified\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -614,10 +628,13 @@ namespace vcpkg::Downloads
|
|||
try_download_files(fs, urls, headers, download_path, sha512, m_config.m_secrets, errors);
|
||||
if (auto url = maybe_url.get())
|
||||
{
|
||||
auto maybe_push = put_file_to_mirror(fs, download_path, sha512);
|
||||
if (!maybe_push.has_value())
|
||||
if (auto hash = sha512.get())
|
||||
{
|
||||
print2(Color::warning, "Warning: failed to store back to mirror:\n", maybe_push.error());
|
||||
auto maybe_push = put_file_to_mirror(fs, download_path, *hash);
|
||||
if (!maybe_push.has_value())
|
||||
{
|
||||
print2(Color::warning, "Warning: failed to store back to mirror:\n", maybe_push.error());
|
||||
}
|
||||
}
|
||||
return *url;
|
||||
}
|
||||
|
@ -628,7 +645,7 @@ namespace vcpkg::Downloads
|
|||
|
||||
ExpectedS<int> DownloadManager::put_file_to_mirror(const Filesystem& fs,
|
||||
const path& file_to_put,
|
||||
const std::string& sha512) const
|
||||
StringView sha512) const
|
||||
{
|
||||
auto maybe_mirror_url = Strings::replace_all(m_config.m_write_url_template.value_or(""), "<SHA>", sha512);
|
||||
if (!maybe_mirror_url.empty())
|
||||
|
|
|
@ -12,11 +12,17 @@
|
|||
namespace vcpkg::Commands::X_Download
|
||||
{
|
||||
static constexpr StringLiteral OPTION_STORE = "store";
|
||||
static constexpr StringLiteral OPTION_SKIP_SHA512 = "skip-sha512";
|
||||
static constexpr StringLiteral OPTION_SHA512 = "sha512";
|
||||
static constexpr StringLiteral OPTION_URL = "url";
|
||||
static constexpr StringLiteral OPTION_HEADER = "header";
|
||||
|
||||
static constexpr CommandSwitch FETCH_SWITCHES[] = {
|
||||
{OPTION_STORE, "Indicates the file should be stored instead of fetched"},
|
||||
{OPTION_SKIP_SHA512, "Do not check the SHA512 of the downloaded file"},
|
||||
};
|
||||
static constexpr CommandSetting FETCH_SETTINGS[] = {
|
||||
{OPTION_SHA512, "The hash of the file to be downloaded"},
|
||||
};
|
||||
static constexpr CommandMultiSetting FETCH_MULTISETTINGS[] = {
|
||||
{OPTION_URL, "URL to download and store if missing from cache"},
|
||||
|
@ -24,20 +30,66 @@ namespace vcpkg::Commands::X_Download
|
|||
};
|
||||
|
||||
const CommandStructure COMMAND_STRUCTURE = {
|
||||
Strings::format("The argument must be at least a file path and a SHA512\n%s",
|
||||
create_example_string("x-download <filepath> <sha512> [--url=https://...]...")),
|
||||
Strings::format("%s\n%s",
|
||||
create_example_string("x-download <filepath> [--sha512=]<sha512> [--url=https://...]..."),
|
||||
create_example_string("x-download <filepath> --skip-sha512 [--url=https://...]...")),
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
{{FETCH_SWITCHES}, {}, FETCH_MULTISETTINGS},
|
||||
{FETCH_SWITCHES, FETCH_SETTINGS, FETCH_MULTISETTINGS},
|
||||
nullptr,
|
||||
};
|
||||
|
||||
static bool is_lower_hex(StringView sha)
|
||||
static bool is_hex(StringView sha)
|
||||
{
|
||||
return std::all_of(
|
||||
sha.begin(), sha.end(), [](char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f'); });
|
||||
return std::all_of(sha.begin(), sha.end(), [](char ch) {
|
||||
return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
|
||||
});
|
||||
}
|
||||
static bool is_sha512(StringView sha) { return sha.size() == 128 && is_hex(sha); }
|
||||
|
||||
static Optional<std::string> get_sha512_check(const VcpkgCmdArguments& args, const ParsedArguments& parsed)
|
||||
{
|
||||
Optional<std::string> sha = nullopt;
|
||||
auto sha_it = parsed.settings.find(OPTION_SHA512);
|
||||
if (args.command_arguments.size() > 1)
|
||||
{
|
||||
if (sha_it != parsed.settings.end())
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO,
|
||||
"Error: SHA512 passed as both an argument and as an option. Only pass one of these.");
|
||||
}
|
||||
sha = args.command_arguments[1];
|
||||
}
|
||||
else if (sha_it != parsed.settings.end())
|
||||
{
|
||||
sha = sha_it->second;
|
||||
}
|
||||
|
||||
if (Util::Sets::contains(parsed.switches, OPTION_SKIP_SHA512))
|
||||
{
|
||||
if (sha.has_value())
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "SHA512 passed, but --skip-sha512 was also passed; only do one or the other.");
|
||||
}
|
||||
}
|
||||
else if (!sha.has_value())
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Required argument --sha512 was not passed.");
|
||||
}
|
||||
|
||||
if (auto p = sha.get())
|
||||
{
|
||||
if (!is_sha512(*p))
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Error: SHA512's must be 128 hex characters: '%s'", *p);
|
||||
}
|
||||
Strings::ascii_to_lowercase(p->begin(), p->end());
|
||||
}
|
||||
|
||||
return sha;
|
||||
}
|
||||
static bool is_lower_sha512(StringView sha) { return sha.size() == 128 && is_lower_hex(sha); }
|
||||
|
||||
void perform_and_exit(const VcpkgCmdArguments& args, Filesystem& fs)
|
||||
{
|
||||
|
@ -46,26 +98,29 @@ namespace vcpkg::Commands::X_Download
|
|||
parse_download_configuration(args.asset_sources_template).value_or_exit(VCPKG_LINE_INFO)};
|
||||
path file = fs.absolute(vcpkg::u8path(args.command_arguments[0]), VCPKG_LINE_INFO);
|
||||
|
||||
std::string sha = Strings::ascii_to_lowercase(std::string(args.command_arguments[1]));
|
||||
if (!is_lower_sha512(sha))
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: SHA512's must be 128 hex characters: '%s'", args.command_arguments[1]);
|
||||
}
|
||||
auto sha = get_sha512_check(args, parsed);
|
||||
|
||||
// Is this a store command?
|
||||
if (Util::Sets::contains(parsed.switches, OPTION_STORE))
|
||||
{
|
||||
auto hash = sha.get();
|
||||
if (!hash)
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "--store option is invalid without a sha512.");
|
||||
}
|
||||
|
||||
auto s = fs.status(file, VCPKG_LINE_INFO);
|
||||
if (s.type() != vcpkg::file_type::regular)
|
||||
{
|
||||
Checks::exit_with_message(
|
||||
VCPKG_LINE_INFO, "Error: path was not a regular file: %s", vcpkg::u8string(file));
|
||||
}
|
||||
auto hash =
|
||||
Strings::ascii_to_lowercase(Hash::get_file_hash(VCPKG_LINE_INFO, fs, file, Hash::Algorithm::Sha512));
|
||||
if (hash != sha) Checks::exit_with_message(VCPKG_LINE_INFO, "Error: file to store does not match hash");
|
||||
download_manager.put_file_to_mirror(fs, file, sha).value_or_exit(VCPKG_LINE_INFO);
|
||||
auto actual_hash = Hash::get_file_hash(VCPKG_LINE_INFO, fs, file, Hash::Algorithm::Sha512);
|
||||
if (*hash != actual_hash)
|
||||
{
|
||||
Checks::exit_with_message(VCPKG_LINE_INFO, "Error: file to store does not match hash");
|
||||
}
|
||||
download_manager.put_file_to_mirror(fs, file, actual_hash).value_or_exit(VCPKG_LINE_INFO);
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
else
|
||||
|
@ -79,14 +134,13 @@ namespace vcpkg::Commands::X_Download
|
|||
}
|
||||
|
||||
auto it_urls = parsed.multisettings.find(OPTION_URL);
|
||||
if (it_urls == parsed.multisettings.end())
|
||||
View<std::string> urls{};
|
||||
if (it_urls != parsed.multisettings.end())
|
||||
{
|
||||
download_manager.download_file(fs, View<std::string>{}, headers, file, sha);
|
||||
}
|
||||
else
|
||||
{
|
||||
download_manager.download_file(fs, it_urls->second, headers, file, sha);
|
||||
urls = it_urls->second;
|
||||
}
|
||||
|
||||
download_manager.download_file(fs, urls, headers, file, sha);
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче