// file : bpkg/manifest -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #ifndef BPKG_MANIFEST #define BPKG_MANIFEST #include #include #include // uint16_t #include #include // move() #include // logic_error #include #include namespace bpkg { class manifest_parser; class manifest_serializer; class manifest_name_value; using strings = std::vector; class version { public: // Create a special empty version. // version (): epoch_ (0), revision_ (0) {} explicit version (const std::string& v): version (v.c_str ()) /* Delegate */ {} explicit version (const char* v): version (v, false) /* Delegate */ {} // Create the version object from separate epoch, upstream, and // revision parts. // version (std::uint16_t epoch, std::string upstream, std::uint16_t revision) : version (upstream.c_str (), true) // Delegate { // Can't initialize in member initializer list due to construction // delegation. // epoch_ = epoch; revision_ = revision; } std::uint16_t epoch () const noexcept {return epoch_;} std::uint16_t revision () const noexcept {return revision_;} const std::string& upstream () const noexcept {return upstream_;} const std::string& canonical_upstream () const noexcept {return canonical_upstream_;} std::string string () const { const std::string& v ( epoch_ != 0 ? std::to_string (epoch_) + "+" + upstream_ : upstream_); return revision_ != 0 ? v + "-" + std::to_string (revision_) : v; } 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;} int compare (const version& v, bool ignore_revision = 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 (!ignore_revision && revision_ != v.revision_) return revision_ < v.revision_ ? -1 : 1; return 0; } bool empty () const noexcept { // No sense to test epoch and revision for 0 as properly constructed // version object can not have them different from 0 if upstream is // empty. Returns true only for objects constructed with the default // constructor. // return upstream_.empty (); } private: version (const char*, bool upstream_only); private: // Let's keep the members in the order they appear in the string // representation. // std::uint16_t epoch_; std::string upstream_; std::uint16_t revision_; std::string canonical_upstream_; // Upstream part canonical representation. }; inline std::ostream& operator<< (std::ostream& os, const version& v) {return os << v.string ();} // priority // class priority { public: enum value_type {low, medium, high, security}; value_type value; // Shouldn't be necessary to access directly. std::string comment; priority (value_type v = low, std::string c = "") : value (v), comment (std::move (c)) {} operator value_type () const {return value;} }; // description // description-file // class description: public std::string { public: bool file; std::string comment; // Description constructor. // explicit description (std::string d = "") : std::string (std::move (d)), file (false) {} // Description file constructor. // description (std::string f, std::string c) : std::string (std::move (f)), file (true), comment (std::move (c)) {} }; // license // class licenses: public strings { public: std::string comment; explicit licenses (std::string c = ""): comment (std::move (c)) {} }; // change // change-file // class change: public std::string { public: bool file; std::string comment; // Change constructor. // explicit change (std::string c = ""): std::string (std::move (c)), file (false) {} // Change file constructor. // change (std::string f, std::string c) : std::string (std::move (f)), file (true), comment (std::move (c)) {} }; // url // package-url // class url: public std::string { public: std::string comment; explicit url (std::string u = "", std::string c = "") : std::string (std::move (u)), comment (std::move (c)) {} }; // email // package-email // class email: public std::string { public: std::string comment; explicit email (std::string e = "", std::string c = "") : std::string (std::move (e)), comment (std::move (c)) {} }; // depends // enum class comparison {eq, lt, gt, le, ge}; struct version_comparison { version value; comparison operation; }; struct dependency { std::string package; butl::optional version; }; class dependency_alternatives: public std::vector { public: bool conditional; std::string comment; explicit dependency_alternatives (bool d = false, std::string c = "") : conditional (d), comment (std::move (c)) {} }; // requires // class requirement_alternatives: public strings { public: bool conditional; std::string comment; explicit requirement_alternatives (bool d = false, std::string c = "") : conditional (d), comment (std::move (c)) {} }; class package_manifest { public: using version_type = bpkg::version; using priority_type = bpkg::priority; using url_type = bpkg::url; using email_type = bpkg::email; using description_type = bpkg::description; std::string name; version_type version; butl::optional priority; std::string summary; std::vector license_alternatives; strings tags; butl::optional description; std::vector changes; url_type url; butl::optional package_url; email_type email; butl::optional package_email; std::vector dependencies; std::vector requirements; public: package_manifest (manifest_parser&); package_manifest (manifest_parser&, manifest_name_value start); void serialize (manifest_serializer&) const; }; class repository_location { public: // Create a special empty repository_location. // repository_location () = default; // Creates remote/absolute repository location. Throws invalid_argument // if the location is a relative path. // explicit repository_location (const std::string&); // Creates a potentially relative repository location. If base is not // empty, use it to complete the relative location to remote/absolute. // Throws invalid_argument if base itself is relative or the resulting // completed location is invalid. // repository_location (const std::string&, const repository_location& base); // Note that relative locations have no canonical name. // const std::string& canonical_name () const noexcept {return canonical_name_;} // There are 3 types of locations: remote, local absolute filesystem // path and local relative filesystem path. Plus there is the special // empty location. The following predicates can be used to determine // what kind of location it is. Note that except for empty(), all the // other predicates throw std::logic_error for an empty location. // bool empty () const noexcept {return path_.empty ();} bool local () const { if (empty ()) throw std::logic_error ("empty location"); return host_.empty (); } bool remote () const { return !local (); } bool absolute () const { return local () && path_.absolute (); } bool relative () const { if (empty ()) throw std::logic_error ("empty location"); // Note that in remote locations path is always absolute. // return path_.relative (); } const butl::dir_path& path () const { if (empty ()) throw std::logic_error ("empty location"); return path_; } const std::string& host () const { if (local ()) throw std::logic_error ("local location"); return host_; } // Value 0 indicated that no port was specified explicitly. // std::uint16_t port () const { if (local ()) throw std::logic_error ("local location"); return port_; } // Note that this is not necessarily syntactically the same // string as what was used to initialize this location. But // it should be semantically equivalent. // std::string string () const; private: std::string canonical_name_; std::string host_; std::uint16_t port_; butl::dir_path path_; }; class repository_manifest { public: repository_location location; public: repository_manifest (manifest_parser&); repository_manifest (manifest_parser&, manifest_name_value start); void serialize (manifest_serializer&) const; }; class manifests { public: std::vector repositories; std::vector packages; public: manifests (manifest_parser&); void serialize (manifest_serializer&) const; }; } #endif // BPKG_MANIFEST