Merge branch 'bw/pathspec-cleanup'
Code clean-up in the pathspec API. * bw/pathspec-cleanup: pathspec: rename prefix_pathspec to init_pathspec_item pathspec: small readability changes pathspec: create strip submodule slash helpers pathspec: create parse_element_magic helper pathspec: create parse_long_magic function pathspec: create parse_short_magic function pathspec: factor global magic into its own function pathspec: simpler logic to prefix original pathspec elements pathspec: always show mnemonic and name in unsupported_magic pathspec: remove unused variable from unsupported_magic pathspec: copy and free owned memory pathspec: remove the deprecated get_pathspec function ls-tree: convert show_recursive to use the pathspec struct interface dir: convert fill_directory to use the pathspec struct interface dir: remove struct path_simplify mv: remove use of deprecated 'get_pathspec()'
This commit is contained in:
commit
fe9ec8bdf6
@ -27,8 +27,6 @@ parse_pathspec(). This function takes several arguments:
|
|||||||
|
|
||||||
- prefix and args come from cmd_* functions
|
- prefix and args come from cmd_* functions
|
||||||
|
|
||||||
get_pathspec() is obsolete and should never be used in new code.
|
|
||||||
|
|
||||||
parse_pathspec() helps catch unsupported features and reject them
|
parse_pathspec() helps catch unsupported features and reject them
|
||||||
politely. At a lower level, different pathspec-related functions may
|
politely. At a lower level, different pathspec-related functions may
|
||||||
not support the same set of features. Such pathspec-sensitive
|
not support the same set of features. Such pathspec-sensitive
|
||||||
|
@ -31,21 +31,18 @@ static const char * const ls_tree_usage[] = {
|
|||||||
|
|
||||||
static int show_recursive(const char *base, int baselen, const char *pathname)
|
static int show_recursive(const char *base, int baselen, const char *pathname)
|
||||||
{
|
{
|
||||||
const char **s;
|
int i;
|
||||||
|
|
||||||
if (ls_options & LS_RECURSIVE)
|
if (ls_options & LS_RECURSIVE)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
s = pathspec._raw;
|
if (!pathspec.nr)
|
||||||
if (!s)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (;;) {
|
for (i = 0; i < pathspec.nr; i++) {
|
||||||
const char *spec = *s++;
|
const char *spec = pathspec.items[i].match;
|
||||||
int len, speclen;
|
int len, speclen;
|
||||||
|
|
||||||
if (!spec)
|
|
||||||
return 0;
|
|
||||||
if (strncmp(base, spec, baselen))
|
if (strncmp(base, spec, baselen))
|
||||||
continue;
|
continue;
|
||||||
len = strlen(pathname);
|
len = strlen(pathname);
|
||||||
@ -59,6 +56,7 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
|
|||||||
continue;
|
continue;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_tree(const unsigned char *sha1, struct strbuf *base,
|
static int show_tree(const unsigned char *sha1, struct strbuf *base,
|
||||||
@ -175,8 +173,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
|
|||||||
* cannot be lifted until it is converted to use
|
* cannot be lifted until it is converted to use
|
||||||
* match_pathspec() or tree_entry_interesting()
|
* match_pathspec() or tree_entry_interesting()
|
||||||
*/
|
*/
|
||||||
parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
|
parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
|
||||||
PATHSPEC_EXCLUDE,
|
~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
|
||||||
PATHSPEC_PREFER_CWD,
|
PATHSPEC_PREFER_CWD,
|
||||||
prefix, argv + 1);
|
prefix, argv + 1);
|
||||||
for (i = 0; i < pathspec.nr; i++)
|
for (i = 0; i < pathspec.nr; i++)
|
||||||
|
50
builtin/mv.c
50
builtin/mv.c
@ -4,6 +4,7 @@
|
|||||||
* Copyright (C) 2006 Johannes Schindelin
|
* Copyright (C) 2006 Johannes Schindelin
|
||||||
*/
|
*/
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
#include "pathspec.h"
|
||||||
#include "lockfile.h"
|
#include "lockfile.h"
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
@ -19,31 +20,42 @@ static const char * const builtin_mv_usage[] = {
|
|||||||
#define DUP_BASENAME 1
|
#define DUP_BASENAME 1
|
||||||
#define KEEP_TRAILING_SLASH 2
|
#define KEEP_TRAILING_SLASH 2
|
||||||
|
|
||||||
static const char **internal_copy_pathspec(const char *prefix,
|
static const char **internal_prefix_pathspec(const char *prefix,
|
||||||
const char **pathspec,
|
const char **pathspec,
|
||||||
int count, unsigned flags)
|
int count, unsigned flags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
const char **result;
|
const char **result;
|
||||||
|
int prefixlen = prefix ? strlen(prefix) : 0;
|
||||||
ALLOC_ARRAY(result, count + 1);
|
ALLOC_ARRAY(result, count + 1);
|
||||||
COPY_ARRAY(result, pathspec, count);
|
|
||||||
result[count] = NULL;
|
/* Create an intermediate copy of the pathspec based on the flags */
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
int length = strlen(result[i]);
|
int length = strlen(pathspec[i]);
|
||||||
int to_copy = length;
|
int to_copy = length;
|
||||||
|
char *it;
|
||||||
while (!(flags & KEEP_TRAILING_SLASH) &&
|
while (!(flags & KEEP_TRAILING_SLASH) &&
|
||||||
to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
|
to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
|
||||||
to_copy--;
|
to_copy--;
|
||||||
if (to_copy != length || flags & DUP_BASENAME) {
|
|
||||||
char *it = xmemdupz(result[i], to_copy);
|
it = xmemdupz(pathspec[i], to_copy);
|
||||||
if (flags & DUP_BASENAME) {
|
if (flags & DUP_BASENAME) {
|
||||||
result[i] = xstrdup(basename(it));
|
result[i] = xstrdup(basename(it));
|
||||||
free(it);
|
free(it);
|
||||||
} else
|
} else {
|
||||||
result[i] = it;
|
result[i] = it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return get_pathspec(prefix, result);
|
result[count] = NULL;
|
||||||
|
|
||||||
|
/* Prefix the pathspec and free the old intermediate strings */
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
const char *match = prefix_path(prefix, prefixlen, result[i]);
|
||||||
|
free((char *) result[i]);
|
||||||
|
result[i] = match;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *add_slash(const char *path)
|
static const char *add_slash(const char *path)
|
||||||
@ -130,7 +142,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||||||
if (read_cache() < 0)
|
if (read_cache() < 0)
|
||||||
die(_("index file corrupt"));
|
die(_("index file corrupt"));
|
||||||
|
|
||||||
source = internal_copy_pathspec(prefix, argv, argc, 0);
|
source = internal_prefix_pathspec(prefix, argv, argc, 0);
|
||||||
modes = xcalloc(argc, sizeof(enum update_mode));
|
modes = xcalloc(argc, sizeof(enum update_mode));
|
||||||
/*
|
/*
|
||||||
* Keep trailing slash, needed to let
|
* Keep trailing slash, needed to let
|
||||||
@ -140,16 +152,16 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
|
|||||||
flags = KEEP_TRAILING_SLASH;
|
flags = KEEP_TRAILING_SLASH;
|
||||||
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
|
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
|
||||||
flags = 0;
|
flags = 0;
|
||||||
dest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);
|
dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
|
||||||
submodule_gitfile = xcalloc(argc, sizeof(char *));
|
submodule_gitfile = xcalloc(argc, sizeof(char *));
|
||||||
|
|
||||||
if (dest_path[0][0] == '\0')
|
if (dest_path[0][0] == '\0')
|
||||||
/* special case: "." was normalized to "" */
|
/* special case: "." was normalized to "" */
|
||||||
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||||
else if (!lstat(dest_path[0], &st) &&
|
else if (!lstat(dest_path[0], &st) &&
|
||||||
S_ISDIR(st.st_mode)) {
|
S_ISDIR(st.st_mode)) {
|
||||||
dest_path[0] = add_slash(dest_path[0]);
|
dest_path[0] = add_slash(dest_path[0]);
|
||||||
destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
|
||||||
} else {
|
} else {
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
die(_("destination '%s' is not a directory"), dest_path[0]);
|
die(_("destination '%s' is not a directory"), dest_path[0]);
|
||||||
|
1
cache.h
1
cache.h
@ -514,7 +514,6 @@ extern void set_git_work_tree(const char *tree);
|
|||||||
|
|
||||||
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
|
||||||
|
|
||||||
extern const char **get_pathspec(const char *prefix, const char **pathspec);
|
|
||||||
extern void setup_work_tree(void);
|
extern void setup_work_tree(void);
|
||||||
extern const char *setup_git_directory_gently(int *);
|
extern const char *setup_git_directory_gently(int *);
|
||||||
extern const char *setup_git_directory(void);
|
extern const char *setup_git_directory(void);
|
||||||
|
189
dir.c
189
dir.c
@ -16,11 +16,6 @@
|
|||||||
#include "varint.h"
|
#include "varint.h"
|
||||||
#include "ewah/ewok.h"
|
#include "ewah/ewok.h"
|
||||||
|
|
||||||
struct path_simplify {
|
|
||||||
int len;
|
|
||||||
const char *path;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tells read_directory_recursive how a file or directory should be treated.
|
* Tells read_directory_recursive how a file or directory should be treated.
|
||||||
* Values are ordered by significance, e.g. if a directory contains both
|
* Values are ordered by significance, e.g. if a directory contains both
|
||||||
@ -50,7 +45,7 @@ struct cached_dir {
|
|||||||
|
|
||||||
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
||||||
const char *path, int len, struct untracked_cache_dir *untracked,
|
const char *path, int len, struct untracked_cache_dir *untracked,
|
||||||
int check_only, const struct path_simplify *simplify);
|
int check_only, const struct pathspec *pathspec);
|
||||||
static int get_dtype(struct dirent *de, const char *path, int len);
|
static int get_dtype(struct dirent *de, const char *path, int len);
|
||||||
|
|
||||||
int fspathcmp(const char *a, const char *b)
|
int fspathcmp(const char *a, const char *b)
|
||||||
@ -179,17 +174,21 @@ char *common_prefix(const struct pathspec *pathspec)
|
|||||||
|
|
||||||
int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
|
int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
size_t len;
|
char *prefix;
|
||||||
|
size_t prefix_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate common prefix for the pathspec, and
|
* Calculate common prefix for the pathspec, and
|
||||||
* use that to optimize the directory walk
|
* use that to optimize the directory walk
|
||||||
*/
|
*/
|
||||||
len = common_prefix_len(pathspec);
|
prefix = common_prefix(pathspec);
|
||||||
|
prefix_len = prefix ? strlen(prefix) : 0;
|
||||||
|
|
||||||
/* Read the directory and prune it */
|
/* Read the directory and prune it */
|
||||||
read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
|
read_directory(dir, prefix, prefix_len, pathspec);
|
||||||
return len;
|
|
||||||
|
free(prefix);
|
||||||
|
return prefix_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int within_depth(const char *name, int namelen,
|
int within_depth(const char *name, int namelen,
|
||||||
@ -1312,7 +1311,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
|
|||||||
static enum path_treatment treat_directory(struct dir_struct *dir,
|
static enum path_treatment treat_directory(struct dir_struct *dir,
|
||||||
struct untracked_cache_dir *untracked,
|
struct untracked_cache_dir *untracked,
|
||||||
const char *dirname, int len, int baselen, int exclude,
|
const char *dirname, int len, int baselen, int exclude,
|
||||||
const struct path_simplify *simplify)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
/* The "len-1" is to strip the final '/' */
|
/* The "len-1" is to strip the final '/' */
|
||||||
switch (directory_exists_in_index(dirname, len-1)) {
|
switch (directory_exists_in_index(dirname, len-1)) {
|
||||||
@ -1341,7 +1340,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
|||||||
untracked = lookup_untracked(dir->untracked, untracked,
|
untracked = lookup_untracked(dir->untracked, untracked,
|
||||||
dirname + baselen, len - baselen);
|
dirname + baselen, len - baselen);
|
||||||
return read_directory_recursive(dir, dirname, len,
|
return read_directory_recursive(dir, dirname, len,
|
||||||
untracked, 1, simplify);
|
untracked, 1, pathspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1349,24 +1348,33 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
|
|||||||
* reading - if the path cannot possibly be in the pathspec,
|
* reading - if the path cannot possibly be in the pathspec,
|
||||||
* return true, and we'll skip it early.
|
* return true, and we'll skip it early.
|
||||||
*/
|
*/
|
||||||
static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)
|
static int simplify_away(const char *path, int pathlen,
|
||||||
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
if (simplify) {
|
int i;
|
||||||
for (;;) {
|
|
||||||
const char *match = simplify->path;
|
|
||||||
int len = simplify->len;
|
|
||||||
|
|
||||||
if (!match)
|
if (!pathspec || !pathspec->nr)
|
||||||
break;
|
return 0;
|
||||||
if (len > pathlen)
|
|
||||||
len = pathlen;
|
GUARD_PATHSPEC(pathspec,
|
||||||
if (!memcmp(path, match, len))
|
PATHSPEC_FROMTOP |
|
||||||
return 0;
|
PATHSPEC_MAXDEPTH |
|
||||||
simplify++;
|
PATHSPEC_LITERAL |
|
||||||
}
|
PATHSPEC_GLOB |
|
||||||
return 1;
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
|
for (i = 0; i < pathspec->nr; i++) {
|
||||||
|
const struct pathspec_item *item = &pathspec->items[i];
|
||||||
|
int len = item->nowildcard_len;
|
||||||
|
|
||||||
|
if (len > pathlen)
|
||||||
|
len = pathlen;
|
||||||
|
if (!ps_strncmp(item, item->match, path, len))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1380,19 +1388,33 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
|
|||||||
* 2. the path is a directory prefix of some element in the
|
* 2. the path is a directory prefix of some element in the
|
||||||
* pathspec
|
* pathspec
|
||||||
*/
|
*/
|
||||||
static int exclude_matches_pathspec(const char *path, int len,
|
static int exclude_matches_pathspec(const char *path, int pathlen,
|
||||||
const struct path_simplify *simplify)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
if (simplify) {
|
int i;
|
||||||
for (; simplify->path; simplify++) {
|
|
||||||
if (len == simplify->len
|
if (!pathspec || !pathspec->nr)
|
||||||
&& !memcmp(path, simplify->path, len))
|
return 0;
|
||||||
return 1;
|
|
||||||
if (len < simplify->len
|
GUARD_PATHSPEC(pathspec,
|
||||||
&& simplify->path[len] == '/'
|
PATHSPEC_FROMTOP |
|
||||||
&& !memcmp(path, simplify->path, len))
|
PATHSPEC_MAXDEPTH |
|
||||||
return 1;
|
PATHSPEC_LITERAL |
|
||||||
}
|
PATHSPEC_GLOB |
|
||||||
|
PATHSPEC_ICASE |
|
||||||
|
PATHSPEC_EXCLUDE);
|
||||||
|
|
||||||
|
for (i = 0; i < pathspec->nr; i++) {
|
||||||
|
const struct pathspec_item *item = &pathspec->items[i];
|
||||||
|
int len = item->nowildcard_len;
|
||||||
|
|
||||||
|
if (len == pathlen &&
|
||||||
|
!ps_strncmp(item, item->match, path, pathlen))
|
||||||
|
return 1;
|
||||||
|
if (len > pathlen &&
|
||||||
|
item->match[pathlen] == '/' &&
|
||||||
|
!ps_strncmp(item, item->match, path, pathlen))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1460,7 +1482,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
|
|||||||
struct untracked_cache_dir *untracked,
|
struct untracked_cache_dir *untracked,
|
||||||
struct strbuf *path,
|
struct strbuf *path,
|
||||||
int baselen,
|
int baselen,
|
||||||
const struct path_simplify *simplify,
|
const struct pathspec *pathspec,
|
||||||
int dtype, struct dirent *de)
|
int dtype, struct dirent *de)
|
||||||
{
|
{
|
||||||
int exclude;
|
int exclude;
|
||||||
@ -1512,7 +1534,7 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
|
|||||||
case DT_DIR:
|
case DT_DIR:
|
||||||
strbuf_addch(path, '/');
|
strbuf_addch(path, '/');
|
||||||
return treat_directory(dir, untracked, path->buf, path->len,
|
return treat_directory(dir, untracked, path->buf, path->len,
|
||||||
baselen, exclude, simplify);
|
baselen, exclude, pathspec);
|
||||||
case DT_REG:
|
case DT_REG:
|
||||||
case DT_LNK:
|
case DT_LNK:
|
||||||
return exclude ? path_excluded : path_untracked;
|
return exclude ? path_excluded : path_untracked;
|
||||||
@ -1524,7 +1546,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
|
|||||||
struct cached_dir *cdir,
|
struct cached_dir *cdir,
|
||||||
struct strbuf *path,
|
struct strbuf *path,
|
||||||
int baselen,
|
int baselen,
|
||||||
const struct path_simplify *simplify)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
strbuf_setlen(path, baselen);
|
strbuf_setlen(path, baselen);
|
||||||
if (!cdir->ucd) {
|
if (!cdir->ucd) {
|
||||||
@ -1541,7 +1563,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
|
|||||||
* with check_only set.
|
* with check_only set.
|
||||||
*/
|
*/
|
||||||
return read_directory_recursive(dir, path->buf, path->len,
|
return read_directory_recursive(dir, path->buf, path->len,
|
||||||
cdir->ucd, 1, simplify);
|
cdir->ucd, 1, pathspec);
|
||||||
/*
|
/*
|
||||||
* We get path_recurse in the first run when
|
* We get path_recurse in the first run when
|
||||||
* directory_exists_in_index() returns index_nonexistent. We
|
* directory_exists_in_index() returns index_nonexistent. We
|
||||||
@ -1556,23 +1578,23 @@ static enum path_treatment treat_path(struct dir_struct *dir,
|
|||||||
struct cached_dir *cdir,
|
struct cached_dir *cdir,
|
||||||
struct strbuf *path,
|
struct strbuf *path,
|
||||||
int baselen,
|
int baselen,
|
||||||
const struct path_simplify *simplify)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
int dtype;
|
int dtype;
|
||||||
struct dirent *de = cdir->de;
|
struct dirent *de = cdir->de;
|
||||||
|
|
||||||
if (!de)
|
if (!de)
|
||||||
return treat_path_fast(dir, untracked, cdir, path,
|
return treat_path_fast(dir, untracked, cdir, path,
|
||||||
baselen, simplify);
|
baselen, pathspec);
|
||||||
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
|
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
|
||||||
return path_none;
|
return path_none;
|
||||||
strbuf_setlen(path, baselen);
|
strbuf_setlen(path, baselen);
|
||||||
strbuf_addstr(path, de->d_name);
|
strbuf_addstr(path, de->d_name);
|
||||||
if (simplify_away(path->buf, path->len, simplify))
|
if (simplify_away(path->buf, path->len, pathspec))
|
||||||
return path_none;
|
return path_none;
|
||||||
|
|
||||||
dtype = DTYPE(de);
|
dtype = DTYPE(de);
|
||||||
return treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);
|
return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_untracked(struct untracked_cache_dir *dir, const char *name)
|
static void add_untracked(struct untracked_cache_dir *dir, const char *name)
|
||||||
@ -1703,7 +1725,7 @@ static void close_cached_dir(struct cached_dir *cdir)
|
|||||||
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
||||||
const char *base, int baselen,
|
const char *base, int baselen,
|
||||||
struct untracked_cache_dir *untracked, int check_only,
|
struct untracked_cache_dir *untracked, int check_only,
|
||||||
const struct path_simplify *simplify)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
struct cached_dir cdir;
|
struct cached_dir cdir;
|
||||||
enum path_treatment state, subdir_state, dir_state = path_none;
|
enum path_treatment state, subdir_state, dir_state = path_none;
|
||||||
@ -1719,7 +1741,8 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
|||||||
|
|
||||||
while (!read_cached_dir(&cdir)) {
|
while (!read_cached_dir(&cdir)) {
|
||||||
/* check how the file or directory should be treated */
|
/* check how the file or directory should be treated */
|
||||||
state = treat_path(dir, untracked, &cdir, &path, baselen, simplify);
|
state = treat_path(dir, untracked, &cdir, &path,
|
||||||
|
baselen, pathspec);
|
||||||
|
|
||||||
if (state > dir_state)
|
if (state > dir_state)
|
||||||
dir_state = state;
|
dir_state = state;
|
||||||
@ -1731,8 +1754,9 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
|||||||
path.buf + baselen,
|
path.buf + baselen,
|
||||||
path.len - baselen);
|
path.len - baselen);
|
||||||
subdir_state =
|
subdir_state =
|
||||||
read_directory_recursive(dir, path.buf, path.len,
|
read_directory_recursive(dir, path.buf,
|
||||||
ud, check_only, simplify);
|
path.len, ud,
|
||||||
|
check_only, pathspec);
|
||||||
if (subdir_state > dir_state)
|
if (subdir_state > dir_state)
|
||||||
dir_state = subdir_state;
|
dir_state = subdir_state;
|
||||||
}
|
}
|
||||||
@ -1756,7 +1780,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
|
|||||||
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
|
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
|
||||||
((dir->flags & DIR_COLLECT_IGNORED) &&
|
((dir->flags & DIR_COLLECT_IGNORED) &&
|
||||||
exclude_matches_pathspec(path.buf, path.len,
|
exclude_matches_pathspec(path.buf, path.len,
|
||||||
simplify)))
|
pathspec)))
|
||||||
dir_add_ignored(dir, path.buf, path.len);
|
dir_add_ignored(dir, path.buf, path.len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1787,36 +1811,9 @@ static int cmp_name(const void *p1, const void *p2)
|
|||||||
return name_compare(e1->name, e1->len, e2->name, e2->len);
|
return name_compare(e1->name, e1->len, e2->name, e2->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct path_simplify *create_simplify(const char **pathspec)
|
|
||||||
{
|
|
||||||
int nr, alloc = 0;
|
|
||||||
struct path_simplify *simplify = NULL;
|
|
||||||
|
|
||||||
if (!pathspec)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (nr = 0 ; ; nr++) {
|
|
||||||
const char *match;
|
|
||||||
ALLOC_GROW(simplify, nr + 1, alloc);
|
|
||||||
match = *pathspec++;
|
|
||||||
if (!match)
|
|
||||||
break;
|
|
||||||
simplify[nr].path = match;
|
|
||||||
simplify[nr].len = simple_length(match);
|
|
||||||
}
|
|
||||||
simplify[nr].path = NULL;
|
|
||||||
simplify[nr].len = 0;
|
|
||||||
return simplify;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_simplify(struct path_simplify *simplify)
|
|
||||||
{
|
|
||||||
free(simplify);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int treat_leading_path(struct dir_struct *dir,
|
static int treat_leading_path(struct dir_struct *dir,
|
||||||
const char *path, int len,
|
const char *path, int len,
|
||||||
const struct path_simplify *simplify)
|
const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
int baselen, rc = 0;
|
int baselen, rc = 0;
|
||||||
@ -1840,9 +1837,9 @@ static int treat_leading_path(struct dir_struct *dir,
|
|||||||
strbuf_add(&sb, path, baselen);
|
strbuf_add(&sb, path, baselen);
|
||||||
if (!is_directory(sb.buf))
|
if (!is_directory(sb.buf))
|
||||||
break;
|
break;
|
||||||
if (simplify_away(sb.buf, sb.len, simplify))
|
if (simplify_away(sb.buf, sb.len, pathspec))
|
||||||
break;
|
break;
|
||||||
if (treat_one_path(dir, NULL, &sb, baselen, simplify,
|
if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
|
||||||
DT_DIR, NULL) == path_none)
|
DT_DIR, NULL) == path_none)
|
||||||
break; /* do not recurse into it */
|
break; /* do not recurse into it */
|
||||||
if (len <= baselen) {
|
if (len <= baselen) {
|
||||||
@ -2010,33 +2007,14 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
|
int read_directory(struct dir_struct *dir, const char *path,
|
||||||
|
int len, const struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
struct path_simplify *simplify;
|
|
||||||
struct untracked_cache_dir *untracked;
|
struct untracked_cache_dir *untracked;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check out create_simplify()
|
|
||||||
*/
|
|
||||||
if (pathspec)
|
|
||||||
GUARD_PATHSPEC(pathspec,
|
|
||||||
PATHSPEC_FROMTOP |
|
|
||||||
PATHSPEC_MAXDEPTH |
|
|
||||||
PATHSPEC_LITERAL |
|
|
||||||
PATHSPEC_GLOB |
|
|
||||||
PATHSPEC_ICASE |
|
|
||||||
PATHSPEC_EXCLUDE);
|
|
||||||
|
|
||||||
if (has_symlink_leading_path(path, len))
|
if (has_symlink_leading_path(path, len))
|
||||||
return dir->nr;
|
return dir->nr;
|
||||||
|
|
||||||
/*
|
|
||||||
* exclude patterns are treated like positive ones in
|
|
||||||
* create_simplify. Usually exclude patterns should be a
|
|
||||||
* subset of positive ones, which has no impacts on
|
|
||||||
* create_simplify().
|
|
||||||
*/
|
|
||||||
simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
|
|
||||||
untracked = validate_untracked_cache(dir, len, pathspec);
|
untracked = validate_untracked_cache(dir, len, pathspec);
|
||||||
if (!untracked)
|
if (!untracked)
|
||||||
/*
|
/*
|
||||||
@ -2044,9 +2022,8 @@ int read_directory(struct dir_struct *dir, const char *path, int len, const stru
|
|||||||
* e.g. prep_exclude()
|
* e.g. prep_exclude()
|
||||||
*/
|
*/
|
||||||
dir->untracked = NULL;
|
dir->untracked = NULL;
|
||||||
if (!len || treat_leading_path(dir, path, len, simplify))
|
if (!len || treat_leading_path(dir, path, len, pathspec))
|
||||||
read_directory_recursive(dir, path, len, untracked, 0, simplify);
|
read_directory_recursive(dir, path, len, untracked, 0, pathspec);
|
||||||
free_simplify(simplify);
|
|
||||||
QSORT(dir->entries, dir->nr, cmp_name);
|
QSORT(dir->entries, dir->nr, cmp_name);
|
||||||
QSORT(dir->ignored, dir->ignored_nr, cmp_name);
|
QSORT(dir->ignored, dir->ignored_nr, cmp_name);
|
||||||
if (dir->untracked) {
|
if (dir->untracked) {
|
||||||
|
494
pathspec.c
494
pathspec.c
@ -67,20 +67,19 @@ static struct pathspec_magic {
|
|||||||
char mnemonic; /* this cannot be ':'! */
|
char mnemonic; /* this cannot be ':'! */
|
||||||
const char *name;
|
const char *name;
|
||||||
} pathspec_magic[] = {
|
} pathspec_magic[] = {
|
||||||
{ PATHSPEC_FROMTOP, '/', "top" },
|
{ PATHSPEC_FROMTOP, '/', "top" },
|
||||||
{ PATHSPEC_LITERAL, 0, "literal" },
|
{ PATHSPEC_LITERAL, '\0', "literal" },
|
||||||
{ PATHSPEC_GLOB, '\0', "glob" },
|
{ PATHSPEC_GLOB, '\0', "glob" },
|
||||||
{ PATHSPEC_ICASE, '\0', "icase" },
|
{ PATHSPEC_ICASE, '\0', "icase" },
|
||||||
{ PATHSPEC_EXCLUDE, '!', "exclude" },
|
{ PATHSPEC_EXCLUDE, '!', "exclude" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void prefix_short_magic(struct strbuf *sb, int prefixlen,
|
static void prefix_magic(struct strbuf *sb, int prefixlen, unsigned magic)
|
||||||
unsigned short_magic)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
strbuf_addstr(sb, ":(");
|
strbuf_addstr(sb, ":(");
|
||||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
|
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
|
||||||
if (short_magic & pathspec_magic[i].bit) {
|
if (magic & pathspec_magic[i].bit) {
|
||||||
if (sb->buf[sb->len - 1] != '(')
|
if (sb->buf[sb->len - 1] != '(')
|
||||||
strbuf_addch(sb, ',');
|
strbuf_addch(sb, ',');
|
||||||
strbuf_addstr(sb, pathspec_magic[i].name);
|
strbuf_addstr(sb, pathspec_magic[i].name);
|
||||||
@ -88,54 +87,61 @@ static void prefix_short_magic(struct strbuf *sb, int prefixlen,
|
|||||||
strbuf_addf(sb, ",prefix:%d)", prefixlen);
|
strbuf_addf(sb, ",prefix:%d)", prefixlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static inline int get_literal_global(void)
|
||||||
* Take an element of a pathspec and check for magic signatures.
|
|
||||||
* Append the result to the prefix. Return the magic bitmap.
|
|
||||||
*
|
|
||||||
* For now, we only parse the syntax and throw out anything other than
|
|
||||||
* "top" magic.
|
|
||||||
*
|
|
||||||
* NEEDSWORK: This needs to be rewritten when we start migrating
|
|
||||||
* get_pathspec() users to use the "struct pathspec" interface. For
|
|
||||||
* example, a pathspec element may be marked as case-insensitive, but
|
|
||||||
* the prefix part must always match literally, and a single stupid
|
|
||||||
* string cannot express such a case.
|
|
||||||
*/
|
|
||||||
static unsigned prefix_pathspec(struct pathspec_item *item,
|
|
||||||
unsigned *p_short_magic,
|
|
||||||
const char **raw, unsigned flags,
|
|
||||||
const char *prefix, int prefixlen,
|
|
||||||
const char *elt)
|
|
||||||
{
|
{
|
||||||
static int literal_global = -1;
|
static int literal = -1;
|
||||||
static int glob_global = -1;
|
|
||||||
static int noglob_global = -1;
|
|
||||||
static int icase_global = -1;
|
|
||||||
unsigned magic = 0, short_magic = 0, global_magic = 0;
|
|
||||||
const char *copyfrom = elt, *long_magic_end = NULL;
|
|
||||||
char *match;
|
|
||||||
int i, pathspec_prefix = -1;
|
|
||||||
|
|
||||||
if (literal_global < 0)
|
if (literal < 0)
|
||||||
literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
literal = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
|
||||||
if (literal_global)
|
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_glob_global(void)
|
||||||
|
{
|
||||||
|
static int glob = -1;
|
||||||
|
|
||||||
|
if (glob < 0)
|
||||||
|
glob = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
|
||||||
|
|
||||||
|
return glob;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_noglob_global(void)
|
||||||
|
{
|
||||||
|
static int noglob = -1;
|
||||||
|
|
||||||
|
if (noglob < 0)
|
||||||
|
noglob = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
|
||||||
|
|
||||||
|
return noglob;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int get_icase_global(void)
|
||||||
|
{
|
||||||
|
static int icase = -1;
|
||||||
|
|
||||||
|
if (icase < 0)
|
||||||
|
icase = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
|
||||||
|
|
||||||
|
return icase;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_global_magic(int element_magic)
|
||||||
|
{
|
||||||
|
int global_magic = 0;
|
||||||
|
|
||||||
|
if (get_literal_global())
|
||||||
global_magic |= PATHSPEC_LITERAL;
|
global_magic |= PATHSPEC_LITERAL;
|
||||||
|
|
||||||
if (glob_global < 0)
|
/* --glob-pathspec is overridden by :(literal) */
|
||||||
glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
|
if (get_glob_global() && !(element_magic & PATHSPEC_LITERAL))
|
||||||
if (glob_global)
|
|
||||||
global_magic |= PATHSPEC_GLOB;
|
global_magic |= PATHSPEC_GLOB;
|
||||||
|
|
||||||
if (noglob_global < 0)
|
if (get_glob_global() && get_noglob_global())
|
||||||
noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);
|
|
||||||
|
|
||||||
if (glob_global && noglob_global)
|
|
||||||
die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
|
die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));
|
||||||
|
|
||||||
|
if (get_icase_global())
|
||||||
if (icase_global < 0)
|
|
||||||
icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
|
|
||||||
if (icase_global)
|
|
||||||
global_magic |= PATHSPEC_ICASE;
|
global_magic |= PATHSPEC_ICASE;
|
||||||
|
|
||||||
if ((global_magic & PATHSPEC_LITERAL) &&
|
if ((global_magic & PATHSPEC_LITERAL) &&
|
||||||
@ -143,84 +149,177 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
die(_("global 'literal' pathspec setting is incompatible "
|
die(_("global 'literal' pathspec setting is incompatible "
|
||||||
"with all other global pathspec settings"));
|
"with all other global pathspec settings"));
|
||||||
|
|
||||||
if (flags & PATHSPEC_LITERAL_PATH)
|
|
||||||
global_magic = 0;
|
|
||||||
|
|
||||||
if (elt[0] != ':' || literal_global ||
|
|
||||||
(flags & PATHSPEC_LITERAL_PATH)) {
|
|
||||||
; /* nothing to do */
|
|
||||||
} else if (elt[1] == '(') {
|
|
||||||
/* longhand */
|
|
||||||
const char *nextat;
|
|
||||||
for (copyfrom = elt + 2;
|
|
||||||
*copyfrom && *copyfrom != ')';
|
|
||||||
copyfrom = nextat) {
|
|
||||||
size_t len = strcspn(copyfrom, ",)");
|
|
||||||
if (copyfrom[len] == ',')
|
|
||||||
nextat = copyfrom + len + 1;
|
|
||||||
else
|
|
||||||
/* handle ')' and '\0' */
|
|
||||||
nextat = copyfrom + len;
|
|
||||||
if (!len)
|
|
||||||
continue;
|
|
||||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
|
||||||
if (strlen(pathspec_magic[i].name) == len &&
|
|
||||||
!strncmp(pathspec_magic[i].name, copyfrom, len)) {
|
|
||||||
magic |= pathspec_magic[i].bit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (starts_with(copyfrom, "prefix:")) {
|
|
||||||
char *endptr;
|
|
||||||
pathspec_prefix = strtol(copyfrom + 7,
|
|
||||||
&endptr, 10);
|
|
||||||
if (endptr - copyfrom != len)
|
|
||||||
die(_("invalid parameter for pathspec magic 'prefix'"));
|
|
||||||
/* "i" would be wrong, but it does not matter */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ARRAY_SIZE(pathspec_magic) <= i)
|
|
||||||
die(_("Invalid pathspec magic '%.*s' in '%s'"),
|
|
||||||
(int) len, copyfrom, elt);
|
|
||||||
}
|
|
||||||
if (*copyfrom != ')')
|
|
||||||
die(_("Missing ')' at the end of pathspec magic in '%s'"), elt);
|
|
||||||
long_magic_end = copyfrom;
|
|
||||||
copyfrom++;
|
|
||||||
} else {
|
|
||||||
/* shorthand */
|
|
||||||
for (copyfrom = elt + 1;
|
|
||||||
*copyfrom && *copyfrom != ':';
|
|
||||||
copyfrom++) {
|
|
||||||
char ch = *copyfrom;
|
|
||||||
|
|
||||||
if (!is_pathspec_magic(ch))
|
|
||||||
break;
|
|
||||||
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
|
|
||||||
if (pathspec_magic[i].mnemonic == ch) {
|
|
||||||
short_magic |= pathspec_magic[i].bit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ARRAY_SIZE(pathspec_magic) <= i)
|
|
||||||
die(_("Unimplemented pathspec magic '%c' in '%s'"),
|
|
||||||
ch, elt);
|
|
||||||
}
|
|
||||||
if (*copyfrom == ':')
|
|
||||||
copyfrom++;
|
|
||||||
}
|
|
||||||
|
|
||||||
magic |= short_magic;
|
|
||||||
*p_short_magic = short_magic;
|
|
||||||
|
|
||||||
/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
|
/* --noglob-pathspec adds :(literal) _unless_ :(glob) is specified */
|
||||||
if (noglob_global && !(magic & PATHSPEC_GLOB))
|
if (get_noglob_global() && !(element_magic & PATHSPEC_GLOB))
|
||||||
global_magic |= PATHSPEC_LITERAL;
|
global_magic |= PATHSPEC_LITERAL;
|
||||||
|
|
||||||
/* --glob-pathspec is overridden by :(literal) */
|
return global_magic;
|
||||||
if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
|
}
|
||||||
global_magic &= ~PATHSPEC_GLOB;
|
|
||||||
|
|
||||||
magic |= global_magic;
|
/*
|
||||||
|
* Parse the pathspec element looking for long magic
|
||||||
|
*
|
||||||
|
* saves all magic in 'magic'
|
||||||
|
* if prefix magic is used, save the prefix length in 'prefix_len'
|
||||||
|
* returns the position in 'elem' after all magic has been parsed
|
||||||
|
*/
|
||||||
|
static const char *parse_long_magic(unsigned *magic, int *prefix_len,
|
||||||
|
const char *elem)
|
||||||
|
{
|
||||||
|
const char *pos;
|
||||||
|
const char *nextat;
|
||||||
|
|
||||||
|
for (pos = elem + 2; *pos && *pos != ')'; pos = nextat) {
|
||||||
|
size_t len = strcspn(pos, ",)");
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pos[len] == ',')
|
||||||
|
nextat = pos + len + 1; /* handle ',' */
|
||||||
|
else
|
||||||
|
nextat = pos + len; /* handle ')' and '\0' */
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (starts_with(pos, "prefix:")) {
|
||||||
|
char *endptr;
|
||||||
|
*prefix_len = strtol(pos + 7, &endptr, 10);
|
||||||
|
if (endptr - pos != len)
|
||||||
|
die(_("invalid parameter for pathspec magic 'prefix'"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||||
|
if (strlen(pathspec_magic[i].name) == len &&
|
||||||
|
!strncmp(pathspec_magic[i].name, pos, len)) {
|
||||||
|
*magic |= pathspec_magic[i].bit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARRAY_SIZE(pathspec_magic) <= i)
|
||||||
|
die(_("Invalid pathspec magic '%.*s' in '%s'"),
|
||||||
|
(int) len, pos, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pos != ')')
|
||||||
|
die(_("Missing ')' at the end of pathspec magic in '%s'"),
|
||||||
|
elem);
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the pathspec element looking for short magic
|
||||||
|
*
|
||||||
|
* saves all magic in 'magic'
|
||||||
|
* returns the position in 'elem' after all magic has been parsed
|
||||||
|
*/
|
||||||
|
static const char *parse_short_magic(unsigned *magic, const char *elem)
|
||||||
|
{
|
||||||
|
const char *pos;
|
||||||
|
|
||||||
|
for (pos = elem + 1; *pos && *pos != ':'; pos++) {
|
||||||
|
char ch = *pos;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!is_pathspec_magic(ch))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||||
|
if (pathspec_magic[i].mnemonic == ch) {
|
||||||
|
*magic |= pathspec_magic[i].bit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARRAY_SIZE(pathspec_magic) <= i)
|
||||||
|
die(_("Unimplemented pathspec magic '%c' in '%s'"),
|
||||||
|
ch, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pos == ':')
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *parse_element_magic(unsigned *magic, int *prefix_len,
|
||||||
|
const char *elem)
|
||||||
|
{
|
||||||
|
if (elem[0] != ':' || get_literal_global())
|
||||||
|
return elem; /* nothing to do */
|
||||||
|
else if (elem[1] == '(')
|
||||||
|
/* longhand */
|
||||||
|
return parse_long_magic(magic, prefix_len, elem);
|
||||||
|
else
|
||||||
|
/* shorthand */
|
||||||
|
return parse_short_magic(magic, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strip_submodule_slash_cheap(struct pathspec_item *item)
|
||||||
|
{
|
||||||
|
if (item->len >= 1 && item->match[item->len - 1] == '/') {
|
||||||
|
int i = cache_name_pos(item->match, item->len - 1);
|
||||||
|
|
||||||
|
if (i >= 0 && S_ISGITLINK(active_cache[i]->ce_mode)) {
|
||||||
|
item->len--;
|
||||||
|
item->match[item->len] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strip_submodule_slash_expensive(struct pathspec_item *item)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < active_nr; i++) {
|
||||||
|
struct cache_entry *ce = active_cache[i];
|
||||||
|
int ce_len = ce_namelen(ce);
|
||||||
|
|
||||||
|
if (!S_ISGITLINK(ce->ce_mode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item->len <= ce_len || item->match[ce_len] != '/' ||
|
||||||
|
memcmp(ce->name, item->match, ce_len))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (item->len == ce_len + 1) {
|
||||||
|
/* strip trailing slash */
|
||||||
|
item->len--;
|
||||||
|
item->match[item->len] = '\0';
|
||||||
|
} else {
|
||||||
|
die(_("Pathspec '%s' is in submodule '%.*s'"),
|
||||||
|
item->original, ce_len, ce->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform the initialization of a pathspec_item based on a pathspec element.
|
||||||
|
*/
|
||||||
|
static void init_pathspec_item(struct pathspec_item *item, unsigned flags,
|
||||||
|
const char *prefix, int prefixlen,
|
||||||
|
const char *elt)
|
||||||
|
{
|
||||||
|
unsigned magic = 0, element_magic = 0;
|
||||||
|
const char *copyfrom = elt;
|
||||||
|
char *match;
|
||||||
|
int pathspec_prefix = -1;
|
||||||
|
|
||||||
|
/* PATHSPEC_LITERAL_PATH ignores magic */
|
||||||
|
if (flags & PATHSPEC_LITERAL_PATH) {
|
||||||
|
magic = PATHSPEC_LITERAL;
|
||||||
|
} else {
|
||||||
|
copyfrom = parse_element_magic(&element_magic,
|
||||||
|
&pathspec_prefix,
|
||||||
|
elt);
|
||||||
|
magic |= element_magic;
|
||||||
|
magic |= get_global_magic(element_magic);
|
||||||
|
}
|
||||||
|
|
||||||
|
item->magic = magic;
|
||||||
|
|
||||||
if (pathspec_prefix >= 0 &&
|
if (pathspec_prefix >= 0 &&
|
||||||
(prefixlen || (prefix && *prefix)))
|
(prefixlen || (prefix && *prefix)))
|
||||||
@ -229,6 +328,7 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
|
if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
|
||||||
die(_("%s: 'literal' and 'glob' are incompatible"), elt);
|
die(_("%s: 'literal' and 'glob' are incompatible"), elt);
|
||||||
|
|
||||||
|
/* Create match string which will be used for pathspec matching */
|
||||||
if (pathspec_prefix >= 0) {
|
if (pathspec_prefix >= 0) {
|
||||||
match = xstrdup(copyfrom);
|
match = xstrdup(copyfrom);
|
||||||
prefixlen = pathspec_prefix;
|
prefixlen = pathspec_prefix;
|
||||||
@ -236,69 +336,47 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
match = xstrdup(copyfrom);
|
match = xstrdup(copyfrom);
|
||||||
prefixlen = 0;
|
prefixlen = 0;
|
||||||
} else {
|
} else {
|
||||||
match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
|
match = prefix_path_gently(prefix, prefixlen,
|
||||||
|
&prefixlen, copyfrom);
|
||||||
if (!match)
|
if (!match)
|
||||||
die(_("%s: '%s' is outside repository"), elt, copyfrom);
|
die(_("%s: '%s' is outside repository"), elt, copyfrom);
|
||||||
}
|
}
|
||||||
*raw = item->match = match;
|
|
||||||
|
item->match = match;
|
||||||
|
item->len = strlen(item->match);
|
||||||
|
item->prefix = prefixlen;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prefix the pathspec (keep all magic) and assign to
|
* Prefix the pathspec (keep all magic) and assign to
|
||||||
* original. Useful for passing to another command.
|
* original. Useful for passing to another command.
|
||||||
*/
|
*/
|
||||||
if (flags & PATHSPEC_PREFIX_ORIGIN) {
|
if ((flags & PATHSPEC_PREFIX_ORIGIN) &&
|
||||||
|
prefixlen && !get_literal_global()) {
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
if (prefixlen && !literal_global) {
|
|
||||||
/* Preserve the actual prefix length of each pattern */
|
/* Preserve the actual prefix length of each pattern */
|
||||||
if (short_magic)
|
prefix_magic(&sb, prefixlen, element_magic);
|
||||||
prefix_short_magic(&sb, prefixlen, short_magic);
|
|
||||||
else if (long_magic_end) {
|
|
||||||
strbuf_add(&sb, elt, long_magic_end - elt);
|
|
||||||
strbuf_addf(&sb, ",prefix:%d)", prefixlen);
|
|
||||||
} else
|
|
||||||
strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
|
|
||||||
}
|
|
||||||
strbuf_addstr(&sb, match);
|
strbuf_addstr(&sb, match);
|
||||||
item->original = strbuf_detach(&sb, NULL);
|
item->original = strbuf_detach(&sb, NULL);
|
||||||
} else
|
} else {
|
||||||
item->original = elt;
|
item->original = xstrdup(elt);
|
||||||
item->len = strlen(item->match);
|
|
||||||
item->prefix = prefixlen;
|
|
||||||
|
|
||||||
if ((flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP) &&
|
|
||||||
(item->len >= 1 && item->match[item->len - 1] == '/') &&
|
|
||||||
(i = cache_name_pos(item->match, item->len - 1)) >= 0 &&
|
|
||||||
S_ISGITLINK(active_cache[i]->ce_mode)) {
|
|
||||||
item->len--;
|
|
||||||
match[item->len] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP)
|
||||||
|
strip_submodule_slash_cheap(item);
|
||||||
|
|
||||||
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
|
if (flags & PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE)
|
||||||
for (i = 0; i < active_nr; i++) {
|
strip_submodule_slash_expensive(item);
|
||||||
struct cache_entry *ce = active_cache[i];
|
|
||||||
int ce_len = ce_namelen(ce);
|
|
||||||
|
|
||||||
if (!S_ISGITLINK(ce->ce_mode))
|
if (magic & PATHSPEC_LITERAL) {
|
||||||
continue;
|
|
||||||
|
|
||||||
if (item->len <= ce_len || match[ce_len] != '/' ||
|
|
||||||
memcmp(ce->name, match, ce_len))
|
|
||||||
continue;
|
|
||||||
if (item->len == ce_len + 1) {
|
|
||||||
/* strip trailing slash */
|
|
||||||
item->len--;
|
|
||||||
match[item->len] = '\0';
|
|
||||||
} else
|
|
||||||
die (_("Pathspec '%s' is in submodule '%.*s'"),
|
|
||||||
elt, ce_len, ce->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (magic & PATHSPEC_LITERAL)
|
|
||||||
item->nowildcard_len = item->len;
|
item->nowildcard_len = item->len;
|
||||||
else {
|
} else {
|
||||||
item->nowildcard_len = simple_length(item->match);
|
item->nowildcard_len = simple_length(item->match);
|
||||||
if (item->nowildcard_len < prefixlen)
|
if (item->nowildcard_len < prefixlen)
|
||||||
item->nowildcard_len = prefixlen;
|
item->nowildcard_len = prefixlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
item->flags = 0;
|
item->flags = 0;
|
||||||
if (magic & PATHSPEC_GLOB) {
|
if (magic & PATHSPEC_GLOB) {
|
||||||
/*
|
/*
|
||||||
@ -315,7 +393,6 @@ static unsigned prefix_pathspec(struct pathspec_item *item,
|
|||||||
/* sanity checks, pathspec matchers assume these are sane */
|
/* sanity checks, pathspec matchers assume these are sane */
|
||||||
assert(item->nowildcard_len <= item->len &&
|
assert(item->nowildcard_len <= item->len &&
|
||||||
item->prefix <= item->len);
|
item->prefix <= item->len);
|
||||||
return magic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pathspec_item_cmp(const void *a_, const void *b_)
|
static int pathspec_item_cmp(const void *a_, const void *b_)
|
||||||
@ -328,22 +405,22 @@ static int pathspec_item_cmp(const void *a_, const void *b_)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void NORETURN unsupported_magic(const char *pattern,
|
static void NORETURN unsupported_magic(const char *pattern,
|
||||||
unsigned magic,
|
unsigned magic)
|
||||||
unsigned short_magic)
|
|
||||||
{
|
{
|
||||||
struct strbuf sb = STRBUF_INIT;
|
struct strbuf sb = STRBUF_INIT;
|
||||||
int i, n;
|
int i;
|
||||||
for (n = i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) {
|
||||||
const struct pathspec_magic *m = pathspec_magic + i;
|
const struct pathspec_magic *m = pathspec_magic + i;
|
||||||
if (!(magic & m->bit))
|
if (!(magic & m->bit))
|
||||||
continue;
|
continue;
|
||||||
if (sb.len)
|
if (sb.len)
|
||||||
strbuf_addch(&sb, ' ');
|
strbuf_addstr(&sb, ", ");
|
||||||
if (short_magic & m->bit)
|
|
||||||
strbuf_addf(&sb, "'%c'", m->mnemonic);
|
if (m->mnemonic)
|
||||||
|
strbuf_addf(&sb, _("'%s' (mnemonic: '%c')"),
|
||||||
|
m->name, m->mnemonic);
|
||||||
else
|
else
|
||||||
strbuf_addf(&sb, "'%s'", m->name);
|
strbuf_addf(&sb, "'%s'", m->name);
|
||||||
n++;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* We may want to substitute "this command" with a command
|
* We may want to substitute "this command" with a command
|
||||||
@ -381,8 +458,6 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
|
|
||||||
/* No arguments with prefix -> prefix pathspec */
|
/* No arguments with prefix -> prefix pathspec */
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
static const char *raw[2];
|
|
||||||
|
|
||||||
if (flags & PATHSPEC_PREFER_FULL)
|
if (flags & PATHSPEC_PREFER_FULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -390,14 +465,11 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
die("BUG: PATHSPEC_PREFER_CWD requires arguments");
|
die("BUG: PATHSPEC_PREFER_CWD requires arguments");
|
||||||
|
|
||||||
pathspec->items = item = xcalloc(1, sizeof(*item));
|
pathspec->items = item = xcalloc(1, sizeof(*item));
|
||||||
item->match = prefix;
|
item->match = xstrdup(prefix);
|
||||||
item->original = prefix;
|
item->original = xstrdup(prefix);
|
||||||
item->nowildcard_len = item->len = strlen(prefix);
|
item->nowildcard_len = item->len = strlen(prefix);
|
||||||
item->prefix = item->len;
|
item->prefix = item->len;
|
||||||
raw[0] = prefix;
|
|
||||||
raw[1] = NULL;
|
|
||||||
pathspec->nr = 1;
|
pathspec->nr = 1;
|
||||||
pathspec->_raw = raw;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,25 +487,17 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
pathspec->nr = n;
|
pathspec->nr = n;
|
||||||
ALLOC_ARRAY(pathspec->items, n);
|
ALLOC_ARRAY(pathspec->items, n);
|
||||||
item = pathspec->items;
|
item = pathspec->items;
|
||||||
pathspec->_raw = argv;
|
|
||||||
prefixlen = prefix ? strlen(prefix) : 0;
|
prefixlen = prefix ? strlen(prefix) : 0;
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
unsigned short_magic;
|
|
||||||
entry = argv[i];
|
entry = argv[i];
|
||||||
|
|
||||||
item[i].magic = prefix_pathspec(item + i, &short_magic,
|
init_pathspec_item(item + i, flags, prefix, prefixlen, entry);
|
||||||
argv + i, flags,
|
|
||||||
prefix, prefixlen, entry);
|
|
||||||
if ((flags & PATHSPEC_LITERAL_PATH) &&
|
|
||||||
!(magic_mask & PATHSPEC_LITERAL))
|
|
||||||
item[i].magic |= PATHSPEC_LITERAL;
|
|
||||||
if (item[i].magic & PATHSPEC_EXCLUDE)
|
if (item[i].magic & PATHSPEC_EXCLUDE)
|
||||||
nr_exclude++;
|
nr_exclude++;
|
||||||
if (item[i].magic & magic_mask)
|
if (item[i].magic & magic_mask)
|
||||||
unsupported_magic(entry,
|
unsupported_magic(entry, item[i].magic & magic_mask);
|
||||||
item[i].magic & magic_mask,
|
|
||||||
short_magic);
|
|
||||||
|
|
||||||
if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
|
if ((flags & PATHSPEC_SYMLINK_LEADING_PATH) &&
|
||||||
has_symlink_leading_path(item[i].match, item[i].len)) {
|
has_symlink_leading_path(item[i].match, item[i].len)) {
|
||||||
@ -457,45 +521,29 @@ void parse_pathspec(struct pathspec *pathspec,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
|
|
||||||
* based interface - see pathspec.c:parse_pathspec().
|
|
||||||
*
|
|
||||||
* Arguments:
|
|
||||||
* - prefix - a path relative to the root of the working tree
|
|
||||||
* - pathspec - a list of paths underneath the prefix path
|
|
||||||
*
|
|
||||||
* Iterates over pathspec, prepending each path with prefix,
|
|
||||||
* and return the resulting list.
|
|
||||||
*
|
|
||||||
* If pathspec is empty, return a singleton list containing prefix.
|
|
||||||
*
|
|
||||||
* If pathspec and prefix are both empty, return an empty list.
|
|
||||||
*
|
|
||||||
* This is typically used by built-in commands such as add.c, in order
|
|
||||||
* to normalize argv arguments provided to the built-in into a list of
|
|
||||||
* paths to process, all relative to the root of the working tree.
|
|
||||||
*/
|
|
||||||
const char **get_pathspec(const char *prefix, const char **pathspec)
|
|
||||||
{
|
|
||||||
struct pathspec ps;
|
|
||||||
parse_pathspec(&ps,
|
|
||||||
PATHSPEC_ALL_MAGIC &
|
|
||||||
~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
|
|
||||||
PATHSPEC_PREFER_CWD,
|
|
||||||
prefix, pathspec);
|
|
||||||
return ps._raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
|
void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
ALLOC_ARRAY(dst->items, dst->nr);
|
ALLOC_ARRAY(dst->items, dst->nr);
|
||||||
COPY_ARRAY(dst->items, src->items, dst->nr);
|
COPY_ARRAY(dst->items, src->items, dst->nr);
|
||||||
|
|
||||||
|
for (i = 0; i < dst->nr; i++) {
|
||||||
|
dst->items[i].match = xstrdup(src->items[i].match);
|
||||||
|
dst->items[i].original = xstrdup(src->items[i].original);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_pathspec(struct pathspec *pathspec)
|
void clear_pathspec(struct pathspec *pathspec)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < pathspec->nr; i++) {
|
||||||
|
free(pathspec->items[i].match);
|
||||||
|
free(pathspec->items[i].original);
|
||||||
|
}
|
||||||
free(pathspec->items);
|
free(pathspec->items);
|
||||||
pathspec->items = NULL;
|
pathspec->items = NULL;
|
||||||
|
pathspec->nr = 0;
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,14 @@
|
|||||||
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
|
#define PATHSPEC_ONESTAR 1 /* the pathspec pattern satisfies GFNM_ONESTAR */
|
||||||
|
|
||||||
struct pathspec {
|
struct pathspec {
|
||||||
const char **_raw; /* get_pathspec() result, not freed by clear_pathspec() */
|
|
||||||
int nr;
|
int nr;
|
||||||
unsigned int has_wildcard:1;
|
unsigned int has_wildcard:1;
|
||||||
unsigned int recursive:1;
|
unsigned int recursive:1;
|
||||||
unsigned magic;
|
unsigned magic;
|
||||||
int max_depth;
|
int max_depth;
|
||||||
struct pathspec_item {
|
struct pathspec_item {
|
||||||
const char *match;
|
char *match;
|
||||||
const char *original;
|
char *original;
|
||||||
unsigned magic;
|
unsigned magic;
|
||||||
int len, prefix;
|
int len, prefix;
|
||||||
int nowildcard_len;
|
int nowildcard_len;
|
||||||
|
Loading…
Reference in New Issue
Block a user