Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement 'new' in C++. #613

Merged
merged 13 commits into from
Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from 7 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
50 changes: 50 additions & 0 deletions azure-pipelines/end-to-end-tests-dir/new.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
. "$PSScriptRoot/../end-to-end-tests-prelude.ps1"

$manifestDir = "$TestingRoot/new_project"
New-Item -Path $manifestDir -ItemType Directory
$manifestPath = Join-Path $manifestDir 'vcpkg.json'
$configurationPath = Join-Path $manifestDir 'vcpkg-configuration.json'

Push-Location $manifestDir
$result = Run-Vcpkg new
Pop-Location
Throw-IfNotFailed
if (-not $result -contains '--application') {
throw "New without --name or --version didn't require setting --application"
}

Push-Location $manifestDir
Run-Vcpkg new --name=hello --version=1.0
Pop-Location
Throw-IfFailed

$expected = @"
{
"name": "hello",
"version": "1.0"
}
"@

$actual = (Get-Content -Path $manifestPath -Raw).TrimEnd()
if ($expected -ne $actual) {
throw "New didn't create vcpkg manifest correctly."
}

Push-Location $manifestDir
$result = Run-Vcpkg new --application
Pop-Location
Throw-IfNotFailed
if (-not $result -contains 'A manifest is already present at') {
throw "New didn't detect existing manifest correctly"
}

Remove-Item $manifestPath
Push-Location $manifestDir
$result = Run-Vcpkg new --application
Pop-Location
Throw-IfNotFailed
if (-not $result -contains 'Creating a manifest would overwrite a vcpkg-configuration.json') {
throw "New didn't detect existing configuration correctly"
}

Remove-Item $configurationPath
40 changes: 0 additions & 40 deletions ce/ce/cli/commands/new.ts

This file was deleted.

3 changes: 0 additions & 3 deletions ce/ce/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { DeleteCommand } from './cli/commands/delete';
import { FindCommand } from './cli/commands/find';
import { HelpCommand } from './cli/commands/help';
import { ListCommand } from './cli/commands/list';
import { NewCommand } from './cli/commands/new';
import { RegenerateCommand } from './cli/commands/regenerate-index';
import { RemoveCommand } from './cli/commands/remove';
import { UpdateCommand } from './cli/commands/update';
Expand Down Expand Up @@ -93,8 +92,6 @@ async function main() {
const activate = new ActivateCommand(commandline);
const deactivate = new DeactivateCommand(commandline);

const newcmd = new NewCommand(commandline);

const regenerate = new RegenerateCommand(commandline);
const update = new UpdateCommand(commandline);

Expand Down
3 changes: 3 additions & 0 deletions include/vcpkg/base/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,11 @@ namespace vcpkg::Json
std::pair<Value, JsonStyle> parse_file(LineInfo li, const Filesystem&, const Path&);
ExpectedS<Json::Object> parse_object(StringView text, StringView origin = {});

std::string stringify(const Value&);
std::string stringify(const Value&, JsonStyle style);
std::string stringify(const Object&);
std::string stringify(const Object&, JsonStyle style);
std::string stringify(const Array&);
std::string stringify(const Array&, JsonStyle style);

uint64_t get_json_parsing_stats();
Expand Down
16 changes: 16 additions & 0 deletions include/vcpkg/base/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,22 @@ namespace vcpkg
(msg::path, msg::exit_code),
"",
"msiexec failed while extracting '{path}' with launch or exit code {exit_code} and message:");
DECLARE_MESSAGE(NewConfigurationAlreadyExists,
(msg::path),
"",
"Creating a manifest would overwrite a vcpkg-configuration.json at {path}.");
DECLARE_MESSAGE(NewManifestAlreadyExists, (msg::path), "", "A manifest is already present at {path}.");
DECLARE_MESSAGE(NewNameCannotBeEmpty, (), "", "--name cannot be empty.");
DECLARE_MESSAGE(NewOnlyOneVersionKind,
(),
"",
"Only one of --version-relaxed, --version-date, or --version-string may be specified.");
DECLARE_MESSAGE(NewSpecifyNameVersionOrApplication,
(),
"",
"Either specify --name and --version to produce a manifest intended for C++ libraries, or specify "
"--application to indicate that the manifest is not intended to be used as a port.");
DECLARE_MESSAGE(NewVersionCannotBeEmpty, (), "", "--version cannot be empty.");
DECLARE_MESSAGE(NoLocalizationForMessages, (), "", "No localized messages for the following: ");
DECLARE_MESSAGE(NoRegistryForPort, (msg::package_name), "", "no registry configured for port {package_name}");
DECLARE_MESSAGE(PackingVendorFailed,
Expand Down
10 changes: 10 additions & 0 deletions include/vcpkg/commands.new.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
#pragma once

#include <vcpkg/base/expected.h>
#include <vcpkg/base/json.h>

#include <vcpkg/commands.interface.h>

namespace vcpkg::Commands
{
ExpectedL<Json::Object> build_prototype_manifest(const std::string* name,
const std::string* version,
bool option_application,
bool option_version_relaxed,
bool option_version_date,
bool option_version_string);

struct NewCommand : PathsCommand
{
void perform_and_exit(const VcpkgCmdArguments& args, const VcpkgPaths& paths) const override;
Expand Down
1 change: 0 additions & 1 deletion include/vcpkg/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,5 @@ namespace vcpkg
};

Json::IDeserializer<Configuration>& get_configuration_deserializer();
Json::IDeserializer<ManifestConfiguration>& get_manifest_configuration_deserializer();
std::vector<std::string> find_unknown_fields(const Configuration& config);
}
2 changes: 1 addition & 1 deletion include/vcpkg/registries.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

namespace vcpkg
{
constexpr StringLiteral builtin_registry_git_url() { return "https://github.com/microsoft/vcpkg"; }
constexpr StringLiteral builtin_registry_git_url = "https://github.com/microsoft/vcpkg";

struct LockFile
{
Expand Down
2 changes: 2 additions & 0 deletions include/vcpkg/vcpkgcmdarguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ namespace vcpkg
std::set<std::string, std::less<>> switches;
std::map<std::string, std::string, std::less<>> settings;
std::map<std::string, std::vector<std::string>, std::less<>> multisettings;

const std::string* read_setting(StringLiteral setting) const noexcept;
};

struct CommandSwitch
Expand Down
6 changes: 6 additions & 0 deletions locales/messages.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@
"LocalizedMessageMustNotEndWithNewline": "The message named {value} ends with a newline which should be added by formatting rather than by localization.",
"MonoInstructions": "This may be caused by an incomplete mono installation. Full mono is available on some systems via `sudo apt install mono-complete`. Ubuntu 18.04 users may need a newer version of mono, available at https://www.mono-project.com/download/stable/",
"MsiexecFailedToExtract": "msiexec failed while extracting '{path}' with launch or exit code {exit_code} and message:",
"NewConfigurationAlreadyExists": "Creating a manifest would overwrite a vcpkg-configuration.json at {path}.",
"NewManifestAlreadyExists": "A manifest is already present at {path}.",
"NewNameCannotBeEmpty": "--name cannot be empty.",
"NewOnlyOneVersionKind": "Only one of --version-relaxed, --version-date, or --version-string may be specified.",
"NewSpecifyNameVersionOrApplication": "Either specify --name and --version to produce a manifest intended for C++ libraries, or specify --application to indicate that the manifest is not intended to be used as a port.",
"NewVersionCannotBeEmpty": "--version cannot be empty.",
"NoLocalizationForMessages": "No localized messages for the following: ",
"NoRegistryForPort": "no registry configured for port {package_name}",
"NoteMessage": "note: ",
Expand Down
8 changes: 8 additions & 0 deletions locales/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@
"MonoInstructions": "This may be caused by an incomplete mono installation. Full mono is available on some systems via `sudo apt install mono-complete`. Ubuntu 18.04 users may need a newer version of mono, available at https://www.mono-project.com/download/stable/",
"MsiexecFailedToExtract": "msiexec failed while extracting '{path}' with launch or exit code {exit_code} and message:",
"_MsiexecFailedToExtract.comment": "An example of {path} is /foo/bar. An example of {exit_code} is 127.",
"NewConfigurationAlreadyExists": "Creating a manifest would overwrite a vcpkg-configuration.json at {path}.",
"_NewConfigurationAlreadyExists.comment": "An example of {path} is /foo/bar.",
"NewManifestAlreadyExists": "A manifest is already present at {path}.",
"_NewManifestAlreadyExists.comment": "An example of {path} is /foo/bar.",
"NewNameCannotBeEmpty": "--name cannot be empty.",
"NewOnlyOneVersionKind": "Only one of --version-relaxed, --version-date, or --version-string may be specified.",
"NewSpecifyNameVersionOrApplication": "Either specify --name and --version to produce a manifest intended for C++ libraries, or specify --application to indicate that the manifest is not intended to be used as a port.",
"NewVersionCannotBeEmpty": "--version cannot be empty.",
"NoLocalizationForMessages": "No localized messages for the following: ",
"NoRegistryForPort": "no registry configured for port {package_name}",
"_NoRegistryForPort.comment": "An example of {package_name} is zlib.",
Expand Down
6 changes: 2 additions & 4 deletions src/vcpkg-test/json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@ static auto _u8_string_to_char_string(const char8_t (&literal)[Sz]) -> const cha
namespace Json = vcpkg::Json;
using Json::Value;

static std::string mystringify(const Value& val) { return Json::stringify(val, Json::JsonStyle{}); }

TEST_CASE ("JSON stringify weird strings", "[json]")
{
std::string str = U8_STR("😀 😁 😂 🤣 😃 😄 😅 😆 😉");
REQUIRE(mystringify(Value::string(str)) == ('"' + str + "\"\n"));
REQUIRE(mystringify(Value::string("\xED\xA0\x80")) == "\"\\ud800\"\n"); // unpaired surrogate
REQUIRE(Json::stringify(Value::string(str)) == ('"' + str + "\"\n"));
REQUIRE(Json::stringify(Value::string("\xED\xA0\x80")) == "\"\\ud800\"\n"); // unpaired surrogate
}

TEST_CASE ("JSON parse keywords", "[json]")
Expand Down
9 changes: 3 additions & 6 deletions src/vcpkg-test/manifests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,7 @@ TEST_CASE ("manifest versioning", "[manifests]")
auto m_pgh = test_parse_project_manifest(projectManifest);
REQUIRE(m_pgh.has_value());
auto& pgh = **m_pgh.get();
CHECK(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) ==
Json::stringify(projectManifest, Json::JsonStyle::with_spaces(4)));
CHECK(Json::stringify(serialize_manifest(pgh)) == Json::stringify(projectManifest));
CHECK(pgh.core_paragraph->version_scheme == std::get<1>(v));
CHECK(pgh.core_paragraph->raw_version == std::get<2>(v));
CHECK(pgh.core_paragraph->port_version == 0);
Expand All @@ -209,8 +208,7 @@ TEST_CASE ("manifest versioning", "[manifests]")
auto m_pgh = test_parse_port_manifest(portManifest);
REQUIRE(m_pgh.has_value());
auto& pgh = **m_pgh.get();
CHECK(Json::stringify(serialize_manifest(pgh), Json::JsonStyle::with_spaces(4)) ==
Json::stringify(portManifest, Json::JsonStyle::with_spaces(4)));
CHECK(Json::stringify(serialize_manifest(pgh)) == Json::stringify(portManifest));
CHECK(pgh.core_paragraph->version_scheme == std::get<1>(v));
CHECK(pgh.core_paragraph->raw_version == std::get<2>(v));
CHECK(pgh.core_paragraph->port_version == 0);
Expand Down Expand Up @@ -800,8 +798,7 @@ TEST_CASE ("manifest embed configuration", "[manifests]")
auto config_obj = config.first.object(VCPKG_LINE_INFO);
REQUIRE(pgh.core_paragraph->vcpkg_configuration.has_value());
auto parsed_config_obj = *pgh.core_paragraph->vcpkg_configuration.get();
REQUIRE(Json::stringify(parsed_config_obj, Json::JsonStyle::with_spaces(4)) ==
Json::stringify(config_obj, Json::JsonStyle::with_spaces(4)));
REQUIRE(Json::stringify(parsed_config_obj) == Json::stringify(config_obj));
}

TEST_CASE ("manifest construct maximum", "[manifests]")
Expand Down
123 changes: 123 additions & 0 deletions src/vcpkg-test/new.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <catch2/catch.hpp>

#include <vcpkg/commands.new.h>

static std::string empty_string;
static std::string example_name = "puppies";
static std::string example_version_relaxed = "1.0";
static std::string example_version_date = "2022-07-05";
static std::string example_version_string = "vista";

using namespace vcpkg;
using namespace vcpkg::Commands;

TEST_CASE ("error cases", "[new]")
{
CHECK(build_prototype_manifest(nullptr, nullptr, false, false, false, false).error().extract_data() ==
"error: Either specify --name and --version to produce a manifest intended for C++ libraries, or specify "
"--application to indicate that the manifest is not intended to be used as a port.");
CHECK(build_prototype_manifest(&empty_string, &example_version_relaxed, false, false, false, false)
.error()
.extract_data() == "error: --name cannot be empty.");
CHECK(build_prototype_manifest(&example_name, &empty_string, false, false, false, false).error().extract_data() ==
"error: --version cannot be empty.");
CHECK(build_prototype_manifest(&example_name, &example_version_relaxed, false, true, true, false)
.error()
.extract_data() ==
"error: Only one of --version-relaxed, --version-date, or --version-string may be specified.");
}

TEST_CASE ("application does not require name and version", "[new]")
{
CHECK(build_prototype_manifest(nullptr, nullptr, true, false, false, false).value_or_exit(VCPKG_LINE_INFO) ==
Json::Object());
}

TEST_CASE ("version examples", "[new]")
{
SECTION ("guess version")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version", example_version_relaxed);
CHECK(build_prototype_manifest(&example_name, &example_version_relaxed, false, false, false, false)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("guess date")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version-date", example_version_date);
CHECK(build_prototype_manifest(&example_name, &example_version_date, false, false, false, false)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("guess string")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version-string", example_version_string);
CHECK(build_prototype_manifest(&example_name, &example_version_string, false, false, false, false)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("force version - version")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version", example_version_relaxed);
CHECK(build_prototype_manifest(&example_name, &example_version_relaxed, false, true, false, false)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("force version - date")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version", example_version_date);
CHECK(build_prototype_manifest(&example_name, &example_version_date, false, true, false, false)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("force version - string")
{
CHECK(!build_prototype_manifest(&example_name, &example_version_string, false, true, false, false).has_value());
}
SECTION ("force date - version")
{
CHECK(
!build_prototype_manifest(&example_name, &example_version_relaxed, false, false, true, false).has_value());
}
SECTION ("force date - date")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version-date", example_version_date);
CHECK(build_prototype_manifest(&example_name, &example_version_date, false, false, true, false)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("force date - string")
{
CHECK(!build_prototype_manifest(&example_name, &example_version_string, false, false, true, false).has_value());
}
SECTION ("force string - version")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version-string", example_version_relaxed);
CHECK(build_prototype_manifest(&example_name, &example_version_relaxed, false, false, false, true)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("force string - date")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version-string", example_version_date);
CHECK(build_prototype_manifest(&example_name, &example_version_date, false, false, false, true)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
SECTION ("force string - string")
{
Json::Object expected;
expected.insert("name", example_name);
expected.insert("version-string", example_version_string);
CHECK(build_prototype_manifest(&example_name, &example_version_string, false, false, false, true)
.value_or_exit(VCPKG_LINE_INFO) == expected);
}
}
4 changes: 2 additions & 2 deletions src/vcpkg-test/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ namespace vcpkg::Test
else if (l != r)
{
INFO(path);
INFO("l = " << Json::stringify(l, {}));
INFO("r = " << Json::stringify(r, {}));
INFO("l = " << Json::stringify(l));
INFO("r = " << Json::stringify(r));
CHECK(false);
}
}
Expand Down
Loading