diff options
Diffstat (limited to 'bpkg/system-package-manager-debian.cxx')
-rw-r--r-- | bpkg/system-package-manager-debian.cxx | 189 |
1 files changed, 182 insertions, 7 deletions
diff --git a/bpkg/system-package-manager-debian.cxx b/bpkg/system-package-manager-debian.cxx index 88bc6df..0670e24 100644 --- a/bpkg/system-package-manager-debian.cxx +++ b/bpkg/system-package-manager-debian.cxx @@ -1830,9 +1830,10 @@ namespace bpkg // system and install all the packages directly from their bpkg locations. // void system_package_manager_debian:: - generate (packages&& pkgs, - packages&& deps, - strings&&, + generate (const packages& pkgs, + const packages& deps, + const strings&, + const package_manifest& pm, const dir_path& out, optional<recursive_mode>) { @@ -1845,7 +1846,13 @@ namespace bpkg const shared_ptr<selected_package>& sp (pkgs.front ().first); const package_name& pn (sp->name); const version& pv (sp->version); - package_status s (map_package (pn, pv, pkgs.front ().second)); + + // @@ TODO: need to factor this to system_package_manager. + // + bool lib (pn.string ().compare (0, 3, "lib") == 0 && pn.string ().size () > 3); + + const available_packages& aps (pkgs.front ().second); + package_status st (map_package (pn, pv, aps)); vector<package_status> sdeps; sdeps.reserve (deps.size ()); @@ -1898,12 +1905,12 @@ namespace bpkg }; diag_record dr (text); - print_status (dr, s); + print_status (dr, st); - for (const package_status& ds: sdeps) + for (const package_status& st: sdeps) { dr << "\n "; - print_status (dr, ds); + print_status (dr, st); } } @@ -1934,6 +1941,172 @@ namespace bpkg dir_path deb (src / dir_path ("debian")); mk_p (deb); + // The control file. + // + // See the "Control files and their fields" chapter in the Debian Policy + // Manual for details (for example, which fields are mandatory). + // + // Note that we try to do a reasonably thorough job (e.g., filling in + // sections, etc) with the view that this can be used as a starting point + // for manual packaging (and perhaps we could add a mode for this in the + // future). + // + path ctrl (deb / "control"); + try + { + ofdstream os (ctrl); + + // First comes the general (source package) stanza. + // + // Note that Priority semantics is not the same as our priority. Rather + // it should reflect the overall functionality of the package. Our + // priority is more appropriately mapped to urgency in the changelog. + // + // If this is not a library, then by default we assume its some kind of + // a development tool and use the devel section. + // + string section ( + ops_->debian_section_specified () ? ops_->debian_section () : + lib ? "libs" : + "devel"); + + string priority ( + ops_->debian_priority_specified () ? ops_->debian_priority () : + "optional"); + + string maintainer ( + ops_->debian_maintainer_specified () ? ops_->debian_maintainer () : + pm.package_email ? static_cast<const string&> (*pm.package_email) : + pm.email ? static_cast<const string&> (*pm.email) : + string ()); + + if (maintainer.empty ()) + fail << "unable to determine package maintainer from manifest" << + info << "specify explicitly with --debian-maintainer"; + + optional<string> homepage (pm.package_url ? pm.package_url->string () : + pm.url ? pm.url->string () : + optional<string> ()); + + os << "Source: " << pn.string () << '\n' + << "Section: " << section << '\n' + << "Priority: " << priority << '\n' + << "Maintainer: " << maintainer << '\n' + << "Standards-Version: " << "4.6.2" << '\n' + << "Build-Depends: " << "debhelper-compat (= 13)" << '\n' + << "Rules-Requires-Root: " << "no" << '\n'; + if (homepage) + os << "Homepage: " << *homepage << '\n'; + if (pm.src_url) + os << "Vcs-Browser: " << pm.src_url->string () << '\n'; + + // Then we have one or more binary package stanzas. + // + // Note that values from the source package (such as Section, Priority) + // are used as defaults for the binary packages. + // + // We cannot easily detect architecture-independent packages (think + // libbutl.bash) and providing an option feels like the best we can do. + // Note that the value `any` means architecture-dependent while `all` + // means architecture-independent. + // + // The Multi-Arch hint can be `same` or `foreign`. The former means that + // a separate copy of the package may be installed for each architecture + // (e.g., library) while the latter -- that a single copy may be used by + // all architectures (e.g., executable, -doc, -common). Not that for + // some murky reasons Multi-Arch:foreign needs to be explicitly + // specified for Architecture:all. + // + // The Description field is quite messy: it requires both the short + // description (our summary) as a first line and a long description (our + // description) as the following lines in the multiline format. + // Converting our description to the Debian format is not going to be + // easy: it can be arbitrarily long and may not even be plain text (it's + // commonly the contents of the README.md file). So for now we fake it + // with a description of the package component. + // + string arch (ops_->debian_architecture_specified () + ? ops_->debian_architecture () + : "any"); + + string march (arch == "all" || !lib ? "foreign" : "same"); + + os << '\n' + << "Package: " << st.main << '\n' + << "Architecture: " << arch << '\n' + << "Multi-Arch: " << march << '\n' + << "Description: " << pm.summary << '\n' + << " This package contains the runtime files." << '\n'; + + // @@ Depends: common (if any) + + if (!st.dev.empty ()) + { + // Feels like the architecture should be the same as for the main + // package. + // + os << '\n' + << "Package: " << st.dev << '\n' + << "Section: " << (lib ? "libdevel" : "devel") << '\n' + << "Architecture: " << arch << '\n' + << "Multi-Arch: " << march << '\n'; + if (!st.doc.empty ()) + os << "Suggests: " << st.doc << '\n'; + os << "Description: " << pm.summary << '\n' + << " This package contains the development files." << '\n'; + + // @@ Depends: main + } + + if (!st.doc.empty ()) + { + os << '\n' + << "Package: " << st.doc << '\n' + << "Section: " << "doc" << '\n' + << "Architecture: " << "all" << '\n' + << "Multi-Arch: " << "foreign" << '\n' + << "Description: " << pm.summary << '\n' + << " This package contains the documentation." << '\n'; + } + + if (!st.dbg.empty ()) + { + os << '\n' + << "Package: " << st.dbg << '\n' + << "Section: " << "debug" << '\n' + << "Priority: " << "extra" << '\n' + << "Architecture: " << arch << '\n' + << "Multi-Arch: " << march << '\n' + << "Description: " << pm.summary << '\n' + << " This package contains the debugging information." << '\n'; + + // @@ Depends: main + } + + if (!st.common.empty ()) + { + // Generally, this package is not necessarily architecture-independent + // (for example, it could contain something shared between multiple + // binary packages produced from the same source package rather than + // something shared between all the architectures of a binary + // package). But seeing that we always generate one binary package, + // for us it only makes sense as architecture-independent. + // + os << '\n' + << "Package: " << st.common << '\n' + << "Architecture: " << "all" << '\n' + << "Multi-Arch: " << "foreign" << '\n' + << "Description: " << pm.summary << '\n' + << " This package contains the architecture-independent files." << '\n'; + } + + os.close (); + } + catch (const io_error& e) + { + fail << "unable to write to " << ctrl << ": " << e; + } + // The rules makefile. Note that it must be executable. // path rules (deb / "rules"); @@ -1959,6 +2132,8 @@ namespace bpkg else if (verb >= 2) os << "export DH_VERBOSE=1\n"; + // @@ TODO: remember to override config.install.sudo. + os.close (); } catch (const io_error& e) |