From 01226d547c006d29731747c2e8c9df4f9312815e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 1 Dec 2023 11:11:50 +0200 Subject: Make fsdir{} usable as target of ad hoc Buildscript recipes In particular, it can now be used to represent a directory symlink. For example: exe{hello}: ... fsdir{assets} fsdir{assets}: % update {{ ln -s $src_base/assets $out_base/assets }} % clean {{ rm $out_base/assets }} --- libbuild2/adhoc-rule-buildscript.cxx | 36 +++++++++++++++++++++++++++++++++--- libbuild2/build/script/runner.cxx | 8 ++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/libbuild2/adhoc-rule-buildscript.cxx b/libbuild2/adhoc-rule-buildscript.cxx index c3e559c..0395ccd 100644 --- a/libbuild2/adhoc-rule-buildscript.cxx +++ b/libbuild2/adhoc-rule-buildscript.cxx @@ -2336,9 +2336,34 @@ namespace build2 context& ctx (t.ctx); - execute_prerequisites (a, t); + target_state ts (target_state::unchanged); - if (!ctx.dry_run || verb != 0) + if (ctx.current_mode == execution_mode::first) + ts |= straight_execute_prerequisites (a, t); + + bool exec (!ctx.dry_run || verb != 0); + + // Special handling for fsdir{} (which is the recommended if somewhat + // hackish way to represent directory symlinks). See fsdir_rule for + // background. + // + // @@ Note that because there is no depdb, we cannot detect the target + // directory change (or any other changes in the script). + // + if (exec && + (a == perform_update_id || a == perform_clean_id) && + t.is_a ()) + { + // For update we only want to skip if it's a directory. For clean we + // want to (try) to clean up any filesystem entry, including a dangling + // symlink. + // + exec = a == perform_update_id + ? !exists (t.dir, true /* ignore_errors */) + : build2::entry_exists (t.dir, false /* follow_symlinks */); + } + + if (exec) { const scope& bs (t.base_scope ()); const scope& rs (*bs.root_scope ()); @@ -2394,9 +2419,14 @@ namespace build2 p.execute_body (rs, bs, e, script, r, !exec_diag /* enter */); } + + ts |= target_state::changed; } - return target_state::changed; + if (ctx.current_mode == execution_mode::last) + ts |= reverse_execute_prerequisites (a, t); + + return ts; } void adhoc_buildscript_rule:: diff --git a/libbuild2/build/script/runner.cxx b/libbuild2/build/script/runner.cxx index e08ebbf..5d9764b 100644 --- a/libbuild2/build/script/runner.cxx +++ b/libbuild2/build/script/runner.cxx @@ -43,6 +43,14 @@ namespace build2 } } } + else if (const fsdir* fd = env.target.is_a ()) + { + // Compare ignoring the trailing directory separator. + // + if (path_traits::compare (i->path.string (), + fd->dir.string ()) == 0) + m = fd; + } else { for (m = &env.target; m != nullptr; m = m->adhoc_member) -- cgit v1.1