diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-03-12 15:43:17 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-03-12 15:43:17 +0200 |
commit | cf6b3e34b59ad120111e0c1ead779bbb3a70c38d (patch) | |
tree | 424e9def98c65d9080e72a69064334c6716fb82b /build/algorithm.cxx | |
parent | 5925c11a1fe8b2e02b790dd40b031ae005d5b68f (diff) |
Implement clean operation
Diffstat (limited to 'build/algorithm.cxx')
-rw-r--r-- | build/algorithm.cxx | 99 |
1 files changed, 86 insertions, 13 deletions
diff --git a/build/algorithm.cxx b/build/algorithm.cxx index 46387b3..cccda49 100644 --- a/build/algorithm.cxx +++ b/build/algorithm.cxx @@ -7,6 +7,7 @@ #include <memory> // unique_ptr #include <utility> // move #include <cassert> +#include <system_error> #include <build/path> #include <build/scope> @@ -15,6 +16,7 @@ #include <build/rule> #include <build/search> #include <build/utility> +#include <build/filesystem> #include <build/diagnostics> using namespace std; @@ -22,7 +24,7 @@ using namespace std; namespace build { target& - search (prerequisite& p) + search_impl (prerequisite& p) { assert (p.target == nullptr); @@ -149,24 +151,33 @@ namespace build search_and_match (action a, target& t) { for (prerequisite& p: t.prerequisites) + match (a, search (p)); + } + + void + search_and_match (action a, target& t, const path& d) + { + for (prerequisite& p: t.prerequisites) { - if (p.target == nullptr) - search (p); + target& pt (search (p)); - match (a, *p.target); + if (pt.dir.sub (d)) + match (a, pt); + else + p.target = nullptr; // Ignore. } } target_state - execute (action a, target& t) + execute_impl (action a, target& t) { // Implementation with some multi-threading ideas in mind. // - switch (target_state ts = t.state ()) + switch (target_state ts = t.state) { case target_state::unknown: { - t.state (target_state::failed); // So the rule can just throw. + t.state = target_state::failed; // So the rule can just throw. auto g ( make_exception_guard ( @@ -175,12 +186,17 @@ namespace build ts = t.recipe (a) (a, t); assert (ts != target_state::unknown && ts != target_state::failed); - t.state (ts); + + // The recipe may have set the target's state manually. + // + if (t.state == target_state::failed) + t.state = ts; + return ts; } case target_state::unchanged: case target_state::changed: - return ts; + assert (false); // Should have been handled by inline execute(). case target_state::failed: throw failed (); } @@ -193,9 +209,12 @@ namespace build for (const prerequisite& p: t.prerequisites) { - assert (p.target != nullptr); + if (p.target == nullptr) // Skip ignored. + continue; + + target& pt (*p.target); - if (execute (a, *p.target) != target_state::unchanged) + if (execute (a, pt) != target_state::unchanged) ts = target_state::changed; } @@ -209,9 +228,10 @@ namespace build for (const prerequisite& p: t.prerequisites) { - assert (p.target != nullptr); - target& pt (*p.target); + if (p.target == nullptr) // Skip ignored. + continue; + target& pt (*p.target); target_state ts (execute (a, pt)); if (!e) @@ -243,4 +263,57 @@ namespace build return e; } + + target_state + perform_clean_file (action a, target& t) + { + // The reverse order of update: first delete the file, then clean + // prerequisites. + // + file& ft (dynamic_cast<file&> (t)); + const path& f (ft.path ()); + + rmfile_status rs; + + // We don't want to print the command if we couldn't delete the + // file because it does not exist (just like we don't print the + // update command if the file is up to date). This makes the + // below code a bit ugly. + // + try + { + rs = try_rmfile (f); + } + catch (const system_error& e) + { + if (verb >= 1) + text << "rm " << f.string (); + else + text << "rm " << t; + + fail << "unable to delete file " << f.string () << ": " << e.what (); + } + + if (rs == rmfile_status::success) + { + if (verb >= 1) + text << "rm " << f.string (); + else + text << "rm " << t; + } + + // Update timestamp in case there are operations after us that + // could use the information. + // + ft.mtime (timestamp_nonexistent); + + // Clean prerequisites. + // + target_state ts (target_state::unchanged); + + if (!t.prerequisites.empty ()) + ts = execute_prerequisites (a, t); + + return rs == rmfile_status::success ? target_state::changed : ts; + } } |