From a05e7b79c5e11c55262ea49099fceafe071a425f Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 22 Mar 2019 23:46:30 +0300 Subject: Skip git repository submodules with 'none' update method configured --- bpkg/fetch-git.cxx | 89 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/bpkg/fetch-git.cxx b/bpkg/fetch-git.cxx index ff53318..ce4046e 100644 --- a/bpkg/fetch-git.cxx +++ b/bpkg/fetch-git.cxx @@ -83,9 +83,28 @@ namespace bpkg return strings (); } + // Run git process and return it's output as a string if git exits with zero + // code and nullopt if it exits with the specified no-result indicating + // code. Fail if the output doesn't contain a single line. + // + // Note that the zero no-result code indicates that the result is not + // optional. A non-zero no-result code means that the requested string (for + // example configuration option value) is not available if git exits with + // this code. + // template - static string - git_line (const common_options&, const char* what, A&&... args); + static optional + git_line (const common_options&, + int no_result, + const char* what, + A&&... args); + + template + inline static string + git_line (const common_options& co, const char* what, A&&... args) + { + return *git_line (co, 0 /* no_result */, what, forward (args)...); + } // Start git process. On the first call check that git version is 2.11.0 or // above, and fail if that's not the case. Note that the full functionality @@ -285,12 +304,12 @@ namespace bpkg return run_git (co, true /* progress */, forward (args)...); } - // Run git process and return it's output as a string. Fail if the output - // doesn't contain a single line. - // template - static string - git_line (const common_options& co, const char* what, A&&... args) + static optional + git_line (const common_options& co, + int no_result, + const char* what, + A&&... args) { fdpipe pipe (open_pipe ()); process pr (start_git (co, pipe, 2 /* stderr */, forward (args)...)); @@ -320,6 +339,11 @@ namespace bpkg fail << "invalid " << what << endg; } + assert (pr.exit); + + if (pr.exit->normal () && pr.exit->code () == no_result) + return nullopt; + // Fall through. } catch (const io_error&) @@ -441,13 +465,18 @@ namespace bpkg // Get option from the specified configuration file. // - inline static string + inline static optional config_get (const common_options& co, const path& file, const string& key, + bool required, const char* what) { + // Note: `git config --get` command exits with the one code if the key + // wasn't found in the configuration file (see git-config(1) for details). + // return git_line (co, + required ? 0 : 1 /* no_result */, what, co.git_option (), "config", @@ -456,6 +485,15 @@ namespace bpkg key); } + inline static string + config_get (const common_options& co, + const path& file, + const string& key, + const char* what) + { + return *config_get (co, file, key, true /* required */, what); + } + // Get/set the repository remote URL. // static repository_url @@ -1661,6 +1699,8 @@ namespace bpkg // Submodule directory path, relative to the top repository. // dir_path psdir (prefix / sm.path); + + dir_path fsdir (dir / sm.path); // Submodule full directory path. string psd (psdir.posix_string ()); // For use in the diagnostics. string nm (git_line (co, "submodule name", @@ -1669,12 +1709,43 @@ namespace bpkg "submodule--helper", "name", sm.path)); + // The 'none' submodule working tree update method most likely + // indicates that the submodule is not currently used in the project. + // Let's skip such submodules as the `git submodule update` command does + // by default. + // + { + optional u (config_get (co, + mf, + "submodule." + nm + ".update", + false /* required */, + "submodule update method")); + + l4 ([&]{trace << "name: " << nm << ", " + << "update: " << (u ? *u : "[null]");}); + + if (u && *u == "none") + { + if (verb >= 2 && !co.no_progress ()) + text << "skipping submodule '" << psd << "'"; + + // Note that the submodule can be enabled for some other snapshot + // we are potentially switching from, and so the submodule + // directory can be non-empty. Let's clean the directory content up + // for good measure, not to confuse build2 operations. + // + if (exists (fsdir)) + rm_r (fsdir, false /* dir_itself */); + + continue; + } + } + string uo ("submodule." + nm + ".url"); string uv (config_get (co, dir, uo, "submodule URL")); l4 ([&]{trace << "name: " << nm << ", URL: " << uv;}); - dir_path fsdir (dir / sm.path); bool initialized (git_repository (fsdir)); // If the submodule is already initialized and its commit didn't -- cgit v1.1