瀏覽代碼

Merge branch 'feature/rm-ver-ranges' into develop

default_compile_flags
vector-of-bool 3 年之前
父節點
當前提交
1a1b087bbc
共有 38 個檔案被更改,包括 587 行新增99 行删除
  1. +9
    -7
      src/dds/build/builder.cpp
  2. +2
    -2
      src/dds/build/plan/library.cpp
  3. +1
    -1
      src/dds/build/plan/template.cpp
  4. +5
    -1
      src/dds/cli/cmd/build.cpp
  5. +15
    -0
      src/dds/cli/cmd/build_common.cpp
  6. +2
    -0
      src/dds/cli/cmd/build_common.hpp
  7. +7
    -1
      src/dds/cli/cmd/build_deps.cpp
  8. +1
    -1
      src/dds/cli/cmd/pkg_ls.cpp
  9. +63
    -7
      src/dds/cli/error_handler.cpp
  10. +1
    -1
      src/dds/db/database.cpp
  11. +20
    -7
      src/dds/deps.cpp
  12. +6
    -1
      src/dds/deps.hpp
  13. +4
    -5
      src/dds/deps.test.cpp
  14. +15
    -0
      src/dds/error/handle.cpp
  15. +26
    -0
      src/dds/error/handle.hpp
  16. +2
    -0
      src/dds/error/on_error.hpp
  17. +4
    -0
      src/dds/error/result.hpp
  18. +55
    -15
      src/dds/pkg/cache.cpp
  19. +12
    -8
      src/dds/pkg/db.cpp
  20. +4
    -4
      src/dds/pkg/db.test.cpp
  21. +1
    -1
      src/dds/pkg/get/dds_http.cpp
  22. +1
    -1
      src/dds/pkg/get/dds_http.test.cpp
  23. +6
    -4
      src/dds/pkg/id.cpp
  24. +4
    -2
      src/dds/pkg/id.hpp
  25. +1
    -1
      src/dds/pkg/id.test.cpp
  26. +73
    -0
      src/dds/pkg/name.cpp
  27. +36
    -0
      src/dds/pkg/name.hpp
  28. +72
    -0
      src/dds/pkg/name.test.cpp
  29. +7
    -8
      src/dds/repoman/repoman.cpp
  30. +7
    -2
      src/dds/sdist/library/manifest.cpp
  31. +6
    -1
      src/dds/sdist/library/manifest.hpp
  32. +9
    -2
      src/dds/sdist/library/root.cpp
  33. +12
    -2
      src/dds/sdist/package.cpp
  34. +14
    -2
      src/dds/sdist/package.hpp
  35. +4
    -4
      src/dds/solve/solve.cpp
  36. +0
    -4
      src/dds/util/result.hpp
  37. +51
    -4
      tests/test_basics.py
  38. +29
    -0
      tests/test_pkg_db.py

+ 9
- 7
src/dds/build/builder.cpp 查看文件

@@ -129,11 +129,13 @@ library_plan prepare_library(state& st,
}
}
}
return library_plan::create(lib, std::move(lp), pkg_man.namespace_ + "/" + lib.manifest().name);
return library_plan::create(lib,
std::move(lp),
pkg_man.namespace_.str + "/" + lib.manifest().name.str);
}

package_plan prepare_one(state& st, const sdist_target& sd) {
package_plan pkg{sd.sd.manifest.id.name, sd.sd.manifest.namespace_};
package_plan pkg{sd.sd.manifest.id.name.str, sd.sd.manifest.namespace_.str};
auto libs = collect_libraries(sd.sd.path);
for (const auto& lib : libs) {
pkg.add_library(prepare_library(st, sd, lib, sd.sd.manifest));
@@ -154,7 +156,7 @@ prepare_ureqs(const build_plan& plan, const toolchain& toolchain, path_ref out_r
usage_requirement_map ureqs;
for (const auto& pkg : plan.packages()) {
for (const auto& lib : pkg.libraries()) {
auto& lib_reqs = ureqs.add(pkg.namespace_(), lib.name());
auto& lib_reqs = ureqs.add(pkg.namespace_(), lib.name().str);
lib_reqs.include_paths.push_back(lib.library_().public_include_dir());
lib_reqs.uses = lib.library_().manifest().uses;
lib_reqs.links = lib.library_().manifest().links;
@@ -174,7 +176,7 @@ void write_lml(build_env_ref env, const library_plan& lib, path_ref lml_path) {
fs::create_directories(lml_path.parent_path());
auto out = open(lml_path, std::ios::binary | std::ios::out);
out << "Type: Library\n"
<< "Name: " << lib.name() << '\n'
<< "Name: " << lib.name().str << '\n'
<< "Include-Path: " << lib.library_().public_include_dir().generic_string() << '\n';
for (auto&& use : lib.uses()) {
out << "Uses: " << use.namespace_ << "/" << use.name << '\n';
@@ -196,7 +198,7 @@ void write_lmp(build_env_ref env, const package_plan& pkg, path_ref lmp_path) {
<< "Name: " << pkg.name() << '\n'
<< "Namespace: " << pkg.namespace_() << '\n';
for (const auto& lib : pkg.libraries()) {
auto lml_path = lmp_path.parent_path() / pkg.namespace_() / (lib.name() + ".lml");
auto lml_path = lmp_path.parent_path() / pkg.namespace_() / (lib.name().str + ".lml");
write_lml(env, lib, lml_path);
out << "Library: " << lml_path.generic_string() << '\n';
}
@@ -217,8 +219,8 @@ void write_lib_cmake(build_env_ref env,
std::ostream& out,
const package_plan& pkg,
const library_plan& lib) {
fmt::print(out, "# Library {}/{}\n", pkg.namespace_(), lib.name());
auto cmake_name = fmt::format("{}::{}", pkg.namespace_(), lib.name());
fmt::print(out, "# Library {}/{}\n", pkg.namespace_(), lib.name().str);
auto cmake_name = fmt::format("{}::{}", pkg.namespace_(), lib.name().str);
auto cm_kind = lib.archive_plan().has_value() ? "STATIC" : "INTERFACE";
fmt::print(
out,

+ 2
- 2
src/dds/build/plan/library.cpp 查看文件

@@ -36,7 +36,7 @@ library_plan library_plan::create(const library_root& lib,
std::vector<source_file> lib_sources;
std::vector<source_file> template_sources;

auto qual_name = std::string(qual_name_.value_or(lib.manifest().name));
auto qual_name = std::string(qual_name_.value_or(lib.manifest().name.str));

// Collect the source for this library. This will look for any compilable sources in the
// `src/` subdirectory of the library.
@@ -84,7 +84,7 @@ library_plan library_plan::create(const library_root& lib,
std::optional<create_archive_plan> archive_plan;
if (!lib_compile_files.empty()) {
dds_log(debug, "Generating an archive library for {}", qual_name);
archive_plan.emplace(lib.manifest().name,
archive_plan.emplace(lib.manifest().name.str,
qual_name,
params.out_subdir,
std::move(lib_compile_files));

+ 1
- 1
src/dds/build/plan/template.cpp 查看文件

@@ -136,7 +136,7 @@ std::string render_template(std::string_view tmpl, const library_root& lib) {
{
"lib",
json_data::mapping_type{
{"name", lib.manifest().name},
{"name", lib.manifest().name.str},
{"root", lib.path().string()},
},
},

+ 5
- 1
src/dds/cli/cmd/build.cpp 查看文件

@@ -12,7 +12,7 @@ using namespace dds;

namespace dds::cli::cmd {

int build(const options& opts) {
static int _build(const options& opts) {
if (!opts.build.add_repos.empty()) {
auto cat = opts.open_pkg_db();
for (auto& str : opts.build.add_repos) {
@@ -38,4 +38,8 @@ int build(const options& opts) {
return 0;
}

int build(const options& opts) {
return handle_build_error([&] { return _build(opts); });
}

} // namespace dds::cli::cmd

+ 15
- 0
src/dds/cli/cmd/build_common.cpp 查看文件

@@ -1,9 +1,12 @@
#include "./build_common.hpp"

#include <dds/error/errors.hpp>
#include <dds/pkg/cache.hpp>
#include <dds/pkg/db.hpp>
#include <dds/pkg/get/get.hpp>

#include <boost/leaf/handle_exception.hpp>

using namespace dds;

builder dds::cli::create_project_builder(const dds::cli::options& opts) {
@@ -43,3 +46,15 @@ builder dds::cli::create_project_builder(const dds::cli::options& opts) {
builder.add(sdist{std::move(man), opts.project_dir}, main_params);
return builder;
}

int dds::cli::handle_build_error(std::function<int()> fn) {
return boost::leaf::try_catch( //
fn,
[](user_error<errc::test_failure> exc) {
write_error_marker("build-failed-test-failed");
dds_log(error, "{}", exc.what());
dds_log(error, "{}", exc.explanation());
dds_log(error, "Refer: {}", exc.error_reference());
return 1;
});
}

+ 2
- 0
src/dds/cli/cmd/build_common.hpp 查看文件

@@ -8,4 +8,6 @@ namespace dds::cli {

dds::builder create_project_builder(const options& opts);

int handle_build_error(std::function<int()>);

} // namespace dds::cli

+ 7
- 1
src/dds/cli/cmd/build_deps.cpp 查看文件

@@ -1,5 +1,7 @@
#include "../options.hpp"

#include "./build_common.hpp"

#include <dds/build/builder.hpp>
#include <dds/build/params.hpp>
#include <dds/pkg/cache.hpp>
@@ -12,7 +14,7 @@

namespace dds::cli::cmd {

int build_deps(const options& opts) {
static int _build_deps(const options& opts) {
dds::build_params params{
.out_root = opts.out_path.value_or(fs::current_path() / "_deps"),
.existing_lm_index = {},
@@ -62,4 +64,8 @@ int build_deps(const options& opts) {
return 0;
}

int build_deps(const options& opts) {
return handle_build_error([&] { return _build_deps(opts); });
}

} // namespace dds::cli::cmd

+ 1
- 1
src/dds/cli/cmd/pkg_ls.cpp 查看文件

@@ -29,7 +29,7 @@ static int _pkg_ls(const options& opts) {
});

for (const auto& [name, grp] : grp_by_name) {
dds_log(info, "{}:", name);
dds_log(info, "{}:", name.str);
for (const dds::sdist& sd : grp) {
dds_log(info, " - {}", sd.manifest.id.version.to_string());
}

+ 63
- 7
src/dds/cli/error_handler.cpp 查看文件

@@ -3,6 +3,8 @@

#include <dds/error/errors.hpp>
#include <dds/error/toolchain.hpp>
#include <dds/sdist/library/manifest.hpp>
#include <dds/sdist/package.hpp>
#include <dds/util/http/pool.hpp>
#include <dds/util/log.hpp>
#include <dds/util/result.hpp>
@@ -42,13 +44,6 @@ auto handlers = std::tuple( //
write_error_marker("package-json5-parse-error");
return 1;
},
[](user_error<errc::test_failure> exc, matchv<cli::subcommand::build>) {
write_error_marker("build-failed-test-failed");
dds_log(error, "{}", exc.what());
dds_log(error, "{}", exc.explanation());
dds_log(error, "Refer: {}", exc.error_reference());
return 1;
},
[](boost::leaf::catch_<error_base> exc) {
dds_log(error, "{}", exc.value().what());
dds_log(error, "{}", exc.value().explanation());
@@ -85,6 +80,67 @@ auto handlers = std::tuple( //
}
return 1;
},
[](e_name_str badname,
invalid_name_reason why,
e_dependency_string depstr,
e_package_manifest_path* pkman_path) {
dds_log(
error,
"Invalid package name '.bold.red[{}]' in dependency string '.br.red[{}]': .br.yellow[{}]"_styled,
badname.value,
depstr.value,
invalid_name_reason_str(why));
if (pkman_path) {
dds_log(error,
" (While reading package manifest from [.bold.yellow[{}]])"_styled,
pkman_path->value);
}
write_error_marker("invalid-pkg-dep-name");
return 1;
},
[](e_pkg_name_str,
e_name_str badname,
invalid_name_reason why,
e_package_manifest_path* pkman_path) {
dds_log(error,
"Invalid package name '.bold.red[{}]': .br.yellow[{}]"_styled,
badname.value,
invalid_name_reason_str(why));
if (pkman_path) {
dds_log(error,
" (While reading package manifest from [.bold.yellow[{}]])"_styled,
pkman_path->value);
}
write_error_marker("invalid-pkg-name");
return 1;
},
[](e_pkg_namespace_str,
e_name_str badname,
invalid_name_reason why,
e_package_manifest_path* pkman_path) {
dds_log(error,
"Invalid package namespace '.bold.red[{}]': .br.yellow[{}]"_styled,
badname.value,
invalid_name_reason_str(why));
if (pkman_path) {
dds_log(error,
" (While reading package manifest from [.bold.yellow[{}]])"_styled,
pkman_path->value);
}
write_error_marker("invalid-pkg-namespace-name");
return 1;
},
[](e_library_manifest_path libpath, invalid_name_reason why, e_name_str badname) {
dds_log(error,
"Invalid library name '.bold.red[{}]': .br.yellow[{}]"_styled,
badname.value,
invalid_name_reason_str(why));
dds_log(error,
" (While reading library manifest from [.bold.yellow[{}]]"_styled,
libpath.value);
write_error_marker("invalid-lib-name");
return 1;
},
[](e_system_error_exc exc, boost::leaf::verbose_diagnostic_info const& diag) {
dds_log(critical,
"An unhandled std::system_error arose. THIS IS A DDS BUG! Info: {}",

+ 1
- 1
src/dds/db/database.cpp 查看文件

@@ -61,7 +61,7 @@ void ensure_migrated(nsql::database& db) {
PRAGMA foreign_keys = 1;
DROP TABLE IF EXISTS dds_meta;
CREATE TABLE IF NOT EXISTS dds_meta_1 AS
WITH init (version) AS (VALUES ('eggs'))
WITH init (version) AS (VALUES (''))
SELECT * FROM init;
)");
nsql::transaction_guard tr{db};

+ 20
- 7
src/dds/deps.cpp 查看文件

@@ -1,8 +1,13 @@
#include "./deps.hpp"

#include <dds/error/errors.hpp>
#include <dds/error/on_error.hpp>
#include <dds/error/result.hpp>
#include <dds/util/log.hpp>
#include <dds/util/string.hpp>

#include <boost/leaf/exception.hpp>
#include <ctre.hpp>
#include <json5/parse_data.hpp>
#include <semester/walk.hpp>

@@ -14,21 +19,29 @@
using namespace dds;

dependency dependency::parse_depends_string(std::string_view str) {
DDS_E_SCOPE(e_dependency_string{std::string(str)});
auto sep_pos = str.find_first_of("=@^~+");
if (sep_pos == str.npos) {
throw_user_error<errc::invalid_version_range_string>("Invalid dependency string '{}'", str);
}

auto name = str.substr(0, sep_pos);
auto name = *dds::name::from_string(str.substr(0, sep_pos));

if (str[sep_pos] == '@') {
++sep_pos;
if (str[sep_pos] != '@') {
static bool did_warn = false;
if (!did_warn) {
dds_log(warn,
"Dependency version ranges are deprecated. All are treated as "
"same-major-version. (Parsing dependency '{}')",
str);
}
did_warn = true;
}
auto range_str = str.substr(sep_pos);

auto range_str = "^" + std::string(str.substr(sep_pos + 1));
try {
auto rng = semver::range::parse_restricted(range_str);
return dependency{std::string(name), {rng.low(), rng.high()}};
return dependency{name, {rng.low(), rng.high()}};
} catch (const semver::invalid_range&) {
throw_user_error<errc::invalid_version_range_string>(
"Invalid version range string '{}' in dependency string '{}'", range_str, str);
@@ -81,7 +94,7 @@ std::string iv_string(const pubgrub::interval_set<semver::version>::interval_typ

std::string dependency::to_string() const noexcept {
std::stringstream strm;
strm << name << "@";
strm << name.str << "@";
if (versions.num_intervals() == 1) {
auto iv = *versions.iter_intervals().begin();
if (iv.high == iv.low.next_after()) {
@@ -89,7 +102,7 @@ std::string dependency::to_string() const noexcept {
return strm.str();
}
if (iv.low == semver::version() && iv.high == semver::version::max_version()) {
return name;
return name.str;
}
strm << "[" << iv_string(iv) << "]";
return strm.str();

+ 6
- 1
src/dds/deps.hpp 查看文件

@@ -1,5 +1,6 @@
#pragma once

#include <dds/pkg/name.hpp>
#include <dds/util/fs.hpp>

#include <pubgrub/interval.hpp>
@@ -12,8 +13,12 @@ namespace dds {

using version_range_set = pubgrub::interval_set<semver::version>;

struct e_dependency_string {
std::string value;
};

struct dependency {
std::string name;
dds::name name;
version_range_set versions;

static dependency parse_depends_string(std::string_view str);

+ 4
- 5
src/dds/deps.test.cpp 查看文件

@@ -11,15 +11,14 @@ TEST_CASE("Parse dependency strings") {
};

auto cur = GENERATE(Catch::Generators::values<case_>({
{"foo@1.2.3", "foo", "1.2.3", "1.2.4"},
{"foo=1.2.3", "foo", "1.2.3", "1.2.4"},
{"foo@1.2.3", "foo", "1.2.3", "2.0.0"},
{"foo=1.2.3", "foo", "1.2.3", "2.0.0"},
{"foo^1.2.3", "foo", "1.2.3", "2.0.0"},
{"foo~1.2.3", "foo", "1.2.3", "1.3.0"},
{"foo+1.2.3", "foo", "1.2.3", semver::version::max_version().to_string()},
{"foo~1.2.3", "foo", "1.2.3", "2.0.0"},
}));

auto dep = dds::dependency::parse_depends_string(cur.depstr);
CHECK(dep.name == cur.name);
CHECK(dep.name.str == cur.name);
CHECK(dep.versions.num_intervals() == 1);
auto ver_iv = *dep.versions.iter_intervals().begin();
CHECK(ver_iv.low == semver::version::parse(cur.low));

+ 15
- 0
src/dds/error/handle.cpp 查看文件

@@ -0,0 +1,15 @@
#include "./handle.hpp"

#include <dds/util/log.hpp>

#include <boost/leaf/handle_exception.hpp>
#include <boost/leaf/result.hpp>
#include <fmt/ostream.h>

using namespace dds;

void dds::leaf_handle_unknown_void(std::string_view message,
const boost::leaf::verbose_diagnostic_info& info) {
dds_log(warn, message);
dds_log(warn, "An unhandled error occurred:\n{}", info);
}

+ 26
- 0
src/dds/error/handle.hpp 查看文件

@@ -0,0 +1,26 @@
#pragma once

#include <neo/fwd.hpp>

#include <string_view>

namespace boost::leaf {

class verbose_diagnostic_info;

} // namespace boost::leaf

namespace dds {

void leaf_handle_unknown_void(std::string_view message,
const boost::leaf::verbose_diagnostic_info&);

template <typename T>
auto leaf_handle_unknown(std::string_view message, T&& val) {
return [val = NEO_FWD(val), message](const boost::leaf::verbose_diagnostic_info& info) {
leaf_handle_unknown_void(message, info);
return val;
};
}

} // namespace dds

+ 2
- 0
src/dds/error/on_error.hpp 查看文件

@@ -1,5 +1,7 @@
#pragma once

#include <neo/pp.hpp>

#include <boost/leaf/on_error.hpp>

/**

+ 4
- 0
src/dds/error/result.hpp 查看文件

@@ -9,4 +9,8 @@ namespace dds {

using boost::leaf::new_error;

struct e_human_message {
std::string value;
};

} // namespace dds

+ 55
- 15
src/dds/pkg/cache.cpp 查看文件

@@ -1,13 +1,17 @@
#include "./cache.hpp"

#include <dds/error/errors.hpp>
#include <dds/error/handle.hpp>
#include <dds/pkg/db.hpp>
#include <dds/sdist/dist.hpp>
#include <dds/sdist/library/manifest.hpp>
#include <dds/solve/solve.hpp>
#include <dds/util/log.hpp>
#include <dds/util/paths.hpp>
#include <dds/util/string.hpp>

#include <boost/leaf/handle_exception.hpp>
#include <fansi/styled.hpp>
#include <neo/ref.hpp>
#include <range/v3/action/sort.hpp>
#include <range/v3/action/unique.hpp>
@@ -17,7 +21,7 @@
#include <range/v3/view/transform.hpp>

using namespace dds;
using namespace fansi::literals;
using namespace ranges;

void pkg_cache::_log_blocking(path_ref dirpath) noexcept {
@@ -29,28 +33,64 @@ void pkg_cache::_init_cache_dir(path_ref dirpath) noexcept { fs::create_director

fs::path pkg_cache::default_local_path() noexcept { return dds_data_dir() / "pkg"; }

pkg_cache pkg_cache::_open_for_directory(bool writeable, path_ref dirpath) {
auto try_read_sdist = [](path_ref p) -> std::optional<sdist> {
if (starts_with(p.filename().string(), ".")) {
return std::nullopt;
}
try {
return sdist::from_directory(p);
} catch (const std::runtime_error& e) {
dds_log(error,
namespace {

std::optional<sdist> try_open_sdist_for_directory(path_ref p) noexcept {
if (starts_with(p.filename().string(), ".")) {
return std::nullopt;
}
return boost::leaf::try_catch( //
[&] { return std::make_optional(sdist::from_directory(p)); },
[&](boost::leaf::catch_<std::runtime_error> exc) {
dds_log(warn,
"Failed to load source distribution from directory '{}': {}",
p.string(),
e.what());
exc.value().what());
return std::nullopt;
}
};
},
[&](e_package_manifest_path*,
e_library_manifest_path* lman_path,
e_pkg_namespace_str* is_namespace,
e_pkg_name_str* is_pkgname,
e_name_str bad_name,
invalid_name_reason why) {
dds_log(
warn,
"Failed to load a source distribution contained in the package cache directory");
dds_log(warn,
"The invalid source distribution is in [.bold.yellow[{}]]"_styled,
p.string());
if (is_namespace) {
dds_log(warn,
"Invalid package namespace '.bold.yellow[{}]'"_styled,
bad_name.value);
} else if (is_pkgname) {
dds_log(warn, "Invalid package name '.bold.yellow[{}]'"_styled, bad_name.value);
} else if (lman_path) {
dds_log(
warn,
"Invalid library name '.bold.yellow[{}]' (Defined in [.bold.yellow[{}]])"_styled,
bad_name.value,
lman_path->value);
}
dds_log(warn, " (.bold.yellow[{}])"_styled, invalid_name_reason_str(why));
dds_log(warn, "We will ignore this directory and not load it as an available package");
return std::nullopt;
},
leaf_handle_unknown(fmt::format("Failed to load source distribution from directory [{}]",
p.string()),
std::nullopt));
}

} // namespace

pkg_cache pkg_cache::_open_for_directory(bool writeable, path_ref dirpath) {
auto entries =
// Get the top-level `name-version` dirs
fs::directory_iterator(dirpath) //
| neo::lref //
// Convert each dir into an `sdist` object
| ranges::views::transform(try_read_sdist) //
| ranges::views::transform(try_open_sdist_for_directory) //
// Drop items that failed to load
| ranges::views::filter([](auto&& opt) { return opt.has_value(); }) //
| ranges::views::transform([](auto&& opt) { return *opt; }) //
@@ -126,7 +166,7 @@ std::vector<pkg_id> pkg_cache::solve(const std::vector<dependency>& deps,
[&](std::string_view name) -> std::vector<pkg_id> {
auto mine = ranges::views::all(_sdists) //
| ranges::views::filter(
[&](const sdist& sd) { return sd.manifest.id.name == name; })
[&](const sdist& sd) { return sd.manifest.id.name.str == name; })
| ranges::views::transform([](const sdist& sd) { return sd.manifest.id; });
auto avail = ctlg.by_name(name);
auto all = ranges::views::concat(mine, avail) | ranges::to_vector;

+ 12
- 8
src/dds/pkg/db.cpp 查看文件

@@ -145,7 +145,7 @@ void migrate_repodb_3(nsql::database& db) {
void do_store_pkg(neo::sqlite3::database& db,
neo::sqlite3::statement_cache& st_cache,
const pkg_listing& pkg) {
dds_log(debug, "Recording package {}@{}", pkg.ident.name, pkg.ident.version.to_string());
dds_log(debug, "Recording package {}@{}", pkg.ident.name.str, pkg.ident.version.to_string());
auto& store_pkg_st = st_cache(R"(
INSERT OR REPLACE INTO dds_pkgs
(name, version, remote_url, description)
@@ -153,7 +153,7 @@ void do_store_pkg(neo::sqlite3::database& db,
(?, ?, ?, ?)
)"_sql);
nsql::exec(store_pkg_st,
pkg.ident.name,
pkg.ident.name.str,
pkg.ident.version.to_string(),
pkg.remote_pkg.to_url_string(),
pkg.description);
@@ -177,7 +177,11 @@ void do_store_pkg(neo::sqlite3::database& db,
assert(dep.versions.num_intervals() == 1);
auto iv_1 = *dep.versions.iter_intervals().begin();
dds_log(trace, " Depends on: {}", dep.to_string());
nsql::exec(new_dep_st, db_pkg_id, dep.name, iv_1.low.to_string(), iv_1.high.to_string());
nsql::exec(new_dep_st,
db_pkg_id,
dep.name.str,
iv_1.low.to_string(),
iv_1.high.to_string());
}
}

@@ -275,7 +279,7 @@ void pkg_db::store(const pkg_listing& pkg) {

result<pkg_listing> pkg_db::get(const pkg_id& pk_id) const noexcept {
auto ver_str = pk_id.version.to_string();
dds_log(trace, "Lookup package {}@{}", pk_id.name, ver_str);
dds_log(trace, "Lookup package {}@{}", pk_id.name.str, ver_str);
auto& st = _stmt_cache(R"(
SELECT
pkg_id,
@@ -288,7 +292,7 @@ result<pkg_listing> pkg_db::get(const pkg_id& pk_id) const noexcept {
ORDER BY pkg_id DESC
)"_sql);
st.reset();
st.bindings() = std::forward_as_tuple(pk_id.name, ver_str);
st.bindings() = std::forward_as_tuple(pk_id.name.str, ver_str);
auto ec = st.step(std::nothrow);
if (ec == nsql::errc::done) {
return new_error([&] {
@@ -317,7 +321,7 @@ result<pkg_listing> pkg_db::get(const pkg_id& pk_id) const noexcept {
}

neo_assert(invariant,
pk_id.name == name && pk_id.version == semver::version::parse(version),
pk_id.name.str == name && pk_id.version == semver::version::parse(version),
"Package metadata does not match",
pk_id.to_string(),
name,
@@ -364,7 +368,7 @@ std::vector<pkg_id> pkg_db::by_name(std::string_view sv) const noexcept {
}

std::vector<dependency> pkg_db::dependencies_of(const pkg_id& pkg) const noexcept {
dds_log(trace, "Lookup dependencies of {}@{}", pkg.name, pkg.version.to_string());
dds_log(trace, "Lookup dependencies of {}", pkg.to_string());
return nsql::exec_tuples<std::string,
std::string,
std::string>( //
@@ -380,7 +384,7 @@ std::vector<dependency> pkg_db::dependencies_of(const pkg_id& pkg) const noexcep
WHERE pkg_id IN this_pkg_id
ORDER BY dep_name
)"_sql),
pkg.name,
pkg.name.str,
pkg.version.to_string()) //
| neo::lref //
| ranges::views::transform([](auto&& pair) {

+ 4
- 4
src/dds/pkg/db.test.cpp 查看文件

@@ -34,7 +34,7 @@ TEST_CASE_METHOD(pkg_db_test_case, "Store a simple package") {

auto pkgs = db.by_name("foo");
REQUIRE(pkgs.size() == 1);
CHECK(pkgs[0].name == "foo");
CHECK(pkgs[0].name.str == "foo");
CHECK(pkgs[0].version == semver::version::parse("1.2.3"));
auto info = db.get(pkgs[0]);
REQUIRE(info);
@@ -67,9 +67,9 @@ TEST_CASE_METHOD(pkg_db_test_case, "Package requirements") {
});
auto pkgs = db.by_name("foo");
REQUIRE(pkgs.size() == 1);
CHECK(pkgs[0].name == "foo");
CHECK(pkgs[0].name.str == "foo");
auto deps = db.dependencies_of(pkgs[0]);
CHECK(deps.size() == 2);
CHECK(deps[0].name == "bar");
CHECK(deps[1].name == "baz");
CHECK(deps[0].name.str == "bar");
CHECK(deps[1].name.str == "baz");
}

+ 1
- 1
src/dds/pkg/get/dds_http.cpp 查看文件

@@ -32,7 +32,7 @@ dds_http_remote_pkg dds_http_remote_pkg::from_url(const neo::url& url) {

void dds_http_remote_pkg::do_get_raw(path_ref dest) const {
auto http_url = repo_url;
fs::path path = fs::path(repo_url.path) / "pkg" / pkg_id.name / pkg_id.version.to_string()
fs::path path = fs::path(repo_url.path) / "pkg" / pkg_id.name.str / pkg_id.version.to_string()
/ "sdist.tar.gz";
http_url.path = path.lexically_normal().generic_string();
http_remote_pkg http;

+ 1
- 1
src/dds/pkg/get/dds_http.test.cpp 查看文件

@@ -6,7 +6,7 @@ TEST_CASE("Parse a URL") {
auto pkg = dds::dds_http_remote_pkg::from_url(
neo::url::parse("dds+http://foo.bar/repo-dir/egg@1.2.3"));
CHECK(pkg.repo_url.to_string() == "http://foo.bar/repo-dir");
CHECK(pkg.pkg_id.name == "egg");
CHECK(pkg.pkg_id.name.str == "egg");
CHECK(pkg.pkg_id.version.to_string() == "1.2.3");
CHECK(pkg.to_url_string() == "dds+http://foo.bar/repo-dir/egg@1.2.3");
}

+ 6
- 4
src/dds/pkg/id.cpp 查看文件

@@ -10,21 +10,23 @@
using namespace dds;

pkg_id pkg_id::parse(const std::string_view s) {
DDS_E_SCOPE(e_invalid_pkg_id_str{std::string(s)});
DDS_E_SCOPE(e_pkg_id_str{std::string(s)});
auto at_pos = s.find('@');
if (at_pos == s.npos) {
BOOST_LEAF_THROW_EXCEPTION(
make_user_error<errc::invalid_pkg_id>("Package ID must contain an '@' symbol"));
}

auto name = s.substr(0, at_pos);
auto name = *dds::name::from_string(s.substr(0, at_pos));
auto ver_str = s.substr(at_pos + 1);

try {
return {std::string(name), semver::version::parse(ver_str)};
return {name, semver::version::parse(ver_str)};
} catch (const semver::invalid_version& err) {
BOOST_LEAF_THROW_EXCEPTION(make_user_error<errc::invalid_pkg_id>(), err);
}
}

std::string pkg_id::to_string() const noexcept { return name + "@" + version.to_string(); }
std::string pkg_id::to_string() const noexcept {
return fmt::format("{}@{}", name.str, version.to_string());
}

+ 4
- 2
src/dds/pkg/id.hpp 查看文件

@@ -1,5 +1,7 @@
#pragma once

#include "./name.hpp"

#include <semver/version.hpp>

#include <string>
@@ -8,7 +10,7 @@

namespace dds {

struct e_invalid_pkg_id_str {
struct e_pkg_id_str {
std::string value;
};

@@ -21,7 +23,7 @@ struct e_invalid_pkg_id_str {
*/
struct pkg_id {
/// The name of the package
std::string name;
dds::name name;
/// The version of the package
semver::version version;


+ 1
- 1
src/dds/pkg/id.test.cpp 查看文件

@@ -16,7 +16,7 @@ TEST_CASE("Package package ID strings") {

auto pk_id = dds::pkg_id::parse(id_str);
CHECK(pk_id.to_string() == id_str);
CHECK(pk_id.name == exp_name);
CHECK(pk_id.name.str == exp_name);
CHECK(pk_id.version.to_string() == exp_ver);
}


+ 73
- 0
src/dds/pkg/name.cpp 查看文件

@@ -0,0 +1,73 @@
#include "./name.hpp"

#include <dds/error/on_error.hpp>
#include <dds/error/result.hpp>

#include <neo/assert.hpp>

#include <ctre.hpp>

using namespace dds;

using err_reason = invalid_name_reason;

static err_reason calc_invalid_name_reason(std::string_view str) noexcept {
constexpr ctll::fixed_string capital_re = "[A-Z]";
constexpr ctll::fixed_string double_punct = "[._\\-]{2}";
constexpr ctll::fixed_string end_punct = "[._\\-]$";
constexpr ctll::fixed_string ws = "\\s";
constexpr ctll::fixed_string invalid_chars = "[^a-z0-9._\\-]";
if (str.empty()) {
return err_reason::empty;
} else if (ctre::search<capital_re>(str)) {
return err_reason::capital;
} else if (ctre::search<double_punct>(str)) {
return err_reason::double_punct;
} else if (str[0] < 'a' || str[0] > 'z') {
return err_reason::initial_not_alpha;
} else if (ctre::search<end_punct>(str)) {
return err_reason::end_punct;
} else if (ctre::search<ws>(str)) {
return err_reason::whitespace;
} else if (ctre::search<invalid_chars>(str)) {
return err_reason::invalid_char;
} else {
neo_assert(invariant,
false,
"Expected to be able to determine an error-reason for the given invalid name",
str);
}
}

std::string_view dds::invalid_name_reason_str(err_reason e) noexcept {
switch (e) {
case err_reason::capital:
return "Uppercase letters are not valid in package names";
case err_reason::double_punct:
return "Adjacent punctuation characters are not valid in package names";
case err_reason::end_punct:
return "Names must not end with a punctuation character";
case err_reason::whitespace:
return "Names must not contain whitespace";
case err_reason::invalid_char:
return "Name contains an invalid character";
case err_reason::initial_not_alpha:
return "Name must begin with a lowercase alphabetic character";
case err_reason::empty:
return "Name cannot be empty";
}
neo::unreachable();
}

result<name> name::from_string(std::string_view str) noexcept {
constexpr ctll::fixed_string name_re = "^([a-z][a-z0-9]*)([._\\-][a-z0-9]+)*$";

auto mat = ctre::match<name_re>(str);

if (!mat) {
return new_error(DDS_E_ARG(e_name_str{std::string(str)}),
DDS_E_ARG(calc_invalid_name_reason(str)));
}

return name{std::string(str)};
}

+ 36
- 0
src/dds/pkg/name.hpp 查看文件

@@ -0,0 +1,36 @@
#pragma once

#include <dds/error/result_fwd.hpp>

#include <string>

namespace dds {

enum class invalid_name_reason {
empty,
capital,
initial_not_alpha,
double_punct,
end_punct,
invalid_char,
whitespace,
};

struct e_name_str {
std::string value;
};

std::string_view invalid_name_reason_str(invalid_name_reason) noexcept;

struct name {
std::string str;

// Parse a package name, ensuring it is a valid package name string
static result<name> from_string(std::string_view str) noexcept;

bool operator==(const name& o) const noexcept { return str == o.str; }
bool operator!=(const name& o) const noexcept { return str != o.str; }
bool operator<(const name& o) const noexcept { return str < o.str; }
};

} // namespace dds

+ 72
- 0
src/dds/pkg/name.test.cpp 查看文件

@@ -0,0 +1,72 @@
#include "./name.hpp"

#include <dds/error/result.hpp>

#include <boost/leaf/handle_error.hpp>

#include <catch2/catch.hpp>

TEST_CASE("Try some invalid names") {
using reason = dds::invalid_name_reason;
struct case_ {
std::string_view invalid_name;
dds::invalid_name_reason error;
};
auto given = GENERATE(Catch::Generators::values<case_>({
{"", reason::empty},

{"H", reason::capital},
{"heLlo", reason::capital},
{"eGGG", reason::capital},
{"e0131F-gg", reason::capital},

{"-foo", reason::initial_not_alpha},
{"123", reason::initial_not_alpha},
{"123-bar", reason::initial_not_alpha},
{" fooo", reason::initial_not_alpha},

{"foo..bar", reason::double_punct},
{"foo-.bar", reason::double_punct},
{"foo-_bar", reason::double_punct},
{"foo__bar", reason::double_punct},
{"foo_.bar", reason::double_punct},

{"foo.", reason::end_punct},
{"foo.bar_", reason::end_punct},
{"foo.bar-", reason::end_punct},

{"foo ", reason::whitespace},
{"foo bar", reason::whitespace},
{"foo\nbar", reason::whitespace},

{"foo&bar", reason::invalid_char},
{"foo+baz", reason::invalid_char},
}));

boost::leaf::context<reason> err_ctx;
err_ctx.activate();
CAPTURE(given.invalid_name);
auto res = dds::name::from_string(given.invalid_name);
err_ctx.deactivate();
CHECKED_IF(!res) {
err_ctx.handle_error<void>(
res.error(),
[&](reason r) { CHECK(r == given.error); },
[] { FAIL_CHECK("No error reason was given"); });
}
}

TEST_CASE("Try some valid names") {
auto given = GENERATE(Catch::Generators::values<std::string_view>({
"hi",
"dog",
"foo.bar",
"foo-bar_bark",
"foo-bar-baz",
"foo-bar.quz",
"q",
}));

auto res = dds::name::from_string(given);
CHECK(res->str == given);
}

+ 7
- 8
src/dds/repoman/repoman.cpp 查看文件

@@ -149,8 +149,7 @@ void repo_manager::import_targz(path_ref tgz_file) {
DDS_E_SCOPE(man->id);

neo::sqlite3::transaction_guard tr{_db};

dds_log(debug, "Recording package {}@{}", man->id.name, man->id.version.to_string());
dds_log(debug, "Recording package {}", man->id.to_string());
dds::pkg_listing info{.ident = man->id,
.deps = man->dependencies,
.description = "[No description]",
@@ -158,7 +157,7 @@ void repo_manager::import_targz(path_ref tgz_file) {
auto rel_url = fmt::format("dds:{}", man->id.to_string());
add_pkg(info, rel_url);

auto dest_path = pkg_dir() / man->id.name / man->id.version.to_string() / "sdist.tar.gz";
auto dest_path = pkg_dir() / man->id.name.str / man->id.version.to_string() / "sdist.tar.gz";
fs::create_directories(dest_path.parent_path());
fs::copy(tgz_file, dest_path);

@@ -176,11 +175,11 @@ void repo_manager::delete_package(pkg_id pkg_id) {
WHERE name = ?
AND version = ?
)"_sql),
pkg_id.name,
pkg_id.name.str,
pkg_id.version.to_string());
/// XXX: Verify with _db.changes() that we actually deleted one row

auto name_dir = pkg_dir() / pkg_id.name;
auto name_dir = pkg_dir() / pkg_id.name.str;
auto ver_dir = name_dir / pkg_id.version.to_string();

DDS_E_SCOPE(e_repo_delete_path{ver_dir});
@@ -210,7 +209,7 @@ void repo_manager::add_pkg(const pkg_listing& info, std::string_view url) {
INSERT INTO dds_repo_packages (name, version, description, url)
VALUES (?, ?, ?, ?)
)"_sql),
info.ident.name,
info.ident.name.str,
info.ident.version.to_string(),
info.description,
url);
@@ -227,12 +226,12 @@ void repo_manager::add_pkg(const pkg_listing& info, std::string_view url) {
dds_log(trace, " Depends on: {}", dep.to_string());
nsql::exec(insert_dep_st,
package_rowid,
dep.name,
dep.name.str,
iv_1.low.to_string(),
iv_1.high.to_string());
}

auto dest_dir = pkg_dir() / info.ident.name / info.ident.version.to_string();
auto dest_dir = pkg_dir() / info.ident.name.str / info.ident.version.to_string();
auto stamp_path = dest_dir / "url.txt";
fs::create_directories(dest_dir);
std::ofstream stamp_file{stamp_path, std::ios::binary};

+ 7
- 2
src/dds/sdist/library/manifest.cpp 查看文件

@@ -2,6 +2,8 @@

#include <dds/dym.hpp>
#include <dds/error/errors.hpp>
#include <dds/error/on_error.hpp>
#include <dds/error/result.hpp>
#include <dds/util/algo.hpp>

#include <json5/parse_data.hpp>
@@ -11,6 +13,8 @@
using namespace dds;

library_manifest library_manifest::load_from_file(path_ref fpath) {
DDS_E_SCOPE(e_library_manifest_path{fpath.string()});

auto content = slurp_file(fpath);
auto data = json5::parse_data(content);

@@ -27,7 +31,7 @@ library_manifest library_manifest::load_from_file(path_ref fpath) {
mapping{
if_key{"name",
require_type<std::string>{"`name` must be a string"},
put_into{lib.name}},
put_into{lib.name.str}},
if_key{"uses",
require_type<json5::data::array_type>{
"`uses` must be an array of usage requirements"},
@@ -54,10 +58,11 @@ library_manifest library_manifest::load_from_file(path_ref fpath) {
throw_user_error<errc::invalid_lib_manifest>(rej->message);
}

if (lib.name.empty()) {
if (lib.name.str.empty()) {
throw_user_error<errc::invalid_lib_manifest>(
"The 'name' field is required (Reading library manifest [{}])", fpath.string());
}
lib.name = *dds::name::from_string(lib.name.str);

return lib;
}

+ 6
- 1
src/dds/sdist/library/manifest.hpp 查看文件

@@ -1,5 +1,6 @@
#pragma once

#include <dds/pkg/name.hpp>
#include <dds/util/fs.hpp>

#include <libman/library.hpp>
@@ -8,6 +9,10 @@

namespace dds {

struct e_library_manifest_path {
std::string value;
};

/**
* Represents the contents of a `library.json5`. This is somewhat a stripped-down
* version of lm::library, to only represent exactly the parts that we want to
@@ -15,7 +20,7 @@ namespace dds {
*/
struct library_manifest {
/// The name of the library
std::string name;
dds::name name;
/// The libraries that the owning library "uses"
std::vector<lm::usage> uses;
/// The libraries that the owning library must be linked with

+ 9
- 2
src/dds/sdist/library/root.cpp 查看文件

@@ -2,6 +2,7 @@

#include <dds/build/plan/compile_file.hpp>
#include <dds/error/errors.hpp>
#include <dds/error/result.hpp>
#include <dds/sdist/root.hpp>
#include <dds/util/algo.hpp>
#include <dds/util/log.hpp>
@@ -60,10 +61,16 @@ library_root library_root::from_directory(path_ref lib_dir) {
auto sources = collect_pf_sources(lib_dir);

library_manifest man;
man.name = lib_dir.filename().string();
auto found = library_manifest::find_in_directory(lib_dir);
auto found = library_manifest::find_in_directory(lib_dir);
if (found) {
man = library_manifest::load_from_file(*found);
} else {
auto name_from_dir = dds::name::from_string(lib_dir.filename().string());
if (!name_from_dir) {
man.name.str = "unnamed";
} else {
man.name = *name_from_dir;
}
}

auto lib = library_root(lib_dir, std::move(sources), std::move(man));

+ 12
- 2
src/dds/sdist/package.cpp 查看文件

@@ -52,11 +52,19 @@ package_manifest parse_json(const json5::data& data, std::string_view fpath) {
required_key{"name",
"A string 'name' is required",
require_str{"'name' must be a string"},
put_into{ret.id.name}},
put_into{ret.id.name,
[](std::string s) {
DDS_E_SCOPE(e_pkg_name_str{s});
return *dds::name::from_string(s);
}}},
required_key{"namespace",
"A string 'namespace' is a required ",
require_str{"'namespace' must be a string"},
put_into{ret.namespace_}},
put_into{ret.namespace_,
[](std::string s) {
DDS_E_SCOPE(e_pkg_namespace_str{s});
return *dds::name::from_string(s);
}}},
required_key{"version",
"A 'version' string is requried",
require_str{"'version' must be a string"},
@@ -104,12 +112,14 @@ package_manifest parse_json(const json5::data& data, std::string_view fpath) {
} // namespace

package_manifest package_manifest::load_from_file(const fs::path& fpath) {
DDS_E_SCOPE(e_package_manifest_path{fpath.string()});
auto content = slurp_file(fpath);
return load_from_json5_str(content, fpath.string());
}

package_manifest package_manifest::load_from_json5_str(std::string_view content,
std::string_view input_name) {
DDS_E_SCOPE(e_package_manifest_path{std::string(input_name)});
try {
auto data = json5::parse_data(content);
return parse_json(data, input_name);

+ 14
- 2
src/dds/sdist/package.hpp 查看文件

@@ -19,14 +19,26 @@ enum class test_lib {
catch_main,
};

struct e_package_manifest_path {
std::string value;
};

struct e_pkg_name_str {
std::string value;
};

struct e_pkg_namespace_str {
std::string value;
};

/**
* Struct representing the contents of a `packaeg.dds` file.
* Struct representing the contents of a `package.json5` file.
*/
struct package_manifest {
/// The package ID, as determined by `Name` and `Version` together
dds::pkg_id id;
/// The declared `Namespace` of the package. This directly corresponds with the libman Namespace
std::string namespace_;
name namespace_;
/// The `test_driver` that this package declares, or `nullopt` if absent.
std::optional<test_lib> test_driver;
/// The dependencies declared with the `Depends` fields, if any.

+ 4
- 4
src/dds/solve/solve.cpp 查看文件

@@ -66,7 +66,7 @@ struct req_type {
auto as_pkg_id(const req_type& req) {
const version_range_set& versions = req.dep.versions;
assert(versions.num_intervals() == 1);
return pkg_id{req.dep.name, (*versions.iter_intervals().begin()).low};
return pkg_id{req.dep.name.str, (*versions.iter_intervals().begin()).low};
}

struct solver_provider {
@@ -78,10 +78,10 @@ struct solver_provider {
std::optional<req_type> best_candidate(const req_type& req) const {
dds_log(debug, "Find best candidate of {}", req.dep.to_string());
// Look up in the cachce for the packages we have with the given name
auto found = pkgs_by_name.find(req.dep.name);
auto found = pkgs_by_name.find(req.dep.name.str);
if (found == pkgs_by_name.end()) {
// If it isn't there, insert an entry in the cache
found = pkgs_by_name.emplace(req.dep.name, pkgs_for_name(req.dep.name)).first;
found = pkgs_by_name.emplace(req.dep.name.str, pkgs_for_name(req.dep.name.str)).first;
}
// Find the first package with the version contained by the ranges in the requirement
auto& for_name = found->second;
@@ -99,7 +99,7 @@ struct solver_provider {
std::vector<req_type> requirements_of(const req_type& req) const {
dds_log(trace,
"Lookup requirements of {}@{}",
req.key(),
req.key().str,
(*req.dep.versions.iter_intervals().begin()).low.to_string());
auto pk_id = as_pkg_id(req);
auto deps = deps_for_pkg(pk_id);

+ 0
- 4
src/dds/util/result.hpp 查看文件

@@ -50,10 +50,6 @@ struct e_url_string {
std::string value;
};

struct e_human_message {
std::string value;
};

struct e_missing_file {
std::filesystem::path path;
};

+ 51
- 4
tests/test_basics.py 查看文件

@@ -45,14 +45,14 @@ def test_simple_lib(tmp_project: Project) -> None:
"""
tmp_project.write('src/foo.cpp', 'int the_answer() { return 42; }')
tmp_project.package_json = {
'name': 'TestProject',
'name': 'test-project',
'version': '0.0.0',
'namespace': 'test',
}
tmp_project.library_json = {'name': 'TestLibrary'}
tmp_project.library_json = {'name': 'test-library'}
tmp_project.build()
assert (tmp_project.build_root / 'compile_commands.json').is_file()
assert list(tmp_project.build_root.glob('libTestLibrary.*')) != []
assert (tmp_project.build_root / 'compile_commands.json').is_file(), 'compdb was not created'
assert list(tmp_project.build_root.glob('libtest-library.*')) != [], 'No archive was created'


def test_lib_with_just_test(tmp_project: Project) -> None:
@@ -67,6 +67,53 @@ def test_lib_with_failing_test(tmp_project: Project) -> None:
tmp_project.build()


def test_invalid_names(tmp_project: Project) -> None:
tmp_project.package_json = {
'name': 'test',
'version': '1.2.3',
'namespace': 'test',
'depends': ['invalid name@1.2.3']
}
with expect_error_marker('invalid-pkg-dep-name'):
tmp_project.build()
with expect_error_marker('invalid-pkg-dep-name'):
tmp_project.pkg_create()
with expect_error_marker('invalid-pkg-dep-name'):
tmp_project.dds.build_deps(['invalid name@1.2.3'])

tmp_project.package_json = {
**tmp_project.package_json,
'name': 'invalid name',
'depends': [],
}
with expect_error_marker('invalid-pkg-name'):
tmp_project.build()
with expect_error_marker('invalid-pkg-name'):
tmp_project.pkg_create()

tmp_project.package_json = {
**tmp_project.package_json,
'name': 'simple_name',
'namespace': 'invalid namespace',
}
with expect_error_marker('invalid-pkg-namespace-name'):
tmp_project.build()
with expect_error_marker('invalid-pkg-namespace-name'):
tmp_project.pkg_create()

tmp_project.package_json = {
'name': 'test',
'version': '1.2.3',
'namespace': 'test',
'depends': [],
}
tmp_project.library_json = {'name': 'invalid name'}
# Need a source directory for dds to load the lib manifest
tmp_project.write('src/empty.hpp', '')
with expect_error_marker('invalid-lib-name'):
tmp_project.build()


TEST_PACKAGE: PackageJSON = {
'name': 'test-pkg',
'version': '0.2.2',

+ 29
- 0
tests/test_pkg_db.py 查看文件

@@ -1,3 +1,5 @@
import json

from dds_ci.dds import DDSWrapper
from dds_ci.testing import Project, RepoServer, PackageJSON
from dds_ci.testing.error import expect_error_marker
@@ -70,3 +72,30 @@ def test_pkg_search(_test_repo: RepoServer, tmp_project: Project) -> None:
dds.run(['pkg', dds.pkg_db_path_arg, 'search', 'neo-*'])
with expect_error_marker('pkg-search-no-result'):
dds.run(['pkg', dds.pkg_db_path_arg, 'search', 'nonexistent'])


def test_pkg_cache_invalid_nofail(tmp_project: Project) -> None:
"""
Check that dds will not fail a build just because the package cache has an invalid
object within.
"""
sdist_dir = tmp_project.dds.repo_dir / 'bad@1.2.3'
sdist_dir.mkdir(parents=True)
tmp_project.build()

# Write an invalid source distribution
pkman_path = sdist_dir / 'package.json5'
pkman_path.write_text(json.dumps({}))
tmp_project.build()

pkman_path.write_text('lol') # Inavlid JSON
tmp_project.build()

pkman_path.write_text('''
{
name: 'invalid name',
namespace: 'test',
version: '1.2.3'
}
''')
tmp_project.build()

Loading…
取消
儲存