aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2023-03-27 08:46:58 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2023-03-27 08:46:58 +0200
commitd38f564abaf6fcbc6c7cf2922f3e8f4c8327362f (patch)
tree07bd84e520a2ac9989237ccbcc8534e1c183ede4
parentb4179919e9456784d91e3ce2766c734213fe2945 (diff)
Add append/prepend support to pkg-bindist --{debian,archive}-build-meta
-rw-r--r--bpkg/pkg-bindist.cli19
-rw-r--r--bpkg/system-package-manager-archive.cxx200
-rw-r--r--bpkg/system-package-manager-debian.cxx29
3 files changed, 154 insertions, 94 deletions
diff --git a/bpkg/pkg-bindist.cli b/bpkg/pkg-bindist.cli
index c9a89da..fd2a197 100644
--- a/bpkg/pkg-bindist.cli
+++ b/bpkg/pkg-bindist.cli
@@ -259,7 +259,10 @@ namespace bpkg
string --debian-build-meta
{
"<data>",
- "Alternative build metadata to include in the binary package version.
+ "Alternative or additional build metadata to include in the binary
+ package version. If the specified value starts/ends with \cb{+} then
+ the value (with \cb{+} removed) is added after/before the default
+ metadata. Otherwise it is used as is instead of the default metadata.
If empty value is specified, then no build metadata is included. By
default, the build metadata is the \cb{ID} and \cb{VERSION_ID}
components from \cb{os-release(5)}, for example, \cb{debian10} in
@@ -568,8 +571,9 @@ namespace bpkg
details on the mapping semantics.
Instead of mapping languages individually you can specify entire build
- metadata as a single value with the \cb{--archive-build-meta}, for
- example:
+ metadata as a single value with the \cb{--archive-build-meta} (it is also
+ possible to add additional metadata; see the option documentation for
+ details). For example:
\
bpkg bindist \
@@ -695,9 +699,12 @@ namespace bpkg
string --archive-build-meta
{
"<data>",
- "Alternative build metadata to include after the version in the binary
- package directory and file names. If empty value is specified, then no
- build metadata is included."
+ "Alternative or additional build metadata to include after the version
+ in the binary package directory and file names. If the specified value
+ starts/ends with \cb{+} then the value (with \cb{+} removed) is added
+ after/before the default metadata. Otherwise it is used as is instead
+ of the default metadata. If empty value is specified, then no build
+ metadata is included."
}
dir_path --archive-install-root
diff --git a/bpkg/system-package-manager-archive.cxx b/bpkg/system-package-manager-archive.cxx
index b8df860..16e635d 100644
--- a/bpkg/system-package-manager-archive.cxx
+++ b/bpkg/system-package-manager-archive.cxx
@@ -3,6 +3,8 @@
#include <bpkg/system-package-manager-archive.hxx>
+#include <map>
+
#include <bpkg/diagnostics.hxx>
#include <bpkg/pkg-bindist-options.hxx>
@@ -503,93 +505,134 @@ namespace bpkg
// libhello-1.2.3-x86_64-debian11-gcc12-rust1.62
//
string base (pn.string () + '-' + pvs);
-
- if (ops->archive_build_meta_specified ())
- {
- if (!ops->archive_build_meta ().empty ())
- base += '-' + ops->archive_build_meta ();
- }
- else
{
- if (!ops->archive_no_cpu ())
- base += '-' + target.cpu;
-
- if (!ops->archive_no_os ())
- base += '-' + os_release.name_id + os_release.version_id;
-
- // First collect the interface languages and then add implementation.
- // This way if different languages map to the same runtimes (e.g., C and
- // C++ mapped to gcc12), then we will always prefer the interface
- // version over the implementation (which could be different, for
- // example, libstdc++6 vs libstdc++-12-dev; but it's not clear how this
- // will be specified, won't they end up with different names as opposed
- // to gcc6 and gcc12 -- still fuzzy/unclear).
- //
- // @@ We will need to split id and version to be able to pick the
- // highest version.
- //
- // @@ Maybe we should just do "soft" version like in <distribution>?
- //
- // Note that we allow multiple values for the same language to support
- // cases like --archive-lang cc=gcc12 --archive-lang cc=g++12.
- //
- vector<reference_wrapper<const pair<const string, string>>> langrt;
+ bool md_s (ops->archive_build_meta_specified ());
+ const string& md (ops->archive_build_meta ());
- auto find = [] (const std::multimap<string, string>& m, const string& n)
+ bool md_f (false);
+ bool md_b (false);
+ if (md_s && !md.empty ())
{
- auto p (m.equal_range (n));
+ md_f = md.front () == '+';
+ md_b = md.back () == '+';
+
+ if (md_f && md_b) // Note: covers just `+`.
+ fail << "invalid build metadata '" << md << "'";
+ }
- if (p.first == p.second)
+ if (md_s && !(md_f || md_b))
+ {
+ if (!md.empty ())
+ base += '-' + md;
+ }
+ else
+ {
+ if (md_b)
{
- // If no mapping for c/c++, fallback to cc.
- //
- if (n == "c" || n == "c++")
- p = m.equal_range ("cc");
+ base += '-';
+ base.append (md, 0, md.size () - 1);
}
- return p;
- };
+ if (!ops->archive_no_cpu ())
+ base += '-' + target.cpu;
- auto add = [&langrt] (const pair<const string, string>& p)
- {
- // Suppress duplicates.
+ if (!ops->archive_no_os ())
+ base += '-' + os_release.name_id + os_release.version_id;
+
+ // First collect the interface languages and then add implementation.
+ // This way if different languages map to the same runtimes (e.g., C
+ // and C++ mapped to gcc12), then we will always prefer the interface
+ // version over the implementation (which could be different, for
+ // example, libstdc++6 vs libstdc++-12-dev; but it's not clear how
+ // this will be specified, won't they end up with different names as
+ // opposed to gcc6 and gcc12 -- still fuzzy/unclear).
+ //
+ // @@ We will need to split id and version to be able to pick the
+ // highest version.
+ //
+ // @@ Maybe we should just do "soft" version like in <distribution>?
+ //
+ // Note that we allow multiple values for the same language to support
+ // cases like --archive-lang cc=gcc12 --archive-lang cc=g++12.
//
- if (find_if (langrt.begin (), langrt.end (),
- [&p] (const pair<const string, string>& x)
- {
- // @@ TODO: keep highest version.
+ vector<reference_wrapper<const pair<const string, string>>> langrt;
- return p.second == x.second;
- }) == langrt.end ())
+ auto find = [] (const std::multimap<string, string>& m,
+ const string& n)
{
- langrt.push_back (p);
- }
- };
+ auto p (m.equal_range (n));
- auto& implm (ops->archive_lang_impl ());
+ if (p.first == p.second)
+ {
+ // If no mapping for c/c++, fallback to cc.
+ //
+ if (n == "c" || n == "c++")
+ p = m.equal_range ("cc");
+ }
- // The interface/implementation distinction is only relevant to
- // libraries. For everything else we treat all the languages as
- // implementation.
- //
- if (lib)
- {
- auto& intfm (ops->archive_lang ());
+ return p;
+ };
+
+ auto add = [&langrt] (const pair<const string, string>& p)
+ {
+ // Suppress duplicates.
+ //
+ if (find_if (langrt.begin (), langrt.end (),
+ [&p] (const pair<const string, string>& x)
+ {
+ // @@ TODO: keep highest version.
+
+ return p.second == x.second;
+ }) == langrt.end ())
+ {
+ langrt.push_back (p);
+ }
+ };
+
+ auto& implm (ops->archive_lang_impl ());
+
+ // The interface/implementation distinction is only relevant to
+ // libraries. For everything else we treat all the languages as
+ // implementation.
+ //
+ if (lib)
+ {
+ auto& intfm (ops->archive_lang ());
+
+ for (const language& l: langs)
+ {
+ if (l.impl)
+ continue;
+
+ auto p (find (intfm, l.name));
+
+ if (p.first == p.second)
+ p = find (implm, l.name);
+
+ if (p.first == p.second)
+ fail << "no runtime mapping for language " << l.name <<
+ info << "consider specifying with --archive-lang[-impl]" <<
+ info << "or alternatively specify --archive-build-meta";
+
+ for (auto i (p.first); i != p.second; ++i)
+ {
+ if (i->second.empty ())
+ continue; // Unimportant.
+
+ add (*i);
+ }
+ }
+ }
for (const language& l: langs)
{
- if (l.impl)
+ if (lib && !l.impl)
continue;
- auto p (find (intfm, l.name));
+ auto p (find (implm, l.name));
if (p.first == p.second)
- p = find (implm, l.name);
-
- if (p.first == p.second)
- fail << "no runtime mapping for language " << l.name <<
- info << "consider specifying with --archive-lang[-impl]" <<
- info << "or alternatively specify --archive-build-meta";
+ continue; // Unimportant.
for (auto i (p.first); i != p.second; ++i)
{
@@ -599,29 +642,16 @@ namespace bpkg
add (*i);
}
}
- }
-
- for (const language& l: langs)
- {
- if (lib && !l.impl)
- continue;
-
- auto p (find (implm, l.name));
- if (p.first == p.second)
- continue; // Unimportant.
+ for (const pair<const string, string>& p: langrt)
+ base += '-' + p.second;
- for (auto i (p.first); i != p.second; ++i)
+ if (md_f)
{
- if (i->second.empty ())
- continue; // Unimportant.
-
- add (*i);
+ base += '-';
+ base.append (md, 1, md.size () - 1);
}
}
-
- for (const pair<const string, string>& p: langrt)
- base += '-' + p.second;
}
dir_path dst (out / dir_path (base));
diff --git a/bpkg/system-package-manager-debian.cxx b/bpkg/system-package-manager-debian.cxx
index b06487f..53d3a07 100644
--- a/bpkg/system-package-manager-debian.cxx
+++ b/bpkg/system-package-manager-debian.cxx
@@ -1849,13 +1849,36 @@ namespace bpkg
if (!no_build_metadata)
{
sv += '~';
- if (build_metadata)
- sv += *build_metadata;
- else
+
+ if (!build_metadata)
{
sv += os_release.name_id;
sv += os_release.version_id; // Could be empty.
}
+ else
+ {
+ const string& md (*build_metadata);
+
+ bool f (md.front () == '+');
+ bool b (md.back () == '+');
+
+ if (f && b) // Note: covers just `+`.
+ fail << "invalid build metadata '" << md << "'";
+
+ if (f || b)
+ {
+ if (b)
+ sv.append (md, 0, md.size () - 1);
+
+ sv += os_release.name_id;
+ sv += os_release.version_id;
+
+ if (f)
+ sv.append (md, 1, md.size () - 1);
+ }
+ else
+ sv += md;
+ }
}
return r;