From 10ea003c84f01b7b9685123291a19e9c562221f7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 19 May 2018 12:32:19 +0200 Subject: Implement manifest installation rule in version module --- build2/version/init.cxx | 85 +++++++++++++++-------------------------------- build2/version/module.hxx | 3 ++ build2/version/rule.cxx | 46 +++++++++++++++++++++++-- build2/version/rule.hxx | 15 +++++++++ 4 files changed, 87 insertions(+), 62 deletions(-) diff --git a/build2/version/init.cxx b/build2/version/init.cxx index c6729f1..e785efc 100644 --- a/build2/version/init.cxx +++ b/build2/version/init.cxx @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -18,6 +17,7 @@ #include #include +#include #include using namespace std; @@ -27,10 +27,11 @@ namespace build2 { namespace version { - static const path manifest ("manifest"); + static const path manifest_file ("manifest"); static const doc_rule doc_rule_; static const in_rule in_rule_; + static const manifest_install_rule manifest_install_rule_; bool boot (scope& rs, const location& l, unique_ptr& mod) @@ -47,7 +48,7 @@ namespace build2 standard_version v; dependency_constraints ds; { - path f (rs.src_path () / manifest); + path f (rs.src_path () / manifest_file); try { @@ -168,6 +169,7 @@ namespace build2 // snapshot number and id (e.g., commit date and id from git). // bool committed (true); + bool rewritten (false); if (v.snapshot () && v.snapshot_sn == standard_version::latest_sn) { snapshot ss (extract_snapshot (rs)); @@ -177,6 +179,7 @@ namespace build2 v.snapshot_sn = ss.sn; v.snapshot_id = move (ss.id); committed = ss.committed; + rewritten = true; } else committed = false; @@ -230,7 +233,7 @@ namespace build2 // Create the module. // - mod.reset (new module (move (v), committed, move (ds))); + mod.reset (new module (move (v), committed, rewritten, move (ds))); return true; // Init first (dist.package, etc). } @@ -286,10 +289,11 @@ namespace build2 p += v.string (); val = move (p); - // Only register the post-processing callback if this a snapshot. + // Only register the post-processing callback if this is a rewritten + // snapshot. // - if (v.snapshot ()) - dm->register_callback (dir_path (".") / manifest, + if (m.rewritten) + dm->register_callback (dir_path (".") / manifest_file, &dist_callback, &m); } @@ -339,6 +343,12 @@ namespace build2 r.insert (perform_update_id, "version.in", in_rule_); r.insert (perform_clean_id, "version.in", in_rule_); r.insert (configure_update_id, "version.in", in_rule_); + + if (cast_false (rs["install.booted"])) + { + r.insert ( + perform_install_id, "version.manifest", manifest_install_rule_); + } } return true; @@ -348,68 +358,25 @@ namespace build2 dist_callback (const path& f, const scope& rs, void* data) { module& m (*static_cast (data)); - const standard_version& v (m.version); // Complain if this is an uncommitted snapshot. // - if (v.snapshot () && !m.committed && !m.dist_uncommitted) + if (!m.committed && !m.dist_uncommitted) fail << "distribution of uncommitted project " << rs.src_path () << info << "specify config.dist.uncommitted=true to force"; - // The plan is simple, re-serialize the manifest into a temporary file - // fixing up the version. Then move the temporary file to the original. + // The plan is simple: fixing up the version in a temporary file then + // move it to the original. // - path t; try { - permissions perm (path_permissions (f)); - - ifdstream ifs (f); - manifest_parser p (ifs, f.string ()); - - t = path::temp_path ("manifest"); - auto_fd ofd (fdopen (t, - fdopen_mode::out | - fdopen_mode::create | - fdopen_mode::exclusive | - fdopen_mode::binary, - perm)); - auto_rmfile arm (t); // Try to remove on failure ignoring errors. - - ofdstream ofs (move (ofd)); - manifest_serializer s (ofs, t.string ()); - - manifest_name_value nv (p.next ()); - assert (nv.name.empty () && nv.value == "1"); // We just loaded it. - s.next (nv.name, nv.value); - - for (nv = p.next (); !nv.empty (); nv = p.next ()) - { - if (nv.name == "version") - nv.value = v.string (); - - s.next (nv.name, nv.value); - } - - s.next (nv.name, nv.value); // End of manifest. - s.next (nv.name, nv.value); // End of stream. - - ofs.close (); - ifs.close (); + auto_rmfile t (fixup_manifest (f, + path::temp_path ("manifest"), + m.version)); - mvfile (t, f, (cpflags::overwrite_content | - cpflags::overwrite_permissions)); - arm.cancel (); - } - catch (const manifest_parsing& e) - { - location l (&f, e.line, e.column); - fail (l) << e.description; - } - catch (const manifest_serialization& e) - { - location l (&t); - fail (l) << e.description; + mvfile (t.path, f, (cpflags::overwrite_content | + cpflags::overwrite_permissions)); + t.cancel (); } catch (const io_error& e) { diff --git a/build2/version/module.hxx b/build2/version/module.hxx index e057e7d..e24ce88 100644 --- a/build2/version/module.hxx +++ b/build2/version/module.hxx @@ -26,6 +26,7 @@ namespace build2 butl::standard_version version; bool committed; // Whether this is a committed snapshot. + bool rewritten; // Whether this is a rewritten .z snapshot. dependency_constraints dependencies; @@ -36,9 +37,11 @@ namespace build2 module (butl::standard_version v, bool c, + bool r, dependency_constraints d) : version (move (v)), committed (c), + rewritten (r), dependencies (move (d)) {} }; } diff --git a/build2/version/rule.cxx b/build2/version/rule.cxx index bbfe1f6..7fc8a2e 100644 --- a/build2/version/rule.cxx +++ b/build2/version/rule.cxx @@ -14,6 +14,7 @@ #include #include +#include using namespace std; using namespace butl; @@ -22,13 +23,15 @@ namespace build2 { namespace version { - // Return true if this prerequisite looks like a project's manifest file. - // To be sure we would need to search it into target but that we can't - // do in match(). + // Return true if this prerequisite is a project's manifest file. To be + // sure we would need to search it into target but that we can't do in + // match(). // static inline bool manifest_prerequisite (const scope& rs, const prerequisite_member& p) { + //@@ TODO: tighted to . + if (!p.is_a () || p.name () != "manifest") return false; @@ -672,5 +675,42 @@ namespace build2 t.mtime (system_clock::now ()); return target_state::changed; } + + // manifest_install_rule + // + bool manifest_install_rule:: + match (action a, target& t, const string&) const + { + // We only match project's manifest. + // + if (!t.is_a () || t.name != "manifest") + return false; + + // Must be in project's src_root. + // + const scope& s (t.base_scope ()); + if (s.root_scope () != &s || s.src_path () != t.dir) + return false; + + return file_rule::match (a, t, ""); + } + + auto_rmfile manifest_install_rule:: + install_pre (const file& t, const install_dir&) const + { + const path& p (t.path ()); + + const scope& rs (t.root_scope ()); + const module& m (*rs.modules.lookup (module::name)); + + if (!m.rewritten) + return auto_rmfile (p, false /* active */); + + // Our options are to use path::temp_path() or to create a .t file in + // the out tree. Somehow the latter feels more appropriate (even though + // if we crash in between, we won't clean it up). + // + return fixup_manifest (p, rs.out_path () / "manifest.t", m.version); + } } } diff --git a/build2/version/rule.hxx b/build2/version/rule.hxx index 9172ba3..bf8d05f 100644 --- a/build2/version/rule.hxx +++ b/build2/version/rule.hxx @@ -9,6 +9,7 @@ #include #include +#include namespace build2 { @@ -47,6 +48,20 @@ namespace build2 static target_state perform_update (action, const target&); }; + + // Pre-process manifest before installation to patch in the version. + // + class manifest_install_rule: public install::file_rule + { + public: + manifest_install_rule () {} + + virtual bool + match (action, target&, const string&) const override; + + virtual auto_rmfile + install_pre (const file&, const install_dir&) const override; + }; } } -- cgit v1.1