"ref": "0.1.0", | "ref": "0.1.0", | ||||
"url": "https://github.com/vector-of-bool/json5.git" | "url": "https://github.com/vector-of-bool/json5.git" | ||||
} | } | ||||
}, | |||||
"0.1.2": { | |||||
"depends": {}, | |||||
"description": "A C++ implementation of a JSON5 parser", | |||||
"git": { | |||||
"auto-lib": null, | |||||
"ref": "0.1.2", | |||||
"url": "https://github.com/vector-of-bool/json5.git" | |||||
} | |||||
} | } | ||||
}, | }, | ||||
"ms-wil": { | "ms-wil": { |
The "namespace" of a library in this case is arbitrary and not necessarily | The "namespace" of a library in this case is arbitrary and not necessarily | ||||
associated with any C++ ``namespace``. | associated with any C++ ``namespace``. | ||||
If more than one library declares itself to have the same ``Name`` and lives in | |||||
the same ``Namespace``, ``dds`` will issue an error. | |||||
If more than one library declares itself to have the same ``name`` and lives in | |||||
the same ``namespace``, ``dds`` will issue an error. | |||||
To avoid this error in your own project and to avoid causing this error in your | To avoid this error in your own project and to avoid causing this error in your | ||||
downstream consumers, the ``Namespace`` of your package should be considered | |||||
carefully and be unique. Do not use a ``Namespace`` that is likely to be used | |||||
downstream consumers, the ``namespace`` of your package should be considered | |||||
carefully and be unique. Do not use a ``namespace`` that is likely to be used | |||||
by another developer or organization, especially generic names. | by another developer or organization, especially generic names. | ||||
If you are seeing this issue and it names a library that you do not own, it | If you are seeing this issue and it names a library that you do not own, it | ||||
means that two or more of your dependencies are attempting to declare a library | means that two or more of your dependencies are attempting to declare a library | ||||
of the same ``Name`` in the same ``Namespace``. This issue should be raised | |||||
of the same ``name`` in the same ``namespace``. This issue should be raised | |||||
with the maintainers of the packages in question. | with the maintainers of the packages in question. | ||||
.. seealso:: | .. seealso:: |
and is thoroughly explained on the :doc:`/guide/packages` page. | and is thoroughly explained on the :doc:`/guide/packages` page. | ||||
For exporting/generating a source distribution from a package, the *package | For exporting/generating a source distribution from a package, the *package | ||||
root* requires a ``package.dds`` file and each *library root* requires a | |||||
root* requires a ``package.json5`` file and each *library root* requires a | |||||
``library.dds`` file. | ``library.dds`` file. | ||||
.. . | .. . |
Error: Invalid package manifest | |||||
############################### | |||||
Every ``dds`` package must contain a valid package manifest, which is stored in | |||||
JSON5 format in ``package.json5`` (or similarly named file). | |||||
The contents of this file must follow a prescribed content, or ``dds`` will | |||||
reject the manifest. Refer to the :ref:`pkgs.pkgs` documentation page for more | |||||
information about how to declare packages. |
A library can declare that it *uses* or *links* to another library by using the | A library can declare that it *uses* or *links* to another library by using the | ||||
``Uses`` and ``Links`` keys in ``library.dds``, respectively. | ``Uses`` and ``Links`` keys in ``library.dds``, respectively. | ||||
These requirements are specified by using the ``Namespace/Name`` pair that | |||||
These requirements are specified by using the ``namespace/name`` pair that | |||||
identifies a library. These are defined by both the project's dependencies and | identifies a library. These are defined by both the project's dependencies and | ||||
the project itself. If a ``Uses`` or ``Links`` key does not correspond to a | the project itself. If a ``Uses`` or ``Links`` key does not correspond to a | ||||
known library, ``dds`` will not be able to resolve the usage requirements, and | known library, ``dds`` will not be able to resolve the usage requirements, and |
dds catalog add <package-id> | dds catalog add <package-id> | ||||
[--depends <requirement> [--depends <requirement> [...]]] | [--depends <requirement> [--depends <requirement> [...]]] | ||||
[--git-url <url> --git-ref <ref>] | [--git-url <url> --git-ref <ref>] | ||||
[--auto-lib <Namespace>/<Name>] | |||||
[--auto-lib <namespace>/<name>] | |||||
The ``<package-id>`` positional arguments is the ``name@version`` package ID | The ``<package-id>`` positional arguments is the ``name@version`` package ID | ||||
that will be added to the catalog. The following options are supported: | that will be added to the catalog. The following options are supported: | ||||
``--depends <requirement>`` | ``--depends <requirement>`` | ||||
This argument, which can be specified multiple times to represent multiple | This argument, which can be specified multiple times to represent multiple | ||||
dependencies, sets the dependencies of the package within the catalog. If | dependencies, sets the dependencies of the package within the catalog. If | ||||
the obtained package root contains a ``package.dds``, then the dependencies | |||||
listed here must be identical to those listed in ``package.dds``, or | |||||
dependency resolution may yield unexpected results. | |||||
the obtained package root contains a ``package.json5``, then the | |||||
dependencies listed here must be identical to those listed in | |||||
``package.json5``, or dependency resolution may yield unexpected results. | |||||
``--git-url <url>`` | ``--git-url <url>`` | ||||
Specify a Git URL to clone from to obtain the package. The root of the | Specify a Git URL to clone from to obtain the package. The root of the | ||||
cloned repository must be a package root, but does not necessarily need to | cloned repository must be a package root, but does not necessarily need to | ||||
have the ``package.dds`` and ``library.dds`` files if relying on the | |||||
have the ``package.json5`` and ``library.dds`` files if relying on the | |||||
``--auto-lib`` parameter. | ``--auto-lib`` parameter. | ||||
``--git-ref`` **must** be passed with ``--git-url``. | ``--git-ref`` **must** be passed with ``--git-url``. | ||||
can only be specified for packages that contain a single library root at | can only be specified for packages that contain a single library root at | ||||
the package root. | the package root. | ||||
The form of the argument is that of ``<Namespapce>/<Name>``, where | |||||
``Namespace`` and ``Name`` are the usage requirement keys that should be | |||||
The form of the argument is that of ``<namespace>/<name>``, where | |||||
``namespace`` and ``name`` are the usage requirement keys that should be | |||||
generated for the library. | generated for the library. | ||||
******************** | ******************** | ||||
Consider that we are creating a package ``acme-gadgets@4.3.6``. We declare the | Consider that we are creating a package ``acme-gadgets@4.3.6``. We declare the | ||||
name and version in the ``package.dds`` in the package root: | |||||
name and version in the ``package.json5`` in the package root: | |||||
.. code-block:: | |||||
.. code-block:: js | |||||
Name: acme-gadgets | |||||
Version: 4.3.6 | |||||
Namespace: acme | |||||
{ | |||||
name: 'acme-widgets', | |||||
version: '4.3.6', | |||||
namespace: 'acme', | |||||
} | |||||
.. note:: | .. note:: | ||||
The ``Namespace`` field is required, but will be addressed in the | |||||
The ``namespace`` field is required, but will be addressed in the | |||||
:ref:`deps.lib-deps` section. | :ref:`deps.lib-deps` section. | ||||
Suppose that our package's libraries build upon the libraries in the | Suppose that our package's libraries build upon the libraries in the | ||||
not as new as ``2.0.0``. Such a dependency can be declared with the ``Depends`` | not as new as ``2.0.0``. Such a dependency can be declared with the ``Depends`` | ||||
key: | key: | ||||
.. code-block:: | |||||
:emphasize-lines: 5 | |||||
Name: acme-gadgets | |||||
Version: 4.3.6 | |||||
Namespace: acme | |||||
.. code-block:: js | |||||
:emphasize-lines: 5-7 | |||||
Depends: acme-widgets ^1.4.3 | |||||
{ | |||||
name: 'acme-gadgets', | |||||
version: '4.3.6', | |||||
namespace: 'acme', | |||||
depends: { | |||||
'acme-widgets': '^1.4.3', | |||||
}, | |||||
} | |||||
.. seealso:: :ref:`deps.ranges`. | .. seealso:: :ref:`deps.ranges`. | ||||
additional ``Depends`` keys | additional ``Depends`` keys | ||||
.. code-block:: | .. code-block:: | ||||
:emphasize-lines: 5-7 | |||||
Name: acme-gadgets | |||||
Version: 4.3.6 | |||||
Namespace: acme | |||||
Depends: acme-widgets ^1.4.3 | |||||
Depends: acme-gizmos ~5.6.5 | |||||
Depends: acme-utils ^3.3.0 | |||||
:emphasize-lines: 7-8 | |||||
{ | |||||
name: 'acme-gadgets', | |||||
version: '4.3.6', | |||||
namespace: 'acme', | |||||
depends: { | |||||
'acme-widgets': '^1.4.3', | |||||
'acme-gizmos': '~5.6.5', | |||||
'acme-utils': '^3.3.0', | |||||
}, | |||||
} | |||||
When ``dds`` attempts to build a project, it will first build the dependency | When ``dds`` attempts to build a project, it will first build the dependency | ||||
solution by iteratively scanning the dependencies of the containing project and | solution by iteratively scanning the dependencies of the containing project and | ||||
To announce that a library wishes to *use* another library, use the aptly-named | To announce that a library wishes to *use* another library, use the aptly-named | ||||
``Uses`` key: | ``Uses`` key: | ||||
.. code-block:: | |||||
.. code-block:: js | |||||
:emphasize-lines: 3-5 | :emphasize-lines: 3-5 | ||||
Name: gadgets | Name: gadgets | ||||
Uses: acme/gizmos | Uses: acme/gizmos | ||||
Uses: acme/utils | Uses: acme/utils | ||||
Here is where the package's ``Namespace`` key comes into play: A library's | |||||
qualified name is specified by joining the ``Namespace`` of the containing | |||||
package with the ``Name`` of the library within that package with a ``/`` | |||||
Here is where the package's ``namespace`` key comes into play: A library's | |||||
qualified name is specified by joining the ``namespace`` of the containing | |||||
package with the ``name`` of the library within that package with a ``/`` | |||||
between them. | between them. | ||||
It is the responsibility of package authors to document the ``Namespace`` and | |||||
It is the responsibility of package authors to document the ``namespace`` and | |||||
``Name`` of the packages and libraries that they distribute. | ``Name`` of the packages and libraries that they distribute. | ||||
.. note:: | .. note:: | ||||
The ``Namespace`` of a package is completely arbitrary, and need not relate | |||||
The ``namespace`` of a package is completely arbitrary, and need not relate | |||||
to a C++ ``namespace``. | to a C++ ``namespace``. | ||||
.. note:: | .. note:: | ||||
The ``Namespace`` need not be unique to a single package. For example, a | |||||
single organization (Like Acme Inc.) can share a single ``Namespace`` for | |||||
The ``namespace`` need not be unique to a single package. For example, a | |||||
single organization (Like Acme Inc.) can share a single ``namespace`` for | |||||
many of their packages and libraries. | many of their packages and libraries. | ||||
However, it is essential that the ``<Namespace>/<Name>`` pair be | |||||
However, it is essential that the ``<namespace>/<name>`` pair be | |||||
universally unique, so choose wisely! | universally unique, so choose wisely! | ||||
Once the ``Uses`` key appears in the ``library.dds`` file of a library, ``dds`` | Once the ``Uses`` key appears in the ``library.dds`` file of a library, ``dds`` |
within a repository or package catalog. | within a repository or package catalog. | ||||
In order for a package to be exported by ``dds`` it must have a | In order for a package to be exported by ``dds`` it must have a | ||||
``package.dds`` file at its package root. Three keys are required to be | |||||
present in the ``package.dds`` file: ``Name``, ``Version``, and ``Namespace``: | |||||
``package.json5`` file at its package root. Three keys are required to be | |||||
present in the ``package.json5`` file: ``name``, ``version``, and ``namespace``: | |||||
.. code-block:: yaml | |||||
.. code-block:: js | |||||
Name: acme-widgets | |||||
Version: 6.7.3 | |||||
Namespace: acme | |||||
{ | |||||
name: 'acme-widgets', | |||||
version: '6.7.3', | |||||
namespace: 'acme', | |||||
} | |||||
``Version`` must be a valid semantic version string. | |||||
``version`` must be a valid semantic version string. | |||||
.. note:: | .. note:: | ||||
The ``Namespace`` key is arbitrary, and not necessarily associated with | |||||
and C++ ``namespace``. | |||||
The ``namespace`` key is arbitrary, and not necessarily associated with | |||||
any C++ ``namespace``. | |||||
.. seealso:: | .. seealso:: | ||||
The purpose of ``Namespace``, as well as additional options in this file, | |||||
The purpose of ``namespace``, as well as additional options in this file, | |||||
are described in the :ref:`deps.pkg-deps` page | are described in the :ref:`deps.pkg-deps` page | ||||
include/ | include/ | ||||
src/ | src/ | ||||
library.dds | library.dds | ||||
package.dds | |||||
package.json5 | |||||
.. _repo.export-local: | .. _repo.export-local: |
.. _catch2: https://github.com/catchorg/Catch2 | .. _catch2: https://github.com/catchorg/Catch2 | ||||
To make use of Catch as our test driver, we simply declare this intent in the | To make use of Catch as our test driver, we simply declare this intent in the | ||||
``package.dds`` file at the package root: | |||||
``package.json5`` file at the package root: | |||||
.. code-block:: yaml | |||||
:caption: ``<root>/package.dds`` | |||||
.. code-block:: js | |||||
:caption: ``<root>/package.json5`` | |||||
:emphasize-lines: 5 | :emphasize-lines: 5 | ||||
Name: hello-dds | |||||
Version: 0.1.0 | |||||
Namespace: tutorial | |||||
Test-Driver: Catch-Main | |||||
{ | |||||
name: 'hello-dds', | |||||
version: '0.1.0', | |||||
namespace: 'tutorial', | |||||
} | |||||
If you now run ``dds build``, we will get a linker error for a multiply-defined | If you now run ``dds build``, we will get a linker error for a multiply-defined | ||||
``main`` function. When setting the ``Test-Driver`` to ``Catch-Main``, ``dds`` | ``main`` function. When setting the ``Test-Driver`` to ``Catch-Main``, ``dds`` |
``dds`` will work happily with packages that do not declare themselves, as long | ``dds`` will work happily with packages that do not declare themselves, as long | ||||
as the filesystem structure is sufficient. However: To use features covered in | as the filesystem structure is sufficient. However: To use features covered in | ||||
later tutorials, we'll need a simple ``package.dds`` file to declare | |||||
later tutorials, we'll need a simple ``package.json5`` file to declare | |||||
information about are package. This file should be placed directly in the | information about are package. This file should be placed directly in the | ||||
package root: | package root: | ||||
.. code-block:: yaml | |||||
:caption: ``<root>/package.dds`` | |||||
Name: hello-dds | |||||
Version: 0.1.0 | |||||
Namespace: tutorial | |||||
.. code-block:: js | |||||
:caption: ``<root>/package.json5`` | |||||
{ | |||||
name: 'hello-dds', | |||||
version: '0.1.0', | |||||
namespace: 'tutorial', | |||||
} | |||||
.. note:: | .. note:: | ||||
The ``Namespace`` option will be discussed later. | |||||
The ``namespace`` option will be discussed later. | |||||
Rebuilding the project will show no difference at the moment. | Rebuilding the project will show no difference at the moment. | ||||
Uses: neo/fun | Uses: neo/fun | ||||
Uses: semver/semver | Uses: semver/semver | ||||
Uses: pubgrub/pubgrub | Uses: pubgrub/pubgrub | ||||
Uses: vob/json5 |
Depends: neo-fun 0.1.0 | Depends: neo-fun 0.1.0 | ||||
Depends: semver 0.2.1 | Depends: semver 0.2.1 | ||||
Depends: pubgrub 0.2.0 | Depends: pubgrub 0.2.0 | ||||
Depends: json5 0.1.2 | |||||
Test-Driver: Catch-Main | Test-Driver: Catch-Main |
{ | |||||
"$schema": "what", | |||||
name: 'dds', | |||||
version: '0.1.0', | |||||
depends: { | |||||
spdlog: '1.4.2', | |||||
'ms-wil': '2019.11.10', | |||||
'range-v3': '0.10.0', | |||||
'nlohmann-json': '3.7.1', | |||||
'neo-sqlite3': '0.2.2', | |||||
'neo-fun': '0.1.0', | |||||
'semver': '0.2.1', | |||||
pubgrub: '0.2.0', | |||||
json5: '0.1.2', | |||||
}, | |||||
test_driver: 'Catch-Main', | |||||
} |
params.toolchain = tc_filepath.get_toolchain(); | params.toolchain = tc_filepath.get_toolchain(); | ||||
params.parallel_jobs = n_jobs.Get(); | params.parallel_jobs = n_jobs.Get(); | ||||
dds::package_manifest man; | dds::package_manifest man; | ||||
const auto man_filepath = project.root.Get() / "package.dds"; | |||||
const auto man_filepath = project.root.Get() / "package.json5"; | |||||
if (exists(man_filepath)) { | if (exists(man_filepath)) { | ||||
man = dds::package_manifest::load_from_file(man_filepath); | man = dds::package_manifest::load_from_file(man_filepath); | ||||
} | } |
#include <dds/error/errors.hpp> | #include <dds/error/errors.hpp> | ||||
#include <dds/proc.hpp> | #include <dds/proc.hpp> | ||||
#include <nlohmann/json.hpp> | |||||
#include <spdlog/spdlog.h> | #include <spdlog/spdlog.h> | ||||
using namespace dds; | using namespace dds; | ||||
spdlog::info("Create sdist from clone ..."); | spdlog::info("Create sdist from clone ..."); | ||||
if (git.auto_lib.has_value()) { | if (git.auto_lib.has_value()) { | ||||
spdlog::info("Generating library data automatically"); | spdlog::info("Generating library data automatically"); | ||||
auto pkg_strm = dds::open(tmpdir.path() / "package.dds", std::ios::binary | std::ios::out); | |||||
pkg_strm << "Name: " << listing.ident.name << '\n' // | |||||
<< "Version: " << listing.ident.version.to_string() << '\n' // | |||||
<< "Namespace: " << git.auto_lib->namespace_; | |||||
auto pkg_strm | |||||
= dds::open(tmpdir.path() / "package.json5", std::ios::binary | std::ios::out); | |||||
auto man_json = nlohmann::json::object(); | |||||
man_json["name"] = listing.ident.name; | |||||
man_json["version"] = listing.ident.version.to_string(); | |||||
man_json["namespace"] = git.auto_lib->namespace_; | |||||
pkg_strm << nlohmann::to_string(man_json); | |||||
auto lib_strm = dds::open(tmpdir.path() / "library.dds", std::ios::binary | std::ios::out); | auto lib_strm = dds::open(tmpdir.path() / "library.dds", std::ios::binary | std::ios::out); | ||||
lib_strm << "Name: " << git.auto_lib->name; | lib_strm << "Name: " << git.auto_lib->name; | ||||
} | } |
return "sdist-ident-mismatch.html"; | return "sdist-ident-mismatch.html"; | ||||
case errc::corrupted_build_db: | case errc::corrupted_build_db: | ||||
return "corrupted-build-db.html"; | return "corrupted-build-db.html"; | ||||
case errc::invalid_pkg_manifest: | |||||
return "invalid-pkg-manifest.html"; | |||||
case errc::invalid_version_range_string: | case errc::invalid_version_range_string: | ||||
return "invalid-version-string.html#range"; | return "invalid-version-string.html#range"; | ||||
case errc::invalid_version_string: | case errc::invalid_version_string: | ||||
The catalog database schema doesn't match what dds expects. This indicates that | 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 | the database file has been modified in a way that dds cannot automatically fix | ||||
and handle. | and handle. | ||||
)"; | |||||
case errc::invalid_pkg_manifest: | |||||
return R"( | |||||
The package manifest is malformed. Refer to the documentation and above error | |||||
message for more details. | |||||
)"; | )"; | ||||
case errc::invalid_catalog_json: | case errc::invalid_catalog_json: | ||||
return R"( | return R"( | ||||
return R"( | return R"( | ||||
A `Uses` or `Links` field for a library specifies a library of an unknown name. | A `Uses` or `Links` field for a library specifies a library of an unknown name. | ||||
Check your spelling, and check that the package containing the library is | Check your spelling, and check that the package containing the library is | ||||
available, either from the `package.dds` or from the `INDEX.lmi` that was used | |||||
available, either from the `package.json5` or from the `INDEX.lmi` that was used | |||||
for the build. | for the build. | ||||
)"; | )"; | ||||
case errc::none: | case errc::none: | ||||
"that was expected of it"; | "that was expected of it"; | ||||
case errc::corrupted_build_db: | case errc::corrupted_build_db: | ||||
return "The build database file is corrupted"; | return "The build database file is corrupted"; | ||||
case errc::invalid_pkg_manifest: | |||||
return "The package manifest is invalid"; | |||||
case errc::invalid_version_range_string: | case errc::invalid_version_range_string: | ||||
return "Attempted to parse an invalid version range string. <- (Seeing this text is a " | return "Attempted to parse an invalid version range string. <- (Seeing this text is a " | ||||
"`dds` bug. Please report it.)"; | "`dds` bug. Please report it.)"; | ||||
case errc::invalid_version_string: | case errc::invalid_version_string: | ||||
return "Attempted to parse an invalid version string. <- (Seeing this text is a `dds` bug. " | |||||
return "Attempted to parse an invalid version string. <- (Seeing this text is a `dds` " | |||||
"bug. " | |||||
"Please report it.)"; | "Please report it.)"; | ||||
case errc::invalid_config_key: | case errc::invalid_config_key: | ||||
return "Found an invalid configuration key. <- (Seeing this text is a `dds` bug. Please " | |||||
return "Found an invalid configuration key. <- (Seeing this text is a `dds` bug. " | |||||
"Please " | |||||
"report it.)"; | "report it.)"; | ||||
case errc::invalid_lib_filesystem: | case errc::invalid_lib_filesystem: | ||||
case errc::invalid_pkg_filesystem: | case errc::invalid_pkg_filesystem: | ||||
return "The filesystem structure of the package/library is invalid. <- (Seeing this text " | |||||
return "The filesystem structure of the package/library is invalid. <- (Seeing this " | |||||
"text " | |||||
"is a `dds` bug. Please report it.)"; | "is a `dds` bug. Please report it.)"; | ||||
case errc::invalid_pkg_id: | case errc::invalid_pkg_id: | ||||
return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please " | return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please " | ||||
"report it.)"; | "report it.)"; | ||||
case errc::invalid_pkg_name: | case errc::invalid_pkg_name: | ||||
return "A package name is invalid <- (Seeing this text is a `dds` bug. Please report it.)"; | |||||
return "A package name is invalid <- (Seeing this text is a `dds` bug. Please report " | |||||
"it.)"; | |||||
case errc::sdist_exists: | case errc::sdist_exists: | ||||
return "The source ditsribution already exists at the destination <- (Seeing this text is " | |||||
return "The source ditsribution already exists at the destination <- (Seeing this " | |||||
"text is " | |||||
"a `dds` bug. Please report it.)"; | "a `dds` bug. Please report it.)"; | ||||
case errc::unknown_test_driver: | case errc::unknown_test_driver: | ||||
return "The specified Test-Driver is not known to `dds`"; | return "The specified Test-Driver is not known to `dds`"; |
corrupted_build_db, | corrupted_build_db, | ||||
invalid_pkg_manifest, | |||||
invalid_version_range_string, | invalid_version_range_string, | ||||
invalid_version_string, | invalid_version_string, | ||||
invalid_pkg_id, | invalid_pkg_id, |
#include <range/v3/view/split.hpp> | #include <range/v3/view/split.hpp> | ||||
#include <range/v3/view/split_when.hpp> | #include <range/v3/view/split_when.hpp> | ||||
#include <range/v3/view/transform.hpp> | #include <range/v3/view/transform.hpp> | ||||
#include <spdlog/fmt/fmt.h> | |||||
#include <spdlog/spdlog.h> | |||||
#include <json5/parse_data.hpp> | |||||
using namespace dds; | using namespace dds; | ||||
package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||||
package_manifest package_manifest::load_from_dds_file(const fs::path& fpath) { | |||||
spdlog::warn( | |||||
"Using deprecated package.dds parsing (on file {}). This will be removed soon. Migrate!", | |||||
fpath.string()); | |||||
auto kvs = lm::parse_file(fpath); | auto kvs = lm::parse_file(fpath); | ||||
package_manifest ret; | package_manifest ret; | ||||
std::string version_str; | std::string version_str; | ||||
return ret; | return ret; | ||||
} | } | ||||
package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||||
auto content = slurp_file(fpath); | |||||
auto data = json5::parse_data(content); | |||||
if (!data.is_object()) { | |||||
throw_user_error<errc::invalid_pkg_manifest>("Root value must be an object"); | |||||
} | |||||
const auto& obj = data.as_object(); | |||||
package_manifest ret; | |||||
/// Get the name | |||||
auto it = obj.find("name"); | |||||
if (it == obj.end() || !it->second.is_string() || it->second.as_string().empty()) { | |||||
throw_user_error<errc::invalid_pkg_name>("'name' field in [{}] must be a non-empty string", | |||||
fpath.string()); | |||||
} | |||||
ret.namespace_ = ret.pkg_id.name = it->second.as_string(); | |||||
/// Get the version | |||||
it = obj.find("version"); | |||||
if (it == obj.end() || !it->second.is_string()) { | |||||
throw_user_error< | |||||
errc::invalid_version_string>("'version' field in [{}] must be a version string", | |||||
fpath.string()); | |||||
} | |||||
auto version_str = it->second.as_string(); | |||||
ret.pkg_id.version = semver::version::parse(version_str); | |||||
/// Get the namespace | |||||
it = obj.find("namespace"); | |||||
if (it != obj.end()) { | |||||
if (!it->second.is_string() || it->second.as_string().empty()) { | |||||
throw_user_error<errc::invalid_pkg_manifest>( | |||||
"'namespace' attribute in [{}] must be a non-empty string", fpath.string()); | |||||
} | |||||
ret.namespace_ = it->second.as_string(); | |||||
} | |||||
/// Get the test driver | |||||
it = obj.find("test_driver"); | |||||
if (it != obj.end()) { | |||||
if (!it->second.is_string()) { | |||||
throw_user_error<errc::invalid_pkg_manifest>( | |||||
"'test_driver' attribute in [{}] must be a non-empty string", fpath.string()); | |||||
} | |||||
auto& test_driver_str = it->second.as_string(); | |||||
if (test_driver_str == "Catch-Main") { | |||||
ret.test_driver = test_lib::catch_main; | |||||
} else if (test_driver_str == "Catch") { | |||||
ret.test_driver = test_lib::catch_; | |||||
} else { | |||||
auto dym = *did_you_mean(test_driver_str, {"Catch-Main", "Catch"}); | |||||
throw_user_error< | |||||
errc::unknown_test_driver>("Unknown 'Test-Driver' '{}' (Did you mean '{}'?)", | |||||
test_driver_str, | |||||
dym); | |||||
} | |||||
} | |||||
/// Get the dependencies | |||||
it = obj.find("depends"); | |||||
if (it != obj.end()) { | |||||
if (!it->second.is_object()) { | |||||
throw_user_error<errc::invalid_pkg_manifest>( | |||||
"'depends' field must be an object mapping package name to version ranges"); | |||||
} | |||||
for (const auto& [pkg_name, range_str_] : it->second.as_object()) { | |||||
if (!range_str_.is_string()) { | |||||
throw_user_error< | |||||
errc::invalid_pkg_manifest>("Dependency for '{}' must be a range string", | |||||
pkg_name); | |||||
} | |||||
try { | |||||
auto rng = semver::range::parse_restricted(range_str_.as_string()); | |||||
dependency dep{pkg_name, {rng.low(), rng.high()}}; | |||||
ret.dependencies.push_back(std::move(dep)); | |||||
} catch (const semver::invalid_range&) { | |||||
throw_user_error<errc::invalid_version_range_string>( | |||||
"Invalid version range string '{}' in dependency declaration for '{}'", | |||||
range_str_.as_string(), | |||||
pkg_name); | |||||
} | |||||
} | |||||
} | |||||
return ret; | |||||
} |
namespace dds { | namespace dds { | ||||
/** | /** | ||||
* Possible values for Test-Driver in a package.dds | |||||
* Possible values for test_driver in a package.json5 | |||||
*/ | */ | ||||
enum class test_lib { | enum class test_lib { | ||||
catch_, | catch_, | ||||
* Load a package manifest from a file on disk. | * Load a package manifest from a file on disk. | ||||
*/ | */ | ||||
static package_manifest load_from_file(path_ref); | static package_manifest load_from_file(path_ref); | ||||
static package_manifest load_from_dds_file(path_ref); | |||||
}; | }; | ||||
} // namespace dds | } // namespace dds |
sdist_copy_library(out, lib, params); | sdist_copy_library(out, lib, params); | ||||
} | } | ||||
auto man_path = params.project_dir / "package.dds"; | |||||
if (!fs::is_regular_file(man_path)) { | |||||
auto j5_man_path = params.project_dir / "package.json5"; | |||||
auto dds_man_path = params.project_dir / "package.dds"; | |||||
package_manifest pkg_man; | |||||
if (fs::is_regular_file(j5_man_path)) { | |||||
pkg_man = package_manifest::load_from_file(j5_man_path); | |||||
sdist_export_file(out, params.project_dir, j5_man_path); | |||||
} else if (fs::is_regular_file(dds_man_path)) { | |||||
pkg_man = package_manifest::load_from_dds_file(dds_man_path); | |||||
sdist_export_file(out, params.project_dir, dds_man_path); | |||||
} else { | |||||
throw_user_error<errc::invalid_pkg_filesystem>( | throw_user_error<errc::invalid_pkg_filesystem>( | ||||
"Creating a source distribution requires a package.dds file for the project (Expected " | |||||
"Creating a source distribution requires a package.json5 file for the project " | |||||
"(Expected " | |||||
"[{}])", | "[{}])", | ||||
man_path.string()); | |||||
j5_man_path.string()); | |||||
} | } | ||||
sdist_export_file(out, params.project_dir, man_path); | |||||
auto pkg_man = package_manifest::load_from_file(man_path); | |||||
spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string()); | spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string()); | ||||
} | } | ||||
sdist sdist::from_directory(path_ref where) { | sdist sdist::from_directory(path_ref where) { | ||||
auto pkg_man = package_manifest::load_from_file(where / "package.dds"); | |||||
/// XXX: Remove this logic once package.dds is all gone. | |||||
auto j5_path = where / "package.json5"; | |||||
auto dds_path = where / "package.dds"; | |||||
// Load based on whichever is actually present | |||||
auto pkg_man = fs::is_regular_file(j5_path) ? package_manifest::load_from_file(j5_path) | |||||
: package_manifest::load_from_dds_file(dds_path); | |||||
return sdist{std::move(pkg_man), where}; | return sdist{std::move(pkg_man), where}; | ||||
} | } |
def basic_pkg_dds(dds: DDS): | def basic_pkg_dds(dds: DDS): | ||||
return set_contents( | return set_contents( | ||||
dds.source_root / 'package.dds', b''' | |||||
Name: test-pkg | |||||
Version: 0.2.2 | |||||
dds.source_root / 'package.json5', b''' | |||||
{ | |||||
name: 'test-pkg', | |||||
version: '0.2.2', | |||||
} | |||||
''') | ''') | ||||
from tests import dds, DDS | from tests import dds, DDS | ||||
from tests.fileutil import ensure_dir | from tests.fileutil import ensure_dir | ||||
import pytest | |||||
def test_get(dds: DDS): | def test_get(dds: DDS): | ||||
dds.scope.enter_context(ensure_dir(dds.build_dir)) | dds.scope.enter_context(ensure_dir(dds.build_dir)) | ||||
'0.2.2': { | '0.2.2': { | ||||
'depends': {}, | 'depends': {}, | ||||
'git': { | 'git': { | ||||
'url': 'https://github.com/vector-of-bool/neo-sqlite3.git', | |||||
'ref': '0.2.2', | |||||
'url': | |||||
'https://github.com/vector-of-bool/neo-sqlite3.git', | |||||
'ref': | |||||
'0.2.2', | |||||
}, | }, | ||||
}, | }, | ||||
}, | }, |
"0.1.0": { | "0.1.0": { | ||||
"git": { | "git": { | ||||
"url": "https://github.com/vector-of-bool/neo-buffer.git", | "url": "https://github.com/vector-of-bool/neo-buffer.git", | ||||
"ref": "develop" | |||||
"ref": "0.1.0" | |||||
}, | }, | ||||
"depends": {} | "depends": {} | ||||
} | } |
Name: deps-test | |||||
Version: 0.0.0 | |||||
Depends: neo-buffer 0.1.0 | |||||
Depends: range-v3 0.9.1 |
{ | |||||
name: 'deps-test', | |||||
version: '0.0.0', | |||||
depends: { | |||||
'neo-buffer': '0.1.0', | |||||
'range-v3': '0.9.1', | |||||
} | |||||
} |
Name: deps-test | |||||
Version: 0.0.0 |
{ | |||||
name: 'deps-test', | |||||
version: '0.0.0' | |||||
} |
Name: json-test | |||||
Version: 0.0.0 | |||||
Depends: nlohmann-json 3.7.1 |
{ | |||||
"name": "json-test", | |||||
"version": "0.0.0", | |||||
"depends": { | |||||
"nlohmann-json": "3.7.1" | |||||
} | |||||
} |
Name: test | |||||
Version: 0.0.0 | |||||
Depends: spdlog 1.4.2 |
{ | |||||
name: 'test', | |||||
version: '0.0.0', | |||||
depends: { | |||||
'spdlog': '1.4.2', | |||||
}, | |||||
} |
Name: foo | |||||
Version: 1.2.3 |
{ | |||||
name: 'foo', | |||||
version: '1.2.3', | |||||
} |
Name: Test | |||||
Version: 0.0.0 | |||||
Test-Driver: Catch |
{ | |||||
"name": "test", | |||||
"version": "0.0.0", | |||||
"test_driver": "Catch", | |||||
} |
Name: Test | |||||
Version: 0.0.0 | |||||
Test-Driver: Catch-Main |
{ | |||||
"name": "test", | |||||
"version": "0.0.0", | |||||
"test_driver": "Catch-Main", | |||||
} |
), | ), | ||||
many_versions( | many_versions( | ||||
'json5', | 'json5', | ||||
('0.1.0', ), | |||||
( | |||||
'0.1.0', | |||||
'0.1.2', | |||||
), | |||||
description='A C++ implementation of a JSON5 parser', | description='A C++ implementation of a JSON5 parser', | ||||
git_url='https://github.com/vector-of-bool/json5.git', | git_url='https://github.com/vector-of-bool/json5.git', | ||||
), | ), |