Skip to content

Commit

Permalink
fix: 3way merge fix and merge recipe tests (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaucy authored Sep 12, 2024
1 parent 8281d27 commit 7c0f872
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 73 deletions.
1 change: 1 addition & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ bazel_dep(name = "boost.url", version = "1.83.0.bzl.2")
bazel_dep(name = "yaml-cpp", version = "0.8.0")
bazel_dep(name = "libarchive", version = "3.7.4.bcr.2")

bazel_dep(name = "googletest", version = "1.15.2", dev_dependency = True)
bazel_dep(name = "toolchains_llvm", version = "1.0.0", dev_dependency = True)
bazel_dep(name = "hedron_compile_commands", dev_dependency = True)

Expand Down
137 changes: 75 additions & 62 deletions ecsact/cli/commands/build/build_recipe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,10 @@ static auto parse_sources( //
outdir = src["outdir"].as<std::string>();
}

if(!relative_to_cwd && !src_path.is_absolute()) {
src_path = recipe_path.parent_path() / src_path;
if(relative_to_cwd && !src_path.is_absolute()) {
src_path = (fs::current_path() / src_path).lexically_normal();
} else {
src_path = src_path.lexically_normal();
}

result.emplace_back(source_path{
Expand All @@ -252,10 +254,7 @@ static auto parse_sources( //
});
}
} else if(src.IsScalar()) {
auto path = fs::path{src.as<std::string>()};
if(!path.is_absolute()) {
path = recipe_path.parent_path() / path;
}
auto path = fs::path{src.as<std::string>()}.lexically_normal();
result.emplace_back(source_path{
.path = path,
.outdir = ".",
Expand All @@ -266,76 +265,90 @@ static auto parse_sources( //
return result;
}

auto ecsact::build_recipe::from_yaml_file( //
std::filesystem::path p
auto ecsact::build_recipe::build_recipe_from_yaml_node( //
YAML::Node doc,
fs::path p
) -> create_result {
auto file = std::ifstream{p};
try {
auto doc = YAML::LoadFile(p.string());

if(!doc.IsMap()) {
return build_recipe_parse_error::expected_map_top_level;
}
if(!doc.IsMap()) {
return ecsact::build_recipe_parse_error::expected_map_top_level;
}

auto exports = parse_exports(doc["exports"]);
if(auto err = get_if_error(exports)) {
return *err;
}
auto exports = parse_exports(doc["exports"]);
if(auto err = get_if_error(exports)) {
return *err;
}

auto imports = parse_imports(doc["imports"]);
if(auto err = get_if_error(imports)) {
return *err;
}
auto imports = parse_imports(doc["imports"]);
if(auto err = get_if_error(imports)) {
return *err;
}

auto sources = parse_sources(p, doc["sources"]);
if(auto err = get_if_error(sources)) {
return *err;
}
auto sources = parse_sources(p, doc["sources"]);
if(auto err = get_if_error(sources)) {
return *err;
}

auto system_libs = parse_system_libs(doc["system_libs"]);
if(auto err = get_if_error(system_libs)) {
return *err;
}
auto system_libs = parse_system_libs(doc["system_libs"]);
if(auto err = get_if_error(system_libs)) {
return *err;
}

auto recipe = build_recipe{};
if(doc["name"]) {
recipe._name = doc["name"].as<std::string>();
}
if(p.has_parent_path()) {
recipe._base_directory = p.parent_path().generic_string();
}
recipe._exports = get_value(exports);
recipe._imports = get_value(imports);
recipe._sources = get_value(sources);
recipe._system_libs = get_value(system_libs);
auto recipe = ecsact::build_recipe{};
if(doc["name"]) {
recipe._name = doc["name"].as<std::string>();
}
if(p.has_parent_path()) {
recipe._base_directory = p.parent_path().generic_string();
}
recipe._exports = get_value(exports);
recipe._imports = get_value(imports);
recipe._sources = get_value(sources);
recipe._system_libs = get_value(system_libs);

if(recipe._exports.empty()) {
return build_recipe_parse_error::missing_exports;
}
if(recipe._exports.empty()) {
return build_recipe_parse_error::missing_exports;
}

auto import_modules =
ecsact::cli::detail::get_ecsact_modules(recipe._imports);
auto export_modules =
ecsact::cli::detail::get_ecsact_modules(recipe._exports);
auto import_modules =
ecsact::cli::detail::get_ecsact_modules(recipe._imports);
auto export_modules =
ecsact::cli::detail::get_ecsact_modules(recipe._exports);

if(!import_modules.unknown_module_methods.empty()) {
return build_recipe_parse_error::unknown_import_method;
}
if(!import_modules.unknown_module_methods.empty()) {
return build_recipe_parse_error::unknown_import_method;
}

if(!export_modules.unknown_module_methods.empty()) {
return build_recipe_parse_error::unknown_export_method;
}
if(!export_modules.unknown_module_methods.empty()) {
return build_recipe_parse_error::unknown_export_method;
}

for(auto&& [imp_mod, _] : import_modules.module_methods) {
for(auto&& [exp_mod, _] : export_modules.module_methods) {
if(imp_mod == exp_mod) {
return build_recipe_parse_error::
conflicting_import_export_method_modules;
}
for(auto&& [imp_mod, _] : import_modules.module_methods) {
for(auto&& [exp_mod, _] : export_modules.module_methods) {
if(imp_mod == exp_mod) {
return build_recipe_parse_error::
conflicting_import_export_method_modules;
}
}
}

return recipe;
return recipe;
}

auto ecsact::build_recipe::from_yaml_string( //
const std::string& str,
fs::path p
) -> create_result {
auto doc = YAML::Load(str);
return build_recipe_from_yaml_node(doc, p);
}

auto ecsact::build_recipe::from_yaml_file( //
std::filesystem::path p
) -> create_result {
auto file = std::ifstream{p};
try {
auto doc = YAML::LoadFile(p.string());
return build_recipe_from_yaml_node(doc, p);
} catch(const YAML::BadFile& err) {
ecsact::cli::report_error("YAML PARSE: {}", err.what());
return build_recipe_parse_error::bad_file;
Expand Down
17 changes: 16 additions & 1 deletion ecsact/cli/commands/build/build_recipe.hh
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#pragma once

#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
#include <span>
#include <filesystem>
#include <cstddef>
#include <optional>
#include <filesystem>

namespace YAML {
class Node;
}

namespace ecsact {

Expand All @@ -33,6 +38,11 @@ public:
std::filesystem::path p
) -> create_result;

static auto from_yaml_string( //
const std::string& str,
std::filesystem::path p
) -> create_result;

static auto merge( //
const build_recipe& a,
const build_recipe& b
Expand Down Expand Up @@ -84,6 +94,11 @@ private:

build_recipe();
build_recipe(const build_recipe&);

static auto build_recipe_from_yaml_node( //
YAML::Node doc,
std::filesystem::path p
) -> create_result;
};

struct build_recipe::create_result
Expand Down
30 changes: 20 additions & 10 deletions ecsact/cli/commands/build/recipe/cook.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ static auto write_file(fs::path path, std::span<std::byte> data) -> void {
}

static auto handle_source( //
fs::path base_directory,
ecsact::build_recipe::source_fetch src,
const ecsact::cli::cook_recipe_options& options
) -> int {
Expand Down Expand Up @@ -239,6 +240,7 @@ static auto handle_source( //
}

static auto handle_source( //
fs::path base_directory,
ecsact::build_recipe::source_codegen src,
const ecsact::cli::cook_recipe_options& options
) -> int {
Expand Down Expand Up @@ -275,55 +277,61 @@ static auto handle_source( //
}

static auto handle_source( //
fs::path base_directory,
ecsact::build_recipe::source_path src,
const ecsact::cli::cook_recipe_options& options
) -> int {
auto src_path = src.path;
if(!src_path.is_absolute()) {
src_path = (base_directory / src_path).lexically_normal();
}

auto outdir = src.outdir //
? options.work_dir / *src.outdir
: options.work_dir;

auto ec = std::error_code{};
fs::create_directories(outdir, ec);

auto before_glob = path_before_glob(src.path);
auto paths = expand_path_globs(src.path, ec);
auto before_glob = path_before_glob(src_path);
auto paths = expand_path_globs(src_path, ec);
if(ec) {
ecsact::cli::report_error(
"Failed to glob {}: {}",
src.path.generic_string(),
src_path.generic_string(),
ec.message()
);
return 1;
}

for(auto path : paths) {
if(!fs::exists(src.path)) {
if(!fs::exists(src_path)) {
ecsact::cli::report_error(
"Source file {} does not exist",
src.path.generic_string()
src_path.generic_string()
);
return 1;
}
auto rel_outdir = outdir;
if(auto stripped = path_strip_prefix(src.path, before_glob)) {
if(auto stripped = path_strip_prefix(src_path, before_glob)) {
rel_outdir = outdir / *stripped;
}

fs::create_directories(rel_outdir, ec);
fs::copy(src.path, rel_outdir, ec);
fs::copy(src_path, rel_outdir, ec);

if(ec) {
ecsact::cli::report_error(
"Failed to copy source {} to {}: {}",
src.path.generic_string(),
src_path.generic_string(),
rel_outdir.generic_string(),
ec.message()
);
return 1;
} else {
ecsact::cli::report_info(
"Copied source {} to {}",
src.path.generic_string(),
src_path.generic_string(),
rel_outdir.generic_string()
);
}
Expand Down Expand Up @@ -707,7 +715,9 @@ auto ecsact::cli::cook_recipe( //

for(auto& src : recipe.sources()) {
exit_code = std::visit(
[&](auto& src) { return handle_source(src, recipe_options); },
[&](auto& src) {
return handle_source(recipe.base_directory(), src, recipe_options);
},
src
);

Expand Down
13 changes: 13 additions & 0 deletions ecsact/cli/commands/build/test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
load("@rules_cc//cc:defs.bzl", "cc_test")
load("//bazel:copts.bzl", "copts")

cc_test(
name = "merge_recipe_test",
copts = copts,
srcs = ["merge_recipe_test.cc"],
deps = [
"@googletest//:gtest",
"@googletest//:gtest_main",
"//ecsact/cli/commands/build:build_recipe",
],
)
Loading

0 comments on commit 7c0f872

Please sign in to comment.