浏览代码

library.json manifest format

default_compile_flags
vector-of-bool 4 年前
父节点
当前提交
2055f4a01c
共有 10 个文件被更改,包括 190 次插入32 次删除
  1. +15
    -0
      library.jsonc
  2. +34
    -0
      res/library-schema.json
  3. +2
    -2
      res/package-schema.json
  4. +13
    -8
      src/dds/error/errors.cpp
  5. +1
    -0
      src/dds/error/errors.hpp
  6. +79
    -4
      src/dds/library/manifest.cpp
  7. +10
    -1
      src/dds/library/manifest.hpp
  8. +8
    -4
      src/dds/library/root.cpp
  9. +5
    -5
      src/dds/package/manifest.cpp
  10. +23
    -8
      src/dds/util/json5_read.hpp

+ 15
- 0
library.jsonc 查看文件

@@ -0,0 +1,15 @@
{
"$schema": "./res/library-schema.json",
"name": "dds",
"uses": [
"spdlog/spdlog",
"Microsoft/wil",
"range-v3/range-v3",
"nlohmann/json",
"neo/sqlite3",
"neo/fun",
"semver/semver",
"pubgrub/pubgrub",
"vob/json5"
]
}

+ 34
- 0
res/library-schema.json 查看文件

@@ -0,0 +1,34 @@
{
"type": "object",
"description": "DDS Library Manifest",
"additionalProperties": false,
"patternProperties": {
"^\\$": {}
},
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"description": "The name of the library within the package.",
"pattern": "^[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*$"
},
"uses": {
"type": "array",
"items": {
"type": "string",
"description": "A library that is used by this library. Should be of the form `namespace/name`.",
"pattern": "^[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*/[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*$"
}
},
"links": {
"type": "array",
"items": {
"type": "string",
"description": "A library that is linked to this library. Should be of the form `namespace/name`.",
"pattern": "^[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*/[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*$"
}
}
}
}

+ 2
- 2
res/package-schema.json 查看文件

@@ -13,13 +13,13 @@
"properties": {
"name": {
"type": "string",
"description": "The name of the package. Must be a valid Semantic Version string.",
"description": "The name of the package",
"pattern": "^[a-z][a-z0-9_]*((\\.|-)[a-z0-9_]+)*$"
},
"version": {
"type": "string",
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$",
"description": "The version of the package. Required",
"description": "The version of the package. Must be a valid Semantic Version string.",
"default": "0.1.0"
},
"namespace": {

+ 13
- 8
src/dds/error/errors.cpp 查看文件

@@ -41,6 +41,8 @@ std::string error_url_suffix(dds::errc ec) noexcept {
return "sdist-ident-mismatch.html";
case errc::corrupted_build_db:
return "corrupted-build-db.html";
case errc::invalid_lib_manifest:
return "invalid-lib-manifest.html";
case errc::invalid_pkg_manifest:
return "invalid-pkg-manifest.html";
case errc::invalid_version_range_string:
@@ -141,6 +143,11 @@ modified by a newer version of dds?
The catalog database schema doesn't match what dds expects. This indicates that
the database file has been modified in a way that dds cannot automatically fix
and handle.
)";
case errc::invalid_lib_manifest:
return R"(
A library manifest is malformed Refer to the documentation and above error
message for more details.
)";
case errc::invalid_pkg_manifest:
return R"(
@@ -273,6 +280,8 @@ std::string_view dds::default_error_string(dds::errc ec) noexcept {
"that was expected of it";
case errc::corrupted_build_db:
return "The build database file is corrupted";
case errc::invalid_lib_manifest:
return "The library manifest is invalid";
case errc::invalid_pkg_manifest:
return "The package manifest is invalid";
case errc::invalid_version_range_string:
@@ -280,17 +289,14 @@ std::string_view dds::default_error_string(dds::errc ec) noexcept {
"`dds` bug. Please report it.)";
case errc::invalid_version_string:
return "Attempted to parse an invalid version string. <- (Seeing this text is a `dds` "
"bug. "
"Please report it.)";
"bug. Please report it.)";
case errc::invalid_config_key:
return "Found an invalid configuration key. <- (Seeing this text is a `dds` bug. "
"Please "
"report it.)";
"Please report it.)";
case errc::invalid_lib_filesystem:
case errc::invalid_pkg_filesystem:
return "The filesystem structure of the package/library is invalid. <- (Seeing this "
"text "
"is a `dds` bug. Please report it.)";
"text is a `dds` bug. Please report it.)";
case errc::invalid_pkg_id:
return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please "
"report it.)";
@@ -299,8 +305,7 @@ std::string_view dds::default_error_string(dds::errc ec) noexcept {
"it.)";
case errc::sdist_exists:
return "The source ditsribution already exists at the destination <- (Seeing this "
"text is "
"a `dds` bug. Please report it.)";
"text is a `dds` bug. Please report it.)";
case errc::unknown_test_driver:
return "The specified Test-Driver is not known to `dds`";
case errc::dependency_resolve_failure:

+ 1
- 0
src/dds/error/errors.hpp 查看文件

@@ -29,6 +29,7 @@ enum class errc {

corrupted_build_db,

invalid_lib_manifest,
invalid_pkg_manifest,
invalid_version_range_string,
invalid_version_string,

+ 79
- 4
src/dds/library/manifest.cpp 查看文件

@@ -1,16 +1,21 @@
#include "./manifest.hpp"

#include <dds/dym.hpp>
#include <dds/error/errors.hpp>
#include <dds/util/algo.hpp>
#include <range/v3/view/transform.hpp>

#include <dds/util/json5_read.hpp>
#include <libman/parse.hpp>

#include <spdlog/fmt/fmt.h>
#include <json5/parse_data.hpp>
#include <range/v3/view/transform.hpp>
#include <spdlog/spdlog.h>

using namespace dds;

library_manifest library_manifest::load_from_file(const fs::path& fpath) {
library_manifest library_manifest::load_from_dds_file(path_ref fpath) {
spdlog::warn(
"Using deprecated library.dds parsing (on file {}). This will be removed soon. Migrate!",
fpath.string());
auto kvs = lm::parse_file(fpath);
library_manifest ret;
ret.name = fpath.parent_path().filename().string();
@@ -27,3 +32,73 @@ library_manifest library_manifest::load_from_file(const fs::path& fpath) {
extend(ret.links, ranges::views::transform(links_strings, lm::split_usage_string));
return ret;
}

library_manifest library_manifest::load_from_file(path_ref fpath) {
auto content = slurp_file(fpath);
auto data = json5::parse_data(content);

if (!data.is_object()) {
throw_user_error<errc::invalid_lib_manifest>("Root value must be an object");
}

library_manifest lib;
using namespace json_read::ops;
json_read::decompose( //
data.as_object(),
object(key("name", require_string(put_into{lib.name}, "`name` must be a string")),
key("uses",
array_each{require_string(
[&](auto&& uses) {
lib.uses.push_back(lm::split_usage_string(uses.as_string()));
return json_read::accept_t{};
},
"All `uses` items must be strings")}),
key("links",
array_each{require_string(
[&](auto&& links) {
lib.links.push_back(lm::split_usage_string(links.as_string()));
return json_read::accept_t{};
},
"All `links` items must be strings")})));

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

return lib;
}

std::optional<fs::path> library_manifest::find_in_directory(path_ref dirpath) {
auto fnames = {
"library.json5",
"library.jsonc",
"library.json",
};
for (auto c : fnames) {
auto cand = dirpath / c;
if (fs::is_regular_file(cand)) {
return cand;
}
}

auto dds_file = dirpath / "library.dds";
if (fs::is_regular_file(dds_file)) {
return dds_file;
}

return std::nullopt;
}

std::optional<library_manifest> library_manifest::load_from_directory(path_ref dirpath) {
auto found = find_in_directory(dirpath);
if (!found.has_value()) {
return std::nullopt;
}

if (found->extension() == ".dds") {
return load_from_dds_file(*found);
} else {
return load_from_file(*found);
}
}

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

@@ -24,7 +24,16 @@ struct library_manifest {
/**
* Load the library manifest from an existing file
*/
static library_manifest load_from_file(const fs::path&);
static library_manifest load_from_file(path_ref);
static library_manifest load_from_dds_file(path_ref);

/**
* Find a library manifest within a directory. This will search for a few
* file candidates and return the result from the first matching. If none
* match, it will return nullopt.
*/
static std::optional<fs::path> find_in_directory(path_ref);
static std::optional<library_manifest> load_from_directory(path_ref);
};

} // namespace dds

+ 8
- 4
src/dds/library/root.cpp 查看文件

@@ -55,10 +55,14 @@ 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 man_path = lib_dir / "library.dds";
if (fs::is_regular_file(man_path)) {
man = library_manifest::load_from_file(man_path);
man.name = lib_dir.filename().string();
auto found = library_manifest::find_in_directory(lib_dir);
if (found) {
if (found->extension() == ".dds") {
man = library_manifest::load_from_dds_file(*found);
} else {
man = library_manifest::load_from_file(*found);
}
}

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

+ 5
- 5
src/dds/package/manifest.cpp 查看文件

@@ -81,8 +81,8 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) {
const auto& obj = data.as_object();
package_manifest ret;

using namespace j5_read::ops;
j5_read::destructure(
using namespace json_read::ops;
json_read::decompose(
obj,
object(
key("name", require_string(put_into{ret.pkg_id.name}, "`name` must be a string")),
@@ -94,7 +94,7 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) {
[&](auto&& version_str_) {
auto& version = version_str_.as_string();
ret.pkg_id.version = semver::version::parse(version);
return j5_read::accept_t{};
return json_read::accept_t{};
},
"`version` must be a string")),
key("depends", object([&](auto key, auto&& range_str_) {
@@ -113,7 +113,7 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) {
range_str_.as_string(),
pkg_name);
}
return j5_read::accept_t{};
return json_read::accept_t{};
})),
key("test_driver",
require_string(
@@ -130,7 +130,7 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) {
test_driver,
dym);
}
return j5_read::accept_t{};
return json_read::accept_t{};
},
"`test_driver` must be a valid test driver name string")),
reject_key));

+ 23
- 8
src/dds/util/json5_read.hpp 查看文件

@@ -7,7 +7,7 @@

namespace dds {

namespace j5_read {
namespace json_read {

struct reject_t {
std::string message;
@@ -51,9 +51,6 @@ struct then {
}
};

template <typename... Hs>
then(Hs...) -> then<Hs...>;

template <typename... KeyHandlers>
struct object {
std::tuple<KeyHandlers...> _keys;
@@ -92,8 +89,26 @@ struct object {
}
};

template <typename... Ks>
object(Ks...) -> object<Ks...>;
template <typename Handler>
struct array_each {
Handler _hs;

result_var operator()(const json5::data& arr) {
if (!arr.is_array()) {
return pass_t{};
}
for (const auto& elem : arr.as_array()) {
result_var res = _hs(elem);
if (std::holds_alternative<reject_t>(res)) {
return res;
}
}
return accept_t{};
}
};

template <typename Handler>
array_each(Handler) -> array_each<Handler>;

template <typename Handler>
struct key {
@@ -172,13 +187,13 @@ put_into(T) -> put_into<T>;
} // namespace ops

template <typename Handler>
auto destructure(const json5::data& dat, Handler&& h) {
auto decompose(const json5::data& dat, Handler&& h) {
result_var res = h(dat);
if (std::holds_alternative<reject_t>(res)) {
throw std::runtime_error(std::get<reject_t>(res).message);
}
}

} // namespace j5_read
} // namespace json_read

} // namespace dds

正在加载...
取消
保存