예제 #1
0
파일: clone.c 프로젝트: dindinw/git
static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
{
	const char *end = repo + strlen(repo), *start, *ptr;
	size_t len;
	char *dir;

	/*
	 * Skip scheme.
	 */
	start = strstr(repo, "://");
	if (start == NULL)
		start = repo;
	else
		start += 3;

	/*
	 * Skip authentication data. The stripping does happen
	 * greedily, such that we strip up to the last '@' inside
	 * the host part.
	 */
	for (ptr = start; ptr < end && !is_dir_sep(*ptr); ptr++) {
		if (*ptr == '@')
			start = ptr + 1;
	}

	/*
	 * Strip trailing spaces, slashes and /.git
	 */
	while (start < end && (is_dir_sep(end[-1]) || isspace(end[-1])))
		end--;
	if (end - start > 5 && is_dir_sep(end[-5]) &&
	    !strncmp(end - 4, ".git", 4)) {
		end -= 5;
		while (start < end && is_dir_sep(end[-1]))
			end--;
	}

	/*
	 * Strip trailing port number if we've got only a
	 * hostname (that is, there is no dir separator but a
	 * colon). This check is required such that we do not
	 * strip URI's like '/foo/bar:2222.git', which should
	 * result in a dir '2222' being guessed due to backwards
	 * compatibility.
	 */
	if (memchr(start, '/', end - start) == NULL
	    && memchr(start, ':', end - start) != NULL) {
		ptr = end;
		while (start < ptr && isdigit(ptr[-1]) && ptr[-1] != ':')
			ptr--;
		if (start < ptr && ptr[-1] == ':')
			end = ptr - 1;
	}

	/*
	 * Find last component. To remain backwards compatible we
	 * also regard colons as path separators, such that
	 * cloning a repository 'foo:bar.git' would result in a
	 * directory 'bar' being guessed.
	 */
	ptr = end;
	while (start < ptr && !is_dir_sep(ptr[-1]) && ptr[-1] != ':')
		ptr--;
	start = ptr;

	/*
	 * Strip .{bundle,git}.
	 */
	len = end - start;
	strip_suffix_mem(start, &len, is_bundle ? ".bundle" : ".git");

	if (!len || (len == 1 && *start == '/'))
		die(_("No directory name could be guessed.\n"
		      "Please specify a directory on the command line"));

	if (is_bare)
		dir = xstrfmt("%.*s.git", (int)len, start);
	else
		dir = xstrndup(start, len);
	/*
	 * Replace sequences of 'control' characters and whitespace
	 * with one ascii space, remove leading and trailing spaces.
	 */
	if (*dir) {
		char *out = dir;
		int prev_space = 1 /* strip leading whitespace */;
		for (end = dir; *end; ++end) {
			char ch = *end;
			if ((unsigned char)ch < '\x20')
				ch = '\x20';
			if (isspace(ch)) {
				if (prev_space)
					continue;
				prev_space = 1;
			} else
				prev_space = 0;
			*out++ = ch;
		}
		*out = '\0';
		if (out > dir && prev_space)
			out[-1] = '\0';
	}
	return dir;
}
예제 #2
0
static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn)
{
	struct stat st;
	struct passwd *pwd;
	size_t pathlen;
	struct strbuf rel = STRBUF_INIT;
	char *p, *slash;
	int n;
	size_t size;

	if (stat(path->buf, &st)) {
		fprintf(stderr, "Error accessing %s: %s (%d)\n",
			path->buf, strerror(errno), errno);
		return;
	}

	strbuf_addch(path, '/');
	pathlen = path->len;

	if (ctx.cfg.strict_export) {
		strbuf_addstr(path, ctx.cfg.strict_export);
		if(stat(path->buf, &st))
			return;
		strbuf_setlen(path, pathlen);
	}

	strbuf_addstr(path, "noweb");
	if (!stat(path->buf, &st))
		return;
	strbuf_setlen(path, pathlen);

	if (!starts_with(path->buf, base))
		strbuf_addbuf(&rel, path);
	else
		strbuf_addstr(&rel, path->buf + strlen(base) + 1);

	if (!strcmp(rel.buf + rel.len - 5, "/.git"))
		strbuf_setlen(&rel, rel.len - 5);
	else if (rel.len && rel.buf[rel.len - 1] == '/')
		strbuf_setlen(&rel, rel.len - 1);

	repo = cgit_add_repo(rel.buf);
	config_fn = fn;
	if (ctx.cfg.enable_git_config) {
		strbuf_addstr(path, "config");
		git_config_from_file(gitconfig_config, path->buf, NULL);
		strbuf_setlen(path, pathlen);
	}

	if (ctx.cfg.remove_suffix) {
		size_t urllen;
		strip_suffix(repo->url, ".git", &urllen);
		strip_suffix_mem(repo->url, &urllen, "/");
		repo->url[urllen] = '\0';
	}
	repo->path = xstrdup(path->buf);
	while (!repo->owner) {
		if ((pwd = getpwuid(st.st_uid)) == NULL) {
			fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
				path->buf, strerror(errno), errno);
			break;
		}
		if (pwd->pw_gecos)
			if ((p = strchr(pwd->pw_gecos, ',')))
				*p = '\0';
		repo->owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name);
	}

	if (repo->desc == cgit_default_repo_desc || !repo->desc) {
		strbuf_addstr(path, "description");
		if (!stat(path->buf, &st))
			readfile(path->buf, &repo->desc, &size);
		strbuf_setlen(path, pathlen);
	}

	if (ctx.cfg.section_from_path) {
		n = ctx.cfg.section_from_path;
		if (n > 0) {
			slash = rel.buf - 1;
			while (slash && n && (slash = strchr(slash + 1, '/')))
				n--;
		} else {
			slash = rel.buf + rel.len;
			while (slash && n && (slash = xstrrchr(rel.buf, slash - 1, '/')))
				n++;
		}
		if (slash && !n) {
			*slash = '\0';
			repo->section = xstrdup(rel.buf);
			*slash = '/';
			if (starts_with(repo->name, repo->section)) {
				repo->name += strlen(repo->section);
				if (*repo->name == '/')
					repo->name++;
			}
		}
	}

	strbuf_addstr(path, "cgitrc");
	if (!stat(path->buf, &st))
		parse_configfile(path->buf, &repo_config);

	strbuf_release(&rel);
}