From 77a5303ebe9d5008df4b409381487c0cebbd69ad Mon Sep 17 00:00:00 2001 From: Yannik Sander <7040031+ysndr@users.noreply.github.com> Date: Fri, 1 Dec 2023 18:15:17 +0100 Subject: [PATCH] chore: untangle resolver mixin (#194) fixes #189 --------- Co-authored-by: Alex Ameen --- flake.lock | 21 --- flake.nix | 5 +- include/flox/resolver/mixins.hh | 276 +++++++++++++------------------- src/resolver/mixins.cc | 270 +++++++++++++++++++------------ src/search/command.cc | 31 ++-- tests/data/manifest/ga1.toml | 3 + tests/ga-registry.bats | 16 ++ 7 files changed, 323 insertions(+), 299 deletions(-) create mode 100644 tests/data/manifest/ga1.toml diff --git a/flake.lock b/flake.lock index 7df2761e..7687e4c8 100644 --- a/flake.lock +++ b/flake.lock @@ -1,25 +1,5 @@ { "nodes": { - "argparse": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1691774076, - "narHash": "sha256-J4Cdw5xc1sKfSqT1NfxY58ETj6fAV9aFbFummJqNKss=", - "owner": "aakropotkin", - "repo": "argparse", - "rev": "e3223ebfd8ab893ea041fc1d5ad72533f58b7279", - "type": "github" - }, - "original": { - "owner": "aakropotkin", - "repo": "argparse", - "type": "github" - } - }, "floco": { "inputs": { "nixpkgs": [ @@ -58,7 +38,6 @@ }, "root": { "inputs": { - "argparse": "argparse", "floco": "floco", "nixpkgs": "nixpkgs", "sqlite3pp": "sqlite3pp" diff --git a/flake.nix b/flake.nix index bf384b1b..4fd7e792 100644 --- a/flake.nix +++ b/flake.nix @@ -12,15 +12,13 @@ inputs.floco.url = "github:aakropotkin/floco"; inputs.floco.inputs.nixpkgs.follows = "/nixpkgs"; - inputs.argparse.url = "github:aakropotkin/argparse"; - inputs.argparse.inputs.nixpkgs.follows = "/nixpkgs"; inputs.sqlite3pp.url = "github:aakropotkin/sqlite3pp"; inputs.sqlite3pp.inputs.nixpkgs.follows = "/nixpkgs"; # ---------------------------------------------------------------------------- # - outputs = { nixpkgs, floco, argparse, sqlite3pp, ... }: let + outputs = { nixpkgs, floco, sqlite3pp, ... }: let # ---------------------------------------------------------------------------- # @@ -67,7 +65,6 @@ overlays.semver overlays.nix sqlite3pp.overlays.default - argparse.overlays.default ]; overlays.flox-pkgdb = final: prev: { diff --git a/include/flox/resolver/mixins.hh b/include/flox/resolver/mixins.hh index 8c048b14..5ab4b772 100644 --- a/include/flox/resolver/mixins.hh +++ b/include/flox/resolver/mixins.hh @@ -66,24 +66,42 @@ private: * Even for internal access you should use the `get' accessors to * lazily initialize. */ - /** Path to user level manifest ( if any ). */ - std::optional globalManifestPath; + /* ------------------------------ arguments ------------------------------- */ + + + /** Path to project level manifest. ( required ) */ + std::optional manifestPath; + + /* ----------------------------- lazy fields ------------------------------ */ + + /** * Contents of user level manifest with global registry and settings * ( if any ). */ std::optional globalManifest; - /** Path to project level manifest. ( required ) */ - std::optional manifestPath; + /** + * Contents of project level manifest with registry, settings, + * activation hook, and list of packages. + */ + std::optional manifestRaw; + /** * Contents of project level manifest with registry, settings, * activation hook, and list of packages. ( required ) */ std::optional manifest; - /** Path to project's lockfile ( if any ). */ - std::optional lockfilePath; + /** + * Contents of project level manifest with registry, settings, + * activation hook, and list of packages. + */ + std::optional globalManifestRaw; + + /** Raw contents of project's lockfile ( if any ). */ + std::optional lockfileRaw; + /** Contents of project's lockfile ( if any ). */ std::optional lockfile; @@ -94,160 +112,150 @@ private: protected: /** - * @brief Initialize the @a globalManifestPath and @a globalManifest member - * variables by reading from a file. + * @brief Set @a globalManifestRaw by loading a manifest from `maybePath`. + * Overrides any previous value before @a manifest is initialized. * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * @throws @a EnvironmentMixinException if called after @a globalManifest is + * initialized, as it is no longer allowed to change the global manifest. + * @throws @a EnvironmentMixinException the path does not exist. */ - virtual void - initGlobalManifestPath( std::filesystem::path path ); + void + setGlobalManifestRaw( std::optional maybePath ); /** - * @brief Manually set @a globalManifestPath without checking to see if it was - * previously set, and do not initialize @manifest. + * @brief Manually set @a globalManifestRaw. + * Overrides any previous value before @a manifest is initialized. * - * This function exists so that child classes can override their - * @a flox::resolver::EnvirontMixin base @a globalManifestPath at runtime - * without accessing private member variables. + * + * @throws @a EnvironmentMixinException if called after @a globalManifest is + * initialized, as it is no longer allowed to change the global manifest. + * @throws @a EnvironmentMixinException the path does not exist. */ void - setGlobalManifestPath( std::optional maybePath ) - { - this->globalManifestPath = std::move( maybePath ); - } + setGlobalManifestRaw( std::optional maybeRaw ); + /** * @brief Initialize the @a globalManifest member variable. * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. + * This is called by @a getGlobalManifest() to lazily initialize the global + * manifest. * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * This function exists so that child classes can change how their global + * manifest is initialized. */ - virtual void + [[nodiscard]] virtual GlobalManifest initGlobalManifest( GlobalManifestRaw manifestRaw ); /** - * @brief Initialize the @a manifestPath and @a manifest member variables by - * reading from a file. + * @brief Set @a manifestRaw by loading a manifest from @a `maybePath`. * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. + * Overrides any previous value before @a manifest is initialized. * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * @throws @a EnvironmentMixinException if called after @a manifest is + * initialized, as it is no longer allowed to change the manifest. + * @throws @a EnvironmentMixinException the path does not exist. */ - virtual void - initManifestPath( std::filesystem::path path ); + void + setManifestRaw( std::optional maybePath ); /** - * @brief Manually set `manifestPath' without checking to see if it was - * previously set, and do not initialize @manifest. + * @brief Manually set @a manifestRaw. + * + * Overrides any previous value before @a manifest is initialized. * - * This function exists so that child classes can override their - * @a flox::resolver::EnvirontMixin base @a manifestPath at runtime without - * accessing private member variables. + * @throws @a EnvironmentMixinException if called after @a manifest is + * initialized, as it is no longer allowed to change the manifest. + * @throws @a EnvironmentMixinException the path does not exist. */ void - setManifestPath( std::optional maybePath ) - { - this->manifestPath = std::move( maybePath ); - } + setManifestRaw( std::optional maybeRaw ); + /** * @brief Initialize the @a manifest member variable. * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. + * Creates a @a flox::resolver::EnvironmentManifest from @a manifestRaw + * stored in the current instance. * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * This function exists so that child classes can override how their manifest + * is initialized. */ - virtual void + [[nodiscard]] virtual EnvironmentManifest initManifest( ManifestRaw manifestRaw ); /** - * @brief Initialize the @a lockfilePath member variable. - * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. + * @brief Set the @a lockfilePath member variable by loading a lockfile from + * `path`. * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * @throws @a EnvironmentMixinException if called after @a lockfile is + * initialized, as it is no longer allowed to change the lockfile. */ virtual void - initLockfilePath( std::filesystem::path path ); + setLockfileRaw( std::filesystem::path path ); /** - * @brief Initialize the @a lockfile member variable. + * @brief Set the @a lockfilePath member variable. * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. - * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * @throws @a EnvironmentMixinException if called after @a lockfile is + * initialized, as it is no longer allowed to change the lockfile. */ virtual void + setLockfileRaw( LockfileRaw lockfileRaw ); + + /** + * @brief Initialize a @a flox::resolver::Lockfile from @a lockfileRaw. + * + * If @a lockfilePath is not set return an empty @a std::optional. + */ + [[nodiscard]] virtual Lockfile initLockfile( LockfileRaw lockfileRaw ); + [[nodiscard]] const std::optional & + getLockfileRaw() + { + return this->lockfileRaw; + } + + public: - /** @brief Get the filesystem path to the global manifest ( if any ). */ - [[nodiscard]] const std::optional & - getGlobalManifestPath() const + /** @brief Get raw global manifest ( if any ). */ + [[nodiscard]] const std::optional & + getGlobalManifestRaw() { - return this->globalManifestPath; + return this->globalManifestRaw; } + /** * @brief Lazily initialize and return the @a globalManifest. * * If @a globalManifest is set simply return it. - * If @a globalManifest is unset, but @a globalManifestPath is set then - * load from the file. + * If @a globalManifest is unset, try to initialize it using + * @a initGlobalManifest(). */ - [[nodiscard]] virtual const std::optional & - getGlobalManifest() - { - return this->globalManifest; - } + [[nodiscard]] const std::optional + getGlobalManifest(); /** @brief Get the filesystem path to the manifest ( if any ). */ - [[nodiscard]] const std::optional & - getManifestPath() const + [[nodiscard]] const std::optional & + getManifestRaw() const { - return this->manifestPath; + return this->manifestRaw; } /** * @brief Lazily initialize and return the @a manifest. * * If @a manifest is set simply return it. - * If @a manifest is unset, but @a manifestPath is set then - * load from the file. + * If @a manifest is unset, initialize it using @a initManifest(). */ [[nodiscard]] const EnvironmentManifest & getManifest(); - /** @brief Get the filesystem path to the lockfile ( if any ). */ - [[nodiscard]] const std::optional & - getLockfilePath() const - { - return this->lockfilePath; - } - /** * @brief Lazily initialize and return the @a lockfile. * @@ -256,25 +264,22 @@ public: * load from the file. */ [[nodiscard]] const std::optional & - getLockfile() - { - return this->lockfile; - } + getLockfile(); /** * @brief Laziliy initialize and return the @a environment. * - * The member variable @a manifest or @a manifestPath must be set for - * initialization to succeed. * Member variables associated with the _global manifest_ and _lockfile_ * are optional. * - * After @a getEnvironment() has been called once, it is no longer possible - * to use any `init*( MEMBER )` functions. + * @throws @a EnvironmentMixinException if the @a getManifest() returns an + * empty optional. */ [[nodiscard]] Environment & getEnvironment(); + /* -------------------------- argument parsers ---------------------------- */ + /** * @brief Sets the path to the global manifest file to load * with `--global-manifest`. @@ -336,66 +341,22 @@ private: protected: - /** - * @brief Initialize the @a globalManifestPath and @a globalManifest member - * variables by reading from a file. - * This form enforces `--ga-registry` by disallowing `registry` in its - * input, and injecting a hard coded `registry`. - * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. - * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. - */ - void - initGlobalManifestPath( std::filesystem::path path ) override; - /** * @brief Initialize the @a globalManifest member variable. - * This form enforces `--ga-registry` by disallowing `registry` in its - * input, and injecting a hard coded `registry`. - * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. - * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * When `--ga-registry` is set it enforces a GA compliant manifest by + * disallowing `registry` in its input, + * and injects a hard coded `registry`. */ - void + [[nodiscard]] GlobalManifest initGlobalManifest( GlobalManifestRaw manifestRaw ) override; - /** - * @brief Initialize the @a manifestPath and @a manifest member variables by - * reading from a file. - * This form enforces `--ga-registry` by disallowing `registry` in its - * input, and injecting a hard coded `registry`. - * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. - * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. - */ - void - initManifestPath( std::filesystem::path path ) override; - /** * @brief Initialize the @a manifest member variable. - * This form enforces `--ga-registry` by disallowing `registry` in its - * input, and injecting a hard coded `registry`. - * - * This may only be called once and must be called before - * `getEnvironment()` is ever used - otherwise an exception will be thrown. - * - * This function exists so that child classes can initialize their - * @a flox::resolver::EnvirontMixin base at runtime without accessing - * private member variables. + * When `--ga-registry` is set it enforces a GA compliant manifest by + * disallowing `registry` in its input, + * and injects a hard coded `registry`. */ - void + [[nodiscard]] EnvironmentManifest initManifest( ManifestRaw manifestRaw ) override; @@ -410,17 +371,6 @@ public: argparse::Argument & addGARegistryOption( argparse::ArgumentParser & parser ); - /** - * @brief Lazily initialize and return the @a globalManifest. - * - * If @a globalManifest is set simply return it. - * If @a globalManifest is unset, but @a globalManifestPath is set then - * load from the file. - */ - [[nodiscard]] const std::optional & - getGlobalManifest() override; - - }; /* End class `GAEnvironmentMixin' */ diff --git a/src/resolver/mixins.cc b/src/resolver/mixins.cc index bdc9de75..30988677 100644 --- a/src/resolver/mixins.cc +++ b/src/resolver/mixins.cc @@ -47,78 +47,194 @@ namespace flox::resolver { } -/* -------------------------------------------------------------------------- */ +/* -------------------------- non virtual set/get --------------------------- */ void -EnvironmentMixin::initGlobalManifest( GlobalManifestRaw manifestRaw ) +EnvironmentMixin::setGlobalManifestRaw( + std::optional maybePath ) { - ENV_MIXIN_THROW_IF_SET( globalManifest ) - this->globalManifest = GlobalManifest( std::move( manifestRaw ) ); + + if ( ! maybePath.has_value() ) + { + this->globalManifestRaw = std::nullopt; + return; + } + + if ( this->globalManifest.has_value() ) + { + throw EnvironmentMixinException( + "global manifest path cannot be set after global manifest was " + "initialized" ); + } + + this->globalManifestRaw + = readManifestFromPath( *maybePath ); } void -EnvironmentMixin::initGlobalManifestPath( std::filesystem::path path ) +EnvironmentMixin::setGlobalManifestRaw( + std::optional maybeRaw ) +{ + + if ( ! maybeRaw.has_value() ) + { + this->globalManifestRaw = std::nullopt; + return; + } + + if ( this->globalManifest.has_value() ) + { + throw EnvironmentMixinException( + "global manifest path cannot be set after global manifest was " + "initialized" ); + } + + this->globalManifestRaw = std::move( maybeRaw ); +} + + +const std::optional +EnvironmentMixin::getGlobalManifest() { - ENV_MIXIN_THROW_IF_SET( globalManifestPath ) - this->globalManifestPath = std::move( path ); - this->initGlobalManifest( - readManifestFromPath( *this->globalManifestPath ) ); + if ( ! this->globalManifest.has_value() ) + { + auto manifestRaw = this->getGlobalManifestRaw(); + if ( ! manifestRaw.has_value() ) { return std::nullopt; } + this->globalManifest = this->initGlobalManifest( *manifestRaw ); + } + + return this->globalManifest; } /* -------------------------------------------------------------------------- */ void -EnvironmentMixin::initManifest( ManifestRaw manifestRaw ) +EnvironmentMixin::setManifestRaw( + std::optional maybePath ) { - ENV_MIXIN_THROW_IF_SET( manifest ) - this->manifest = EnvironmentManifest( std::move( manifestRaw ) ); + + if ( ! maybePath.has_value() ) + { + this->manifestRaw = std::nullopt; + return; + } + + if ( this->manifest.has_value() ) + { + throw EnvironmentMixinException( + " manifest path cannot be set after manifest was " + "initialized" ); + } + + this->manifestRaw = readManifestFromPath( *maybePath ); } void -EnvironmentMixin::initManifestPath( std::filesystem::path path ) +EnvironmentMixin::setManifestRaw( std::optional maybeRaw ) { - ENV_MIXIN_THROW_IF_SET( manifestPath ) - this->manifestPath = std::move( path ); - this->initManifest( - readManifestFromPath( *this->manifestPath ) ); + + if ( ! maybeRaw.has_value() ) + { + this->manifestRaw = std::nullopt; + return; + } + + if ( this->manifest.has_value() ) + { + throw EnvironmentMixinException( + " manifest path cannot be set after manifest was " + "initialized" ); + } + + this->manifestRaw = std::move( maybeRaw ); +} + +const EnvironmentManifest & +EnvironmentMixin::getManifest() +{ + if ( ! this->manifest.has_value() ) + { + if ( auto manifestRaw = this->getManifestRaw(); manifestRaw.has_value() ) + { + this->manifest = this->initManifest( *manifestRaw ); + } + else + { + throw EnvironmentMixinException( + "raw manifest or manifest path must be set before manifest can be " + "initialized" ); + } + } + + return *this->manifest; } /* -------------------------------------------------------------------------- */ void -EnvironmentMixin::initLockfile( LockfileRaw lockfileRaw ) +EnvironmentMixin::setLockfileRaw( std::filesystem::path path ) { - ENV_MIXIN_THROW_IF_SET( lockfile ); - this->lockfile = Lockfile( std::move( lockfileRaw ) ); + if ( ! std::filesystem::exists( path ) ) + { + throw InvalidLockfileException( "no such path: " + path.string() ); + } + + LockfileRaw lockfileRaw = readAndCoerceJSON( path ); + this->setLockfileRaw( lockfileRaw ); } void -EnvironmentMixin::initLockfilePath( std::filesystem::path path ) +EnvironmentMixin::setLockfileRaw( LockfileRaw lockfileRaw ) { - if ( ! std::filesystem::exists( path ) ) + if ( this->lockfile.has_value() ) { - throw InvalidLockfileException( "no such path: " + path.string() ); + throw EnvironmentMixinException( + "lockfile path cannot be set after lockfile was " + "initialized" ); } - ENV_MIXIN_THROW_IF_SET( lockfilePath ) - this->lockfilePath = std::move( path ); - this->initLockfile( readAndCoerceJSON( *this->lockfilePath ) ); + this->lockfileRaw = std::move( lockfileRaw ); } +const std::optional & +EnvironmentMixin::getLockfile() +{ + if ( ! this->lockfile.has_value() ) + { + if ( auto lockfileRaw = this->getLockfileRaw(); lockfileRaw.has_value() ) + { + this->lockfile = this->initLockfile( *lockfileRaw ); + } + } + + return this->lockfile; +} /* -------------------------------------------------------------------------- */ -const EnvironmentManifest & -EnvironmentMixin::getManifest() +Lockfile +EnvironmentMixin::initLockfile( LockfileRaw lockfileRaw ) { - if ( ! this->manifest.has_value() ) - { - throw EnvironmentMixinException( - "you must provide an inline manifest or the path to a " - "manifest file" ); - } - return *this->manifest; + return Lockfile( std::move( lockfileRaw ) ); +} + + +/* ------------------------ virtual specific impls -------------------------- */ + +GlobalManifest +EnvironmentMixin::initGlobalManifest( GlobalManifestRaw manifestRaw ) +{ + return GlobalManifest( std::move( manifestRaw ) ); +} + + +/* -------------------------------------------------------------------------- */ + +EnvironmentManifest +EnvironmentMixin::initManifest( ManifestRaw manifestRaw ) +{ + return EnvironmentManifest( std::move( manifestRaw ) ); } @@ -148,7 +264,7 @@ EnvironmentMixin::addGlobalManifestFileOption( .help( "the path to the user's global `manifest.{toml,yaml,json}' file." ) .metavar( "PATH" ) .action( [&]( const std::string & strPath ) - { this->initGlobalManifestPath( nix::absPath( strPath ) ); } ); + { this->setGlobalManifestRaw( nix::absPath( strPath ) ); } ); } @@ -161,7 +277,7 @@ EnvironmentMixin::addManifestFileOption( argparse::ArgumentParser & parser ) .help( "the path to the `manifest.{toml,yaml,json}' file." ) .metavar( "PATH" ) .action( [&]( const std::string & strPath ) - { this->initManifestPath( nix::absPath( strPath ) ); } ); + { this->setManifestRaw( nix::absPath( strPath ) ); } ); } @@ -176,12 +292,12 @@ EnvironmentMixin::addManifestFileArg( argparse::ArgumentParser & parser, .help( "the path to the project's `manifest.{toml,yaml,json}' file." ) .metavar( "MANIFEST-PATH" ) .action( [&]( const std::string & strPath ) - { this->initManifestPath( nix::absPath( strPath ) ); } ); + { this->setManifestRaw( nix::absPath( strPath ) ); } ); return required ? arg.required() : arg; } -/* -------------------------------------------------------------------------- */ +/* ---------------------- EnvironmentMixin arguments ------------------------ */ argparse::Argument & EnvironmentMixin::addLockfileOption( argparse::ArgumentParser & parser ) @@ -190,10 +306,9 @@ EnvironmentMixin::addLockfileOption( argparse::ArgumentParser & parser ) .help( "the path to the projects existing `manifest.lock' file." ) .metavar( "PATH" ) .action( [&]( const std::string & strPath ) - { this->initLockfilePath( nix::absPath( strPath ) ); } ); + { this->setLockfileRaw( nix::absPath( strPath ) ); } ); } - /* -------------------------------------------------------------------------- */ argparse::Argument & @@ -210,26 +325,23 @@ EnvironmentMixin::addFloxDirectoryOption( argparse::ArgumentParser & parser ) std::filesystem::path dir( nix::absPath( strPath ) ); /* Try to locate lockfile. */ auto path = dir / "manifest.lock"; - if ( std::filesystem::exists( path ) ) - { - this->initLockfilePath( path ); - } + if ( std::filesystem::exists( path ) ) { this->setLockfileRaw( path ); } /* Locate manifest. */ // NOLINTBEGIN(bugprone-branch-clone) if ( path = dir / "manifest.json"; std::filesystem::exists( path ) ) { - this->initManifestPath( path ); + this->setManifestRaw( path ); } else if ( path = dir / "manifest.toml"; std::filesystem::exists( path ) ) { - this->initManifestPath( path ); + this->setManifestRaw( path ); } else if ( path = dir / "manifest.yaml"; std::filesystem::exists( path ) ) { - this->initManifestPath( path ); + this->setManifestRaw( path ); } else { @@ -242,88 +354,42 @@ EnvironmentMixin::addFloxDirectoryOption( argparse::ArgumentParser & parser ) } ); } +/* ---------------- EnvironmentMixin init overrides ------------------------- */ -/* -------------------------------------------------------------------------- */ - -void +GlobalManifest GAEnvironmentMixin::initGlobalManifest( GlobalManifestRaw manifestRaw ) { if ( this->gaRegistry ) { (void) static_cast( manifestRaw ); + if ( ! manifestRaw.registry.has_value() ) { manifestRaw.registry = getGARegistry(); } } - this->EnvironmentMixin::initGlobalManifest( std::move( manifestRaw ) ); + return this->EnvironmentMixin::initGlobalManifest( manifestRaw ); } - /* -------------------------------------------------------------------------- */ -void -GAEnvironmentMixin::initGlobalManifestPath( std::filesystem::path path ) -{ - if ( this->gaRegistry ) - { - auto manifestRawGA = readManifestFromPath( path ); - auto manifestRaw = static_cast( manifestRawGA ); - this->setGlobalManifestPath( std::move( path ) ); - this->EnvironmentMixin::initGlobalManifest( std::move( manifestRaw ) ); - } - else { this->EnvironmentMixin::initGlobalManifestPath( std::move( path ) ); } -} - - -/* -------------------------------------------------------------------------- */ - -void +EnvironmentManifest GAEnvironmentMixin::initManifest( ManifestRaw manifestRaw ) { if ( this->gaRegistry ) { (void) static_cast( manifestRaw ); + if ( ! manifestRaw.registry.has_value() ) { manifestRaw.registry = getGARegistry(); } } - this->EnvironmentMixin::initManifest( std::move( manifestRaw ) ); + return this->EnvironmentMixin::initManifest( manifestRaw ); } -/* -------------------------------------------------------------------------- */ - -void -GAEnvironmentMixin::initManifestPath( std::filesystem::path path ) -{ - if ( this->gaRegistry ) - { - auto manifestRawGA = readManifestFromPath( path ); - auto manifestRaw = static_cast( manifestRawGA ); - this->setManifestPath( std::move( path ) ); - this->EnvironmentMixin::initManifest( std::move( manifestRaw ) ); - } - else { this->EnvironmentMixin::initManifestPath( std::move( path ) ); } -} - - -/* -------------------------------------------------------------------------- */ - -const std::optional & -GAEnvironmentMixin::getGlobalManifest() -{ - if ( ( ! this->EnvironmentMixin::getGlobalManifest().has_value() ) - && this->gaRegistry ) - { - this->initGlobalManifest( GlobalManifestRaw() ); - } - return this->EnvironmentMixin::getGlobalManifest(); -} - - -/* -------------------------------------------------------------------------- */ +/* --------------------- GAEnvironmentMixin arguments ----------------------- */ argparse::Argument & GAEnvironmentMixin::addGARegistryOption( argparse::ArgumentParser & parser ) diff --git a/src/search/command.cc b/src/search/command.cc index 8abaa060..4baff08a 100644 --- a/src/search/command.cc +++ b/src/search/command.cc @@ -124,24 +124,37 @@ void SearchCommand::initEnvironment() { /* Init global manifest. */ - auto maybePath = this->params.getGlobalManifestPath(); - if ( maybePath.has_value() ) { this->initGlobalManifestPath( *maybePath ); } + + if ( auto path = this->params.getGlobalManifestPath(); path.has_value() ) + { + this->setGlobalManifestRaw( *path ); + } else if ( auto raw = this->params.getGlobalManifestRaw(); raw.has_value() ) { - this->initGlobalManifest( *raw ); + this->setGlobalManifestRaw( *raw ); } /* Init manifest. */ - maybePath = this->params.getManifestPath(); - if ( maybePath.has_value() ) { this->initManifestPath( *maybePath ); } - else { this->initManifest( this->params.getManifestRaw() ); } + + if ( auto path = this->params.getManifestPath(); path.has_value() ) + { + this->setManifestRaw( *path ); + } + else + { + auto raw = this->params.getManifestRaw(); + this->setManifestRaw( raw ); + } /* Init lockfile . */ - maybePath = this->params.getLockfilePath(); - if ( maybePath.has_value() ) { this->initLockfilePath( *maybePath ); } + + if ( auto path = this->params.getLockfilePath(); path.has_value() ) + { + this->setLockfileRaw( *path ); + } else if ( auto raw = this->params.getLockfileRaw(); raw.has_value() ) { - this->initLockfile( *raw ); + this->setLockfileRaw( *raw ); } } diff --git a/tests/data/manifest/ga1.toml b/tests/data/manifest/ga1.toml new file mode 100644 index 00000000..c9724590 --- /dev/null +++ b/tests/data/manifest/ga1.toml @@ -0,0 +1,3 @@ + +# empty install table #189 +[install] diff --git a/tests/ga-registry.bats b/tests/ga-registry.bats index 4ddfbc4f..885c1e3a 100644 --- a/tests/ga-registry.bats +++ b/tests/ga-registry.bats @@ -133,6 +133,22 @@ setup_file() { } +# ---------------------------------------------------------------------------- # + +# bats test_tags=manifest:empty, lock:empty + +@test "An empty manifest should lock successfully with --ga-registry and without" { + run $PKGDB manifest lock "$TDATA/ga1.toml"; + assert_success; + + run $PKGDB manifest lock --ga-registry "$TDATA/ga1.toml"; + assert_success; + + run $PKGDB manifest lock "$TDATA/ga1.toml" --ga-registry; + assert_success; +} + + # ---------------------------------------------------------------------------- # # bats test_tags=manifest:ga-registry, lock:ga-registry