aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2023-02-20 16:09:02 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2023-02-20 19:50:42 +0300
commitc97dba3a4f2af33091112a347e181a5a2edc9914 (patch)
tree201471b5d13cf3af66cd5a856a98fc87316fbae6
parent209a5d12d829adcf7bff48d64c436a8c0ff4b30e (diff)
Add type and language package manifest values
Also add manifest.ixx.
-rw-r--r--libbpkg/manifest.cxx148
-rw-r--r--libbpkg/manifest.hxx319
-rw-r--r--libbpkg/manifest.ixx402
-rw-r--r--tests/manifest/testscript172
4 files changed, 742 insertions, 299 deletions
diff --git a/libbpkg/manifest.cxx b/libbpkg/manifest.cxx
index 162de5a..8db4026 100644
--- a/libbpkg/manifest.cxx
+++ b/libbpkg/manifest.cxx
@@ -9,10 +9,10 @@
#include <sstream>
#include <cassert>
#include <cstdlib> // strtoull()
-#include <cstring> // strncmp(), strcmp(), strchr()
+#include <cstring> // strncmp(), strcmp(), strchr(), strcspn()
#include <utility> // move()
#include <cstdint> // uint*_t
-#include <algorithm> // find(), find_if_not(), find_first_of(), replace()
+#include <algorithm> // find(), find_if(), find_first_of(), replace()
#include <stdexcept> // invalid_argument
#include <type_traits> // remove_reference
@@ -1112,20 +1112,6 @@ namespace bpkg
}
}
- std::string dependency::
- string () const
- {
- std::string r (name.string ());
-
- if (constraint)
- {
- r += ' ';
- r += constraint->string ();
- }
-
- return r;
- }
-
// dependency_alternative
//
string dependency_alternative::
@@ -1226,14 +1212,6 @@ namespace bpkg
return r;
}
- bool dependency_alternative::
- single_line () const
- {
- return !prefer &&
- !require &&
- (!reflect || reflect->find ('\n') == string::npos);
- }
-
// dependency_alternatives
//
class dependency_alternatives_lexer: public char_scanner<utf8_validator>
@@ -2419,18 +2397,6 @@ namespace bpkg
return serializer::merge_comment (r, comment);
}
- bool dependency_alternatives::
- conditional () const
- {
- for (const dependency_alternative& da: *this)
- {
- if (da.enable)
- return true;
- }
-
- return false;
- }
-
// requirement_alternative
//
string requirement_alternative::
@@ -2515,12 +2481,6 @@ namespace bpkg
return r;
}
- bool requirement_alternative::
- single_line () const
- {
- return !reflect || reflect->find ('\n') == string::npos;
- }
-
// requirement_alternatives
//
requirement_alternatives::
@@ -2620,18 +2580,6 @@ namespace bpkg
return serializer::merge_comment (r, comment);
}
- bool requirement_alternatives::
- conditional () const
- {
- for (const requirement_alternative& ra: *this)
- {
- if (ra.enable)
- return true;
- }
-
- return false;
- }
-
// build_class_term
//
build_class_term::
@@ -3240,25 +3188,6 @@ namespace bpkg
return r;
}
- // distribution_name_value
- //
- optional<string> distribution_name_value::
- distribution (const string& s) const
- {
- size_t sn (s.size ());
- size_t nn (name.size ());
-
- if (nn > sn && name.compare (nn - sn, sn, s) == 0)
- {
- size_t p (name.find ('-'));
-
- if (p == nn - sn)
- return string (name, 0, p);
- }
-
- return nullopt;
- }
-
// pkg_package_manifest
//
static build_class_expr
@@ -3709,6 +3638,64 @@ namespace bpkg
upstream_version = move (nv);
}
+ else if (n == "type")
+ {
+ if (m.type)
+ bad_name ("package type redefinition");
+
+ // Strip the type extra information, if present.
+ //
+ size_t p (v.find (','));
+ if (p != string::npos)
+ {
+ v.resize (p);
+ trim_right (v);
+ }
+
+ if (v.empty ())
+ bad_value ("empty package type");
+
+ m.type = move (v);
+ }
+ else if (n == "language")
+ {
+ // Strip the language extra information, if present.
+ //
+ size_t p (v.find (','));
+ if (p != string::npos)
+ v.resize (p);
+
+ // Determine the language impl flag.
+ //
+ bool impl (false);
+ p = v.find ('=');
+ if (p != string::npos)
+ {
+ string s (trim (string (v, p + 1)));
+ if (s != "impl")
+ bad_value (!s.empty ()
+ ? "unexpected '" + s + "' value after '='"
+ : "expected 'impl' after '='");
+
+ impl = true;
+
+ v.resize (p);
+ }
+
+ // Finally, validate and add the language.
+ //
+ trim_right (v);
+
+ if (v.empty ())
+ bad_value ("empty package language");
+
+ if (find_if (m.languages.begin (), m.languages.end (),
+ [&v] (const language& l) {return l.name == v;}) !=
+ m.languages.end ())
+ bad_value ("duplicate package language");
+
+ m.languages.emplace_back (move (v), impl);
+ }
else if (n == "project")
{
if (m.project)
@@ -4452,15 +4439,6 @@ namespace bpkg
}
package_manifest::
- package_manifest (manifest_parser& p,
- bool iu,
- bool cv,
- package_manifest_flags fl)
- : package_manifest (p, function<translate_function> (), iu, cv, fl)
- {
- }
-
- package_manifest::
package_manifest (const string& name,
vector<name_value>&& vs,
const function<translate_function>& tf,
@@ -4977,6 +4955,12 @@ namespace bpkg
if (m.upstream_version)
s.next ("upstream-version", *m.upstream_version);
+ if (m.type)
+ s.next ("type", *m.type);
+
+ for (const language& l: m.languages)
+ s.next ("language", !l.impl ? l.name : l.name + "=impl");
+
if (m.project)
s.next ("project", m.project->string ());
diff --git a/libbpkg/manifest.hxx b/libbpkg/manifest.hxx
index 6779881..1d45edf 100644
--- a/libbpkg/manifest.hxx
+++ b/libbpkg/manifest.hxx
@@ -11,7 +11,6 @@
#include <cstdint> // uint*_t
#include <ostream>
#include <utility> // move()
-#include <stdexcept> // logic_error
#include <functional>
#include <libbutl/url.hxx>
@@ -111,23 +110,12 @@ namespace bpkg
std::string
string (bool ignore_revision = false, bool ignore_iteration = false) const;
- bool
- operator< (const version& v) const noexcept {return compare (v) < 0;}
-
- bool
- operator> (const version& v) const noexcept {return compare (v) > 0;}
-
- bool
- operator== (const version& v) const noexcept {return compare (v) == 0;}
-
- bool
- operator<= (const version& v) const noexcept {return compare (v) <= 0;}
-
- bool
- operator>= (const version& v) const noexcept {return compare (v) >= 0;}
-
- bool
- operator!= (const version& v) const noexcept {return compare (v) != 0;}
+ bool operator< (const version& v) const noexcept;
+ bool operator> (const version& v) const noexcept;
+ bool operator== (const version& v) const noexcept;
+ bool operator<= (const version& v) const noexcept;
+ bool operator>= (const version& v) const noexcept;
+ bool operator!= (const version& v) const noexcept;
// If the revision is ignored, then the iteration is also ignored,
// regardless of the argument (see above for details).
@@ -135,28 +123,7 @@ namespace bpkg
int
compare (const version& v,
bool ignore_revision = false,
- bool ignore_iteration = false) const noexcept
- {
- if (epoch != v.epoch)
- return epoch < v.epoch ? -1 : 1;
-
- if (int c = canonical_upstream.compare (v.canonical_upstream))
- return c;
-
- if (int c = canonical_release.compare (v.canonical_release))
- return c;
-
- if (!ignore_revision)
- {
- if (revision != v.revision)
- return revision < v.revision ? -1 : 1;
-
- if (!ignore_iteration && iteration != v.iteration)
- return iteration < v.iteration ? -1 : 1;
- }
-
- return 0;
- }
+ bool ignore_iteration = false) const noexcept;
bool
empty () const noexcept
@@ -207,33 +174,10 @@ namespace bpkg
return os << (v.empty () ? "<empty-version>" : v.string ());
}
- inline version::flags
- operator&= (version::flags& x, version::flags y)
- {
- return x = static_cast<version::flags> (
- static_cast<std::uint16_t> (x) &
- static_cast<std::uint16_t> (y));
- }
-
- inline version::flags
- operator|= (version::flags& x, version::flags y)
- {
- return x = static_cast<version::flags> (
- static_cast<std::uint16_t> (x) |
- static_cast<std::uint16_t> (y));
- }
-
- inline version::flags
- operator& (version::flags x, version::flags y)
- {
- return x &= y;
- }
-
- inline version::flags
- operator| (version::flags x, version::flags y)
- {
- return x |= y;
- }
+ version::flags operator& (version::flags, version::flags);
+ version::flags operator| (version::flags, version::flags);
+ version::flags operator&= (version::flags&, version::flags);
+ version::flags operator|= (version::flags&, version::flags);
// priority
//
@@ -251,6 +195,17 @@ namespace bpkg
operator value_type () const {return value;}
};
+ // language
+ //
+ struct language
+ {
+ std::string name;
+ bool impl; // True if implementation-only.
+
+ language (): impl (false) {}
+ language (std::string n, bool i): name (std::move (n)), impl (i) {}
+ };
+
// description
// description-file
// change
@@ -415,17 +370,10 @@ namespace bpkg
}
inline bool
- operator== (const version_constraint& x, const version_constraint& y)
- {
- return x.min_version == y.min_version && x.max_version == y.max_version &&
- x.min_open == y.min_open && x.max_open == y.max_open;
- }
+ operator== (const version_constraint&, const version_constraint&);
inline bool
- operator!= (const version_constraint& x, const version_constraint& y)
- {
- return !(x == y);
- }
+ operator!= (const version_constraint&, const version_constraint&);
struct LIBBPKG_EXPORT dependency
{
@@ -447,11 +395,8 @@ namespace bpkg
string () const;
};
- inline std::ostream&
- operator<< (std::ostream& os, const dependency& d)
- {
- return os << d.string ();
- }
+ std::ostream&
+ operator<< (std::ostream&, const dependency&);
// depends
//
@@ -593,8 +538,13 @@ namespace bpkg
// Return true if the string() function would return the single-line
// representation.
//
- LIBBPKG_EXPORT bool
- single_line () const;
+ bool
+ single_line () const
+ {
+ return !prefer &&
+ !require &&
+ (!reflect || reflect->find ('\n') == std::string::npos);
+ }
};
inline std::ostream&
@@ -650,7 +600,7 @@ namespace bpkg
// Return true if there is a conditional alternative in the list.
//
- LIBBPKG_EXPORT bool
+ bool
conditional () const;
};
@@ -701,8 +651,11 @@ namespace bpkg
// Return true if the string() function would return the single-line
// representation.
//
- LIBBPKG_EXPORT bool
- single_line () const;
+ bool
+ single_line () const
+ {
+ return !reflect || reflect->find ('\n') == std::string::npos;
+ }
// Return true if this is a single requirement with an empty id or an
// empty enable condition.
@@ -755,7 +708,7 @@ namespace bpkg
// Return true if there is a conditional alternative in the list.
//
- LIBBPKG_EXPORT bool
+ bool
conditional () const;
// Return true if this is a single simple requirement alternative.
@@ -825,33 +778,17 @@ namespace bpkg
require_bootstrap_build = 0x100
};
- inline package_manifest_flags
- operator&= (package_manifest_flags& x, package_manifest_flags y)
- {
- return x = static_cast<package_manifest_flags> (
- static_cast<std::uint16_t> (x) &
- static_cast<std::uint16_t> (y));
- }
+ package_manifest_flags
+ operator& (package_manifest_flags, package_manifest_flags);
- inline package_manifest_flags
- operator|= (package_manifest_flags& x, package_manifest_flags y)
- {
- return x = static_cast<package_manifest_flags> (
- static_cast<std::uint16_t> (x) |
- static_cast<std::uint16_t> (y));
- }
+ package_manifest_flags
+ operator| (package_manifest_flags, package_manifest_flags);
- inline package_manifest_flags
- operator& (package_manifest_flags x, package_manifest_flags y)
- {
- return x &= y;
- }
+ package_manifest_flags
+ operator&= (package_manifest_flags&, package_manifest_flags);
- inline package_manifest_flags
- operator| (package_manifest_flags x, package_manifest_flags y)
- {
- return x |= y;
- }
+ package_manifest_flags
+ operator|= (package_manifest_flags&, package_manifest_flags);
// Target build configuration class term.
//
@@ -973,12 +910,7 @@ namespace bpkg
bool& result) const;
bool
- match (const strings& cs, const build_class_inheritance_map& bs) const
- {
- bool r (false);
- match (cs, bs, r);
- return r;
- }
+ match (const strings&, const build_class_inheritance_map&) const;
};
inline std::ostream&
@@ -1147,7 +1079,7 @@ namespace bpkg
//
// Note that the value format/semantics can be distribution-specific.
//
- struct LIBBPKG_EXPORT distribution_name_value
+ struct distribution_name_value
{
std::string name;
std::string value;
@@ -1174,11 +1106,13 @@ namespace bpkg
package_name name;
version_type version;
butl::optional<std::string> upstream_version;
+ butl::optional<std::string> type; // <name>[, ...]
+ butl::small_vector<language, 1> languages; // <name>[=impl][, ...]
butl::optional<package_name> project;
butl::optional<priority_type> priority;
std::string summary;
-
butl::small_vector<licenses, 1> license_alternatives;
+
butl::small_vector<std::string, 5> topics;
butl::small_vector<std::string, 5> keywords;
butl::optional<text_file> description;
@@ -1234,6 +1168,35 @@ namespace bpkg
butl::optional<std::string> sha256sum;
butl::optional<std::string> fragment;
+ // Translate optional type to either `exe`, `lib`, or `other`.
+ //
+ // Specifically, if type is present but is not one of the recognized
+ // names, then return `other`. If type is absent and the package name
+ // starts with the `lib` prefix, then return `lib`. Otherwise, return
+ // `exe`.
+ //
+ std::string
+ effective_type () const;
+
+ static std::string
+ effective_type (const butl::optional<std::string>&, const package_name&);
+
+ // Translate the potentially empty list of languages to a non-empty one.
+ //
+ // Specifically, if the list of languages is not empty, then return it as
+ // is. Otherwise, if the package name has an extension (as in, say,
+ // libbutl.bash), then return it as the language. Otherwise, return `cc`
+ // (unspecified c-common language).
+ //
+ butl::small_vector<language, 1>
+ effective_languages () const;
+
+ static butl::small_vector<language, 1>
+ effective_languages (const butl::small_vector<language, 1>&,
+ const package_name&);
+
+ // Return effective project name.
+ //
const package_name&
effective_project () const noexcept {return project ? *project : name;}
@@ -1417,13 +1380,10 @@ namespace bpkg
// Create individual package manifest.
//
- inline package_manifest
+ package_manifest
pkg_package_manifest (butl::manifest_parser& p,
bool ignore_unknown = false,
- bool complete_values = true)
- {
- return package_manifest (p, ignore_unknown, complete_values);
- }
+ bool complete_values = true);
LIBBPKG_EXPORT package_manifest
dir_package_manifest (butl::manifest_parser&, bool ignore_unknown = false);
@@ -1729,9 +1689,8 @@ namespace bpkg
repository_type,
const repository_location& base);
- repository_location (const repository_location& l,
- const repository_location& base)
- : repository_location (l.url (), l.type (), base) {}
+ repository_location (const repository_location&,
+ const repository_location& base);
// Note that relative locations have no canonical name. Canonical name of
// an empty location is the empty name.
@@ -1749,59 +1708,22 @@ namespace bpkg
empty () const noexcept {return url_.empty ();}
bool
- local () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return url_.scheme == repository_protocol::file;
- }
+ local () const;
bool
- remote () const
- {
- return !local ();
- }
+ remote () const;
bool
- absolute () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- // Note that in remote locations path is always relative.
- //
- return url_.path->absolute ();
- }
+ absolute () const;
bool
- relative () const
- {
- return local () && url_.path->relative ();
- }
+ relative () const;
repository_type
- type () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return type_;
- }
+ type () const;
repository_basis
- basis () const
- {
- switch (type ())
- {
- case repository_type::pkg: return repository_basis::archive;
- case repository_type::dir: return repository_basis::directory;
- case repository_type::git: return repository_basis::version_control;
- }
-
- assert (false); // Can't be here.
- return repository_basis::archive;
- }
+ basis () const;
// Note that the URL of an empty location is empty.
//
@@ -1815,69 +1737,30 @@ namespace bpkg
// "directories" it always contains the trailing slash.
//
const butl::path&
- path () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return *url_.path;
- }
+ path () const;
const std::string&
- host () const
- {
- if (local ())
- throw std::logic_error ("local location");
-
- return url_.authority->host;
- }
+ host () const;
// Value 0 indicated that no port was specified explicitly.
//
std::uint16_t
- port () const
- {
- if (local ())
- throw std::logic_error ("local location");
-
- return url_.authority->port;
- }
+ port () const;
repository_protocol
- proto () const
- {
- if (empty ())
- throw std::logic_error ("empty location");
-
- return url_.scheme;
- }
+ proto () const;
const butl::optional<std::string>&
- fragment () const
- {
- if (relative ())
- throw std::logic_error ("relative filesystem path");
-
- return url_.fragment;
- }
+ fragment () const;
bool
- archive_based () const
- {
- return basis () == repository_basis::archive;
- }
+ archive_based () const;
bool
- directory_based () const
- {
- return basis () == repository_basis::directory;
- }
+ directory_based () const;
bool
- version_control_based () const
- {
- return basis () == repository_basis::version_control;
- }
+ version_control_based () const;
// Return an untyped URL if the correct type can be guessed just from
// the URL. Otherwise, return the typed URL.
@@ -2174,4 +2057,6 @@ namespace bpkg
}
}
+#include <libbpkg/manifest.ixx>
+
#endif // LIBBPKG_MANIFEST_HXX
diff --git a/libbpkg/manifest.ixx b/libbpkg/manifest.ixx
new file mode 100644
index 0000000..d6eb4a6
--- /dev/null
+++ b/libbpkg/manifest.ixx
@@ -0,0 +1,402 @@
+// file : libbpkg/manifest.ixx -*- C++ -*-
+// license : MIT; see accompanying LICENSE file
+
+#include <stdexcept> // logic_error
+
+namespace bpkg
+{
+ // version
+ //
+ inline int version::
+ compare (const version& v, bool ir, bool ii) const noexcept
+ {
+ if (epoch != v.epoch)
+ return epoch < v.epoch ? -1 : 1;
+
+ if (int c = canonical_upstream.compare (v.canonical_upstream))
+ return c;
+
+ if (int c = canonical_release.compare (v.canonical_release))
+ return c;
+
+ if (!ir)
+ {
+ if (revision != v.revision)
+ return revision < v.revision ? -1 : 1;
+
+ if (!ii && iteration != v.iteration)
+ return iteration < v.iteration ? -1 : 1;
+ }
+
+ return 0;
+ }
+
+ inline bool version::
+ operator< (const version& v) const noexcept
+ {
+ return compare (v) < 0;
+ }
+
+ inline bool version::
+ operator> (const version& v) const noexcept
+ {
+ return compare (v) > 0;
+ }
+
+ inline bool version::
+ operator== (const version& v) const noexcept
+ {
+ return compare (v) == 0;
+ }
+
+ inline bool version::
+ operator<= (const version& v) const noexcept
+ {
+ return compare (v) <= 0;
+ }
+
+ inline bool version::
+ operator>= (const version& v) const noexcept
+ {
+ return compare (v) >= 0;
+ }
+
+ inline bool version::
+ operator!= (const version& v) const noexcept
+ {
+ return compare (v) != 0;
+ }
+
+ inline version::flags
+ operator&= (version::flags& x, version::flags y)
+ {
+ return x = static_cast<version::flags> (
+ static_cast<std::uint16_t> (x) &
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline version::flags
+ operator|= (version::flags& x, version::flags y)
+ {
+ return x = static_cast<version::flags> (
+ static_cast<std::uint16_t> (x) |
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline version::flags
+ operator& (version::flags x, version::flags y)
+ {
+ return x &= y;
+ }
+
+ inline version::flags
+ operator| (version::flags x, version::flags y)
+ {
+ return x |= y;
+ }
+
+ // version_constraint
+ //
+ inline bool
+ operator== (const version_constraint& x, const version_constraint& y)
+ {
+ return x.min_version == y.min_version && x.max_version == y.max_version &&
+ x.min_open == y.min_open && x.max_open == y.max_open;
+ }
+
+ inline bool
+ operator!= (const version_constraint& x, const version_constraint& y)
+ {
+ return !(x == y);
+ }
+
+ // dependency
+ //
+ inline std::string dependency::
+ string () const
+ {
+ std::string r (name.string ());
+
+ if (constraint)
+ {
+ r += ' ';
+ r += constraint->string ();
+ }
+
+ return r;
+ }
+
+ inline std::ostream&
+ operator<< (std::ostream& os, const dependency& d)
+ {
+ return os << d.string ();
+ }
+
+ // dependency_alternatives
+ //
+ inline bool dependency_alternatives::
+ conditional () const
+ {
+ for (const dependency_alternative& da: *this)
+ {
+ if (da.enable)
+ return true;
+ }
+
+ return false;
+ }
+
+ // requirement_alternatives
+ //
+ inline bool requirement_alternatives::
+ conditional () const
+ {
+ for (const requirement_alternative& ra: *this)
+ {
+ if (ra.enable)
+ return true;
+ }
+
+ return false;
+ }
+
+ // distribution_name_value
+ //
+ inline butl::optional<std::string> distribution_name_value::
+ distribution (const std::string& s) const
+ {
+ using namespace std;
+
+ size_t sn (s.size ());
+ size_t nn (name.size ());
+
+ if (nn > sn && name.compare (nn - sn, sn, s) == 0)
+ {
+ size_t p (name.find ('-'));
+
+ if (p == nn - sn)
+ return string (name, 0, p);
+ }
+
+ return butl::nullopt;
+ }
+
+ // package_manifest_flags
+ //
+ inline package_manifest_flags
+ operator&= (package_manifest_flags& x, package_manifest_flags y)
+ {
+ return x = static_cast<package_manifest_flags> (
+ static_cast<std::uint16_t> (x) &
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline package_manifest_flags
+ operator|= (package_manifest_flags& x, package_manifest_flags y)
+ {
+ return x = static_cast<package_manifest_flags> (
+ static_cast<std::uint16_t> (x) |
+ static_cast<std::uint16_t> (y));
+ }
+
+ inline package_manifest_flags
+ operator& (package_manifest_flags x, package_manifest_flags y)
+ {
+ return x &= y;
+ }
+
+ inline package_manifest_flags
+ operator| (package_manifest_flags x, package_manifest_flags y)
+ {
+ return x |= y;
+ }
+
+ // build_class_expr
+ //
+ inline bool build_class_expr::
+ match (const strings& cs, const build_class_inheritance_map& bs) const
+ {
+ bool r (false);
+ match (cs, bs, r);
+ return r;
+ }
+
+ // package_manifest
+ //
+ inline package_manifest::
+ package_manifest (butl::manifest_parser& p,
+ bool iu,
+ bool cv,
+ package_manifest_flags fl)
+ : package_manifest (p, std::function<translate_function> (), iu, cv, fl)
+ {
+ }
+
+ inline package_manifest
+ pkg_package_manifest (butl::manifest_parser& p, bool iu, bool cvs)
+ {
+ return package_manifest (p, iu, cvs);
+ }
+
+ inline std::string package_manifest::
+ effective_type (const butl::optional<std::string>& t, const package_name& n)
+ {
+ if (t)
+ return *t == "exe" || *t == "lib" ? *t : "other";
+
+ const std::string& s (n.string ());
+ return s.size () > 3 && s.compare (0, 3, "lib") == 0 ? "lib" : "exe";
+ }
+
+ inline std::string package_manifest::
+ effective_type () const
+ {
+ return effective_type (type, name);
+ }
+
+ inline butl::small_vector<language, 1> package_manifest::
+ effective_languages (const butl::small_vector<language, 1>& ls,
+ const package_name& n)
+ {
+ if (!ls.empty ())
+ return ls;
+
+ std::string ext (n.extension ());
+ return butl::small_vector<language, 1> (
+ 1,
+ language (!ext.empty () ? move (ext) : "cc", false /* impl */));
+ }
+
+ inline butl::small_vector<language, 1> package_manifest::
+ effective_languages () const
+ {
+ return effective_languages (languages, name);
+ }
+
+ // repository_location
+ //
+ inline repository_type repository_location::
+ type () const
+ {
+ if (empty ())
+ throw std::logic_error ("empty location");
+
+ return type_;
+ }
+
+ inline repository_location::
+ repository_location (const repository_location& l,
+ const repository_location& base)
+ : repository_location (l.url (), l.type (), base)
+ {
+ }
+
+ inline bool repository_location::
+ local () const
+ {
+ if (empty ())
+ throw std::logic_error ("empty location");
+
+ return url_.scheme == repository_protocol::file;
+ }
+
+ inline bool repository_location::
+ remote () const
+ {
+ return !local ();
+ }
+
+ inline bool repository_location::
+ absolute () const
+ {
+ if (empty ())
+ throw std::logic_error ("empty location");
+
+ // Note that in remote locations path is always relative.
+ //
+ return url_.path->absolute ();
+ }
+
+ inline bool repository_location::
+ relative () const
+ {
+ return local () && url_.path->relative ();
+ }
+
+ inline repository_basis repository_location::
+ basis () const
+ {
+ switch (type ())
+ {
+ case repository_type::pkg: return repository_basis::archive;
+ case repository_type::dir: return repository_basis::directory;
+ case repository_type::git: return repository_basis::version_control;
+ }
+
+ assert (false); // Can't be here.
+ return repository_basis::archive;
+ }
+
+ inline bool repository_location::
+ archive_based () const
+ {
+ return basis () == repository_basis::archive;
+ }
+
+ inline bool repository_location::
+ directory_based () const
+ {
+ return basis () == repository_basis::directory;
+ }
+
+ inline bool repository_location::
+ version_control_based () const
+ {
+ return basis () == repository_basis::version_control;
+ }
+
+ inline const butl::path& repository_location::
+ path () const
+ {
+ if (empty ())
+ throw std::logic_error ("empty location");
+
+ return *url_.path;
+ }
+
+ inline const std::string& repository_location::
+ host () const
+ {
+ if (local ())
+ throw std::logic_error ("local location");
+
+ return url_.authority->host;
+ }
+
+ inline std::uint16_t repository_location::
+ port () const
+ {
+ if (local ())
+ throw std::logic_error ("local location");
+
+ return url_.authority->port;
+ }
+
+ inline repository_protocol repository_location::
+ proto () const
+ {
+ if (empty ())
+ throw std::logic_error ("empty location");
+
+ return url_.scheme;
+ }
+
+ inline const butl::optional<std::string>& repository_location::
+ fragment () const
+ {
+ if (relative ())
+ throw std::logic_error ("relative filesystem path");
+
+ return url_.fragment;
+ }
+}
diff --git a/tests/manifest/testscript b/tests/manifest/testscript
index f4a5282..6f714ad 100644
--- a/tests/manifest/testscript
+++ b/tests/manifest/testscript
@@ -102,6 +102,176 @@
EOE
}
+ : type
+ :
+ {
+ : valid
+ :
+ $* <<EOF >>EOF
+ : 1
+ name: libfoo
+ version: 2.0.0
+ type: lib
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOF
+
+ : extras
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: foo
+ version: 2.0.0
+ type: bash, something extra
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+ : 1
+ name: foo
+ version: 2.0.0
+ type: bash
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOO
+
+ : duplicate
+ :
+ $* <<EOI 2>'stdin:5:1: error: package type redefinition' != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ type: lib
+ type: exe
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : empty
+ :
+ $* <<EOI 2>'stdin:4:6: error: empty package type' != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ type:
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : empty-extras
+ :
+ $* <<EOI 2>'stdin:4:7: error: empty package type' != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ type: , extras
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+ }
+
+ : language
+ :
+ {
+ : valid
+ :
+ $* <<EOF >>EOF
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language: c++
+ language: c=impl
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOF
+
+ : extras
+ :
+ $* <<EOI >>EOO
+ : 1
+ name: foo
+ version: 2.0.0
+ language: c++, something extra
+ language: c=impl, something extra
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+ : 1
+ name: foo
+ version: 2.0.0
+ language: c++
+ language: c=impl
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOO
+
+ : empty
+ :
+ $* <<EOI 2>'stdin:4:10: error: empty package language' != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language:
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : empty-extras
+ :
+ $* <<EOI 2>'stdin:4:11: error: empty package language' != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language: , extras
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : empty-impl
+ :
+ $* <<EOI 2>'stdin:4:11: error: empty package language' != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language: =impl
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : invalid-value
+ :
+ $* <<EOI 2>"stdin:4:11: error: unexpected 'imp' value after '='" != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language: c++=imp
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : empty-value
+ :
+ $* <<EOI 2>"stdin:4:11: error: expected 'impl' after '='" != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language: c++=
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+
+ : duplicate
+ :
+ $* <<EOI 2>"stdin:5:11: error: duplicate package language" != 0
+ : 1
+ name: libfoo
+ version: 2.0.0
+ language: c++=impl
+ language: c++
+ summary: Modern C++ parser
+ license: LGPLv2
+ EOI
+ }
+
: license
:
{
@@ -3897,6 +4067,8 @@
:
name: libfoo
version: 1.2.3+2
+ type: lib
+ language: c++
project: foo
priority: high; Due to critical bug fix.
summary: Modern XML parser