コード例 #1
0
ファイル: dir.c プロジェクト: CCorreia/git
int init_pathspec(struct pathspec *pathspec, const char **paths)
{
	const char **p = paths;
	int i;

	memset(pathspec, 0, sizeof(*pathspec));
	if (!p)
		return 0;
	while (*p)
		p++;
	pathspec->raw = paths;
	pathspec->nr = p - paths;
	if (!pathspec->nr)
		return 0;

	pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);
	for (i = 0; i < pathspec->nr; i++) {
		struct pathspec_item *item = pathspec->items+i;
		const char *path = paths[i];

		item->match = path;
		item->len = strlen(path);
		item->use_wildcard = !no_wildcard(path);
		if (item->use_wildcard)
			pathspec->has_wildcard = 1;
	}

	qsort(pathspec->items, pathspec->nr,
	      sizeof(struct pathspec_item), pathspec_item_cmp);

	return 0;
}
コード例 #2
0
ファイル: setup.c プロジェクト: 1tgr/git
/*
 * Verify a filename that we got as an argument for a pathspec
 * entry. Note that a filename that begins with "-" never verifies
 * as true, because even if such a filename were to exist, we want
 * it to be preceded by the "--" marker (or we want the user to
 * use a format like "./-filename")
 *
 * The "diagnose_misspelt_rev" is used to provide a user-friendly
 * diagnosis when dying upon finding that "name" is not a pathname.
 * If set to 1, the diagnosis will try to diagnose "name" as an
 * invalid object name (e.g. HEAD:foo). If set to 0, the diagnosis
 * will only complain about an inexisting file.
 *
 * This function is typically called to check that a "file or rev"
 * argument is unambiguous. In this case, the caller will want
 * diagnose_misspelt_rev == 1 when verifying the first non-rev
 * argument (which could have been a revision), and
 * diagnose_misspelt_rev == 0 for the next ones (because we already
 * saw a filename, there's not ambiguity anymore).
 */
void verify_filename(const char *prefix,
		     const char *arg,
		     int diagnose_misspelt_rev)
{
	if (*arg == '-')
		die("bad flag '%s' used after filename", arg);
	if (check_filename(prefix, arg) || !no_wildcard(arg))
		return;
	die_verify_filename(prefix, arg, diagnose_misspelt_rev);
}
コード例 #3
0
ファイル: dir.c プロジェクト: CCorreia/git
void add_exclude(const char *string, const char *base,
		 int baselen, struct exclude_list *which)
{
	struct exclude *x;
	size_t len;
	int to_exclude = 1;
	int flags = 0;

	if (*string == '!') {
		to_exclude = 0;
		string++;
	}
	len = strlen(string);
	if (len && string[len - 1] == '/') {
		char *s;
		x = xmalloc(sizeof(*x) + len);
		s = (char *)(x+1);
		memcpy(s, string, len - 1);
		s[len - 1] = '\0';
		string = s;
		x->pattern = s;
		flags = EXC_FLAG_MUSTBEDIR;
	} else {
		x = xmalloc(sizeof(*x));
		x->pattern = string;
	}
	x->to_exclude = to_exclude;
	x->patternlen = strlen(string);
	x->base = base;
	x->baselen = baselen;
	x->flags = flags;
	if (!strchr(string, '/'))
		x->flags |= EXC_FLAG_NODIR;
	if (no_wildcard(string))
		x->flags |= EXC_FLAG_NOWILDCARD;
	if (*string == '*' && no_wildcard(string+1))
		x->flags |= EXC_FLAG_ENDSWITH;
	ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
	which->excludes[which->nr++] = x;
}
コード例 #4
0
ファイル: dir.c プロジェクト: 00027jang27/git
int init_pathspec(struct pathspec *pathspec, const char **paths)
{
	const char **p = paths;
	int i;

	memset(pathspec, 0, sizeof(*pathspec));
	if (!p)
		return 0;
	while (*p)
		p++;
	pathspec->raw = paths;
	pathspec->nr = p - paths;
	if (!pathspec->nr)
		return 0;

	pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);
	for (i = 0; i < pathspec->nr; i++) {
		struct pathspec_item *item = pathspec->items+i;
		const char *path = paths[i];

		item->match = path;
		item->len = strlen(path);
		item->flags = 0;
		if (limit_pathspec_to_literal()) {
			item->nowildcard_len = item->len;
		} else {
			item->nowildcard_len = simple_length(path);
			if (item->nowildcard_len < item->len) {
				pathspec->has_wildcard = 1;
				if (path[item->nowildcard_len] == '*' &&
				    no_wildcard(path + item->nowildcard_len + 1))
					item->flags |= PATHSPEC_ONESTAR;
			}
		}
	}

	qsort(pathspec->items, pathspec->nr,
	      sizeof(struct pathspec_item), pathspec_item_cmp);

	return 0;
}
コード例 #5
0
ファイル: setup.c プロジェクト: jiangxilong/git
int check_filename(const char *prefix, const char *arg)
{
	const char *name;
	struct stat st;

	if (starts_with(arg, ":/")) {
		if (arg[2] == '\0') /* ":/" is root dir, always exists */
			return 1;
		name = arg + 2;
	} else if (!no_wildcard(arg))
		return 1;
	else if (prefix)
		name = prefix_filename(prefix, strlen(prefix), arg);
	else
		name = arg;
	if (!lstat(name, &st))
		return 1; /* file exists */
	if (errno == ENOENT || errno == ENOTDIR)
		return 0; /* file does not exist */
	die_errno("failed to stat '%s'", arg);
}
コード例 #6
0
ファイル: dir.c プロジェクト: B-Rich/git
void parse_exclude_pattern(const char **pattern,
			   int *patternlen,
			   int *flags,
			   int *nowildcardlen)
{
	const char *p = *pattern;
	size_t i, len;

	*flags = 0;
	if (*p == '!') {
		*flags |= EXC_FLAG_NEGATIVE;
		p++;
	}
	len = strlen(p);
	if (len && p[len - 1] == '/') {
		len--;
		*flags |= EXC_FLAG_MUSTBEDIR;
	}
	for (i = 0; i < len; i++) {
		if (p[i] == '/')
			break;
	}
	if (i == len)
		*flags |= EXC_FLAG_NODIR;
	*nowildcardlen = simple_length(p);
	/*
	 * we should have excluded the trailing slash from 'p' too,
	 * but that's one more allocation. Instead just make sure
	 * nowildcardlen does not exceed real patternlen
	 */
	if (*nowildcardlen > len)
		*nowildcardlen = len;
	if (*p == '*' && no_wildcard(p + 1))
		*flags |= EXC_FLAG_ENDSWITH;
	*pattern = p;
	*patternlen = len;
}
コード例 #7
0
ファイル: checkout.c プロジェクト: Noffica/git
static int parse_branchname_arg(int argc, const char **argv,
				int dwim_new_local_branch_ok,
				struct branch_info *new_branch_info,
				struct checkout_opts *opts,
				struct object_id *rev,
				int *dwim_remotes_matched)
{
	struct tree **source_tree = &opts->source_tree;
	const char **new_branch = &opts->new_branch;
	int argcount = 0;
	struct object_id branch_rev;
	const char *arg;
	int dash_dash_pos;
	int has_dash_dash = 0;
	int i;

	/*
	 * case 1: git checkout <ref> -- [<paths>]
	 *
	 *   <ref> must be a valid tree, everything after the '--' must be
	 *   a path.
	 *
	 * case 2: git checkout -- [<paths>]
	 *
	 *   everything after the '--' must be paths.
	 *
	 * case 3: git checkout <something> [--]
	 *
	 *   (a) If <something> is a commit, that is to
	 *       switch to the branch or detach HEAD at it.  As a special case,
	 *       if <something> is A...B (missing A or B means HEAD but you can
	 *       omit at most one side), and if there is a unique merge base
	 *       between A and B, A...B names that merge base.
	 *
	 *   (b) If <something> is _not_ a commit, either "--" is present
	 *       or <something> is not a path, no -t or -b was given, and
	 *       and there is a tracking branch whose name is <something>
	 *       in one and only one remote (or if the branch exists on the
	 *       remote named in checkout.defaultRemote), then this is a
	 *       short-hand to fork local <something> from that
	 *       remote-tracking branch.
	 *
	 *   (c) Otherwise, if "--" is present, treat it like case (1).
	 *
	 *   (d) Otherwise :
	 *       - if it's a reference, treat it like case (1)
	 *       - else if it's a path, treat it like case (2)
	 *       - else: fail.
	 *
	 * case 4: git checkout <something> <paths>
	 *
	 *   The first argument must not be ambiguous.
	 *   - If it's *only* a reference, treat it like case (1).
	 *   - If it's only a path, treat it like case (2).
	 *   - else: fail.
	 *
	 */
	if (!argc)
		return 0;

	arg = argv[0];
	dash_dash_pos = -1;
	for (i = 0; i < argc; i++) {
		if (!strcmp(argv[i], "--")) {
			dash_dash_pos = i;
			break;
		}
	}
	if (dash_dash_pos == 0)
		return 1; /* case (2) */
	else if (dash_dash_pos == 1)
		has_dash_dash = 1; /* case (3) or (1) */
	else if (dash_dash_pos >= 2)
		die(_("only one reference expected, %d given."), dash_dash_pos);
	opts->count_checkout_paths = !opts->quiet && !has_dash_dash;

	if (!strcmp(arg, "-"))
		arg = "@{-1}";

	if (get_oid_mb(arg, rev)) {
		/*
		 * Either case (3) or (4), with <something> not being
		 * a commit, or an attempt to use case (1) with an
		 * invalid ref.
		 *
		 * It's likely an error, but we need to find out if
		 * we should auto-create the branch, case (3).(b).
		 */
		int recover_with_dwim = dwim_new_local_branch_ok;

		int could_be_checkout_paths = !has_dash_dash &&
			check_filename(opts->prefix, arg);

		if (!has_dash_dash && !no_wildcard(arg))
			recover_with_dwim = 0;

		/*
		 * Accept "git checkout foo" and "git checkout foo --"
		 * as candidates for dwim.
		 */
		if (!(argc == 1 && !has_dash_dash) &&
		    !(argc == 2 && has_dash_dash))
			recover_with_dwim = 0;

		if (recover_with_dwim) {
			const char *remote = unique_tracking_name(arg, rev,
								  dwim_remotes_matched);
			if (remote) {
				if (could_be_checkout_paths)
					die(_("'%s' could be both a local file and a tracking branch.\n"
					      "Please use -- (and optionally --no-guess) to disambiguate"),
					    arg);
				*new_branch = arg;
				arg = remote;
				/* DWIMmed to create local branch, case (3).(b) */
			} else {
				recover_with_dwim = 0;
			}
		}

		if (!recover_with_dwim) {
			if (has_dash_dash)
				die(_("invalid reference: %s"), arg);
			return argcount;
		}
	}

	/* we can't end up being in (2) anymore, eat the argument */
	argcount++;
	argv++;
	argc--;

	new_branch_info->name = arg;
	setup_branch_path(new_branch_info);

	if (!check_refname_format(new_branch_info->path, 0) &&
	    !read_ref(new_branch_info->path, &branch_rev))
		oidcpy(rev, &branch_rev);
	else
		new_branch_info->path = NULL; /* not an existing branch */

	new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
	if (!new_branch_info->commit) {
		/* not a commit */
		*source_tree = parse_tree_indirect(rev);
	} else {
		parse_commit_or_die(new_branch_info->commit);
		*source_tree = get_commit_tree(new_branch_info->commit);
	}

	if (!*source_tree)                   /* case (1): want a tree */
		die(_("reference is not a tree: %s"), arg);
	if (!has_dash_dash) {	/* case (3).(d) -> (1) */
		/*
		 * Do not complain the most common case
		 *	git checkout branch
		 * even if there happen to be a file called 'branch';
		 * it would be extremely annoying.
		 */
		if (argc)
			verify_non_filename(opts->prefix, arg);
	} else {
		argcount++;
		argv++;
		argc--;
	}

	return argcount;
}
コード例 #8
0
ファイル: pathspec.c プロジェクト: Cheche/git
/*
 * 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 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)
		literal_global = git_env_bool(GIT_LITERAL_PATHSPECS_ENVIRONMENT, 0);
	if (literal_global)
		global_magic |= PATHSPEC_LITERAL;

	if (glob_global < 0)
		glob_global = git_env_bool(GIT_GLOB_PATHSPECS_ENVIRONMENT, 0);
	if (glob_global)
		global_magic |= PATHSPEC_GLOB;

	if (noglob_global < 0)
		noglob_global = git_env_bool(GIT_NOGLOB_PATHSPECS_ENVIRONMENT, 0);

	if (glob_global && noglob_global)
		die(_("global 'glob' and 'noglob' pathspec settings are incompatible"));


	if (icase_global < 0)
		icase_global = git_env_bool(GIT_ICASE_PATHSPECS_ENVIRONMENT, 0);
	if (icase_global)
		global_magic |= PATHSPEC_ICASE;

	if ((global_magic & PATHSPEC_LITERAL) &&
	    (global_magic & ~PATHSPEC_LITERAL))
		die(_("global 'literal' pathspec setting is incompatible "
		      "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 */
	if (noglob_global && !(magic & PATHSPEC_GLOB))
		global_magic |= PATHSPEC_LITERAL;

	/* --glob-pathspec is overridden by :(literal) */
	if ((global_magic & PATHSPEC_GLOB) && (magic & PATHSPEC_LITERAL))
		global_magic &= ~PATHSPEC_GLOB;

	magic |= global_magic;

	if (pathspec_prefix >= 0 &&
	    (prefixlen || (prefix && *prefix)))
		die("BUG: 'prefix' magic is supposed to be used at worktree's root");

	if ((magic & PATHSPEC_LITERAL) && (magic & PATHSPEC_GLOB))
		die(_("%s: 'literal' and 'glob' are incompatible"), elt);

	if (pathspec_prefix >= 0) {
		match = xstrdup(copyfrom);
		prefixlen = pathspec_prefix;
	} else if (magic & PATHSPEC_FROMTOP) {
		match = xstrdup(copyfrom);
		prefixlen = 0;
	} else {
		match = prefix_path_gently(prefix, prefixlen, &prefixlen, copyfrom);
		if (!match)
			die(_("%s: '%s' is outside repository"), elt, copyfrom);
	}
	*raw = item->match = match;
	/*
	 * Prefix the pathspec (keep all magic) and assign to
	 * original. Useful for passing to another command.
	 */
	if (flags & PATHSPEC_PREFIX_ORIGIN) {
		struct strbuf sb = STRBUF_INIT;
		const char *start = elt;
		if (prefixlen && !literal_global) {
			/* Preserve the actual prefix length of each pattern */
			if (short_magic)
				die("BUG: prefixing on short magic is not supported");
			else if (long_magic_end) {
				strbuf_add(&sb, start, long_magic_end - start);
				strbuf_addf(&sb, ",prefix:%d", prefixlen);
				start = long_magic_end;
			} else {
				if (*start == ':')
					start++;
				strbuf_addf(&sb, ":(prefix:%d)", prefixlen);
			}
		}
		strbuf_add(&sb, start, copyfrom - start);
		strbuf_addstr(&sb, match);
		item->original = strbuf_detach(&sb, NULL);
	} else
		item->original = 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_EXPENSIVE)
		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 || 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;
	else {
		item->nowildcard_len = simple_length(item->match);
		if (item->nowildcard_len < prefixlen)
			item->nowildcard_len = prefixlen;
	}
	item->flags = 0;
	if (magic & PATHSPEC_GLOB) {
		/*
		 * FIXME: should we enable ONESTAR in _GLOB for
		 * pattern "* * / * . c"?
		 */
	} else {
		if (item->nowildcard_len < item->len &&
		    item->match[item->nowildcard_len] == '*' &&
		    no_wildcard(item->match + item->nowildcard_len + 1))
			item->flags |= PATHSPEC_ONESTAR;
	}

	/* sanity checks, pathspec matchers assume these are sane */
	assert(item->nowildcard_len <= item->len &&
	       item->prefix         <= item->len);
	return magic;
}