Browse Source

GlobPattern: support trailing slash and globstar (eg. **/*.egg)

rdb 8 years ago
parent
commit
29edf55069
1 changed files with 52 additions and 11 deletions
  1. 52 11
      dtool/src/dtoolutil/globPattern.cxx

+ 52 - 11
dtool/src/dtoolutil/globPattern.cxx

@@ -99,7 +99,7 @@ match_files(vector_string &results, const Filename &cwd) const {
     pattern = source;
     pattern = source;
   } else {
   } else {
     pattern = source.substr(0, slash);
     pattern = source.substr(0, slash);
-    suffix = source.substr(slash + 1);
+    suffix = source.substr(slash);
   }
   }
 
 
   GlobPattern glob(pattern);
   GlobPattern glob(pattern);
@@ -118,11 +118,21 @@ r_match_files(const Filename &prefix, const string &suffix,
   size_t slash = suffix.find('/');
   size_t slash = suffix.find('/');
   if (slash == string::npos) {
   if (slash == string::npos) {
     next_pattern = suffix;
     next_pattern = suffix;
+  } else if (slash + 1 == suffix.size()) {
+    // If the slash is at the end, we need to keep it, since it indicates that
+    // we only want to match directories.
+    next_pattern = suffix.substr(0, slash);
+    next_suffix = "/";
   } else {
   } else {
     next_pattern = suffix.substr(0, slash);
     next_pattern = suffix.substr(0, slash);
     next_suffix = suffix.substr(slash + 1);
     next_suffix = suffix.substr(slash + 1);
   }
   }
 
 
+  if (_pattern == "**" && next_pattern == "**") {
+    // Collapse consecutive globstar patterns.
+    return r_match_files(prefix, next_suffix, results, cwd);
+  }
+
   Filename parent_dir;
   Filename parent_dir;
   if (prefix.is_local() && !cwd.empty()) {
   if (prefix.is_local() && !cwd.empty()) {
     parent_dir = Filename(cwd, prefix);
     parent_dir = Filename(cwd, prefix);
@@ -136,19 +146,24 @@ r_match_files(const Filename &prefix, const string &suffix,
   if (!has_glob_characters()) {
   if (!has_glob_characters()) {
     // If there are no special characters in the pattern, it's a literal
     // If there are no special characters in the pattern, it's a literal
     // match.
     // match.
+    Filename fn(parent_dir, _pattern);
     if (suffix.empty()) {
     if (suffix.empty()) {
       // Time to stop.
       // Time to stop.
-      Filename single_filename(parent_dir, _pattern);
-      if (single_filename.exists()) {
+      if (fn.exists()) {
         results.push_back(Filename(prefix, _pattern));
         results.push_back(Filename(prefix, _pattern));
         return 1;
         return 1;
       }
       }
       return 0;
       return 0;
+    } else if (fn.is_directory()) {
+      // If the pattern ends with a slash, match a directory only.
+      if (suffix == "/") {
+        results.push_back(Filename(prefix, _pattern + "/"));
+        return 1;
+      } else {
+        return next_glob.r_match_files(Filename(prefix, _pattern),
+                                       next_suffix, results, cwd);
+      }
     }
     }
-
-    return next_glob.r_match_files(Filename(prefix, _pattern),
-                                   next_suffix, results, cwd);
-
   }
   }
 
 
   // If there *are* special glob characters, we must attempt to match the
   // If there *are* special glob characters, we must attempt to match the
@@ -164,18 +179,44 @@ r_match_files(const Filename &prefix, const string &suffix,
   // the pattern.
   // the pattern.
   int num_matched = 0;
   int num_matched = 0;
 
 
+  // A globstar pattern matches zero or more directories.
+  if (_pattern == "**") {
+    // Try to match this directory (as if the globstar wasn't there)
+    if (suffix.empty()) {
+      // This is a directory.  Add it.
+      results.push_back(Filename(prefix));
+      num_matched++;
+    } else if (suffix == "/") {
+      // Keep the trailing slash, but be sure not to duplicate it.
+      results.push_back(Filename(prefix, ""));
+      num_matched++;
+    } else {
+      num_matched += next_glob.r_match_files(prefix, next_suffix, results, cwd);
+    }
+    next_suffix = suffix;
+    next_glob = *this;
+  }
+
   vector_string::const_iterator fi;
   vector_string::const_iterator fi;
   for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
   for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
     const string &local_file = (*fi);
     const string &local_file = (*fi);
     if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
     if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
       if (matches(local_file)) {
       if (matches(local_file)) {
         // We have a match; continue.
         // We have a match; continue.
-        if (suffix.empty()) {
+        if (Filename(parent_dir, local_file).is_directory()) {
+          if (suffix.empty() && _pattern != "**") {
+            results.push_back(Filename(prefix, local_file));
+            num_matched++;
+          } else if (suffix == "/" && _pattern != "**") {
+            results.push_back(Filename(prefix, local_file + "/"));
+            num_matched++;
+          } else {
+            num_matched += next_glob.r_match_files(Filename(prefix, local_file),
+                                                   next_suffix, results, cwd);
+          }
+        } else if (suffix.empty()) {
           results.push_back(Filename(prefix, local_file));
           results.push_back(Filename(prefix, local_file));
           num_matched++;
           num_matched++;
-        } else {
-          num_matched += next_glob.r_match_files(Filename(prefix, local_file),
-                                                 next_suffix, results, cwd);
         }
         }
       }
       }
     }
     }