Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bundle URIs Part 1: Preparation patches #17

Closed
wants to merge 8 commits into from
141 changes: 12 additions & 129 deletions builtin/submodule--helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,135 +72,6 @@ static char *get_default_remote(void)
return repo_get_default_remote(the_repository);
}

static int starts_with_dot_slash(const char *str)
{
return str[0] == '.' && is_dir_sep(str[1]);
}

static int starts_with_dot_dot_slash(const char *str)
{
return str[0] == '.' && str[1] == '.' && is_dir_sep(str[2]);
}

/*
* Returns 1 if it was the last chop before ':'.
*/
static int chop_last_dir(char **remoteurl, int is_relative)
{
char *rfind = find_last_dir_sep(*remoteurl);
if (rfind) {
*rfind = '\0';
return 0;
}

rfind = strrchr(*remoteurl, ':');
if (rfind) {
*rfind = '\0';
return 1;
}

if (is_relative || !strcmp(".", *remoteurl))
die(_("cannot strip one component off url '%s'"),
*remoteurl);

free(*remoteurl);
*remoteurl = xstrdup(".");
return 0;
}

/*
* The `url` argument is the URL that navigates to the submodule origin
* repo. When relative, this URL is relative to the superproject origin
* URL repo. The `up_path` argument, if specified, is the relative
* path that navigates from the submodule working tree to the superproject
* working tree. Returns the origin URL of the submodule.
*
* Return either an absolute URL or filesystem path (if the superproject
* origin URL is an absolute URL or filesystem path, respectively) or a
* relative file system path (if the superproject origin URL is a relative
* file system path).
*
* When the output is a relative file system path, the path is either
* relative to the submodule working tree, if up_path is specified, or to
* the superproject working tree otherwise.
*
* NEEDSWORK: This works incorrectly on the domain and protocol part.
* remote_url url outcome expectation
* http://a.com/b ../c http://a.com/c as is
* http://a.com/b/ ../c http://a.com/c same as previous line, but
* ignore trailing slash in url
* http://a.com/b ../../c http://c error out
* http://a.com/b ../../../c http:/c error out
* http://a.com/b ../../../../c http:c error out
* http://a.com/b ../../../../../c .:c error out
* NEEDSWORK: Given how chop_last_dir() works, this function is broken
* when a local part has a colon in its path component, too.
*/
static char *relative_url(const char *remote_url,
const char *url,
const char *up_path)
{
int is_relative = 0;
int colonsep = 0;
char *out;
char *remoteurl = xstrdup(remote_url);
struct strbuf sb = STRBUF_INIT;
size_t len = strlen(remoteurl);

if (is_dir_sep(remoteurl[len-1]))
remoteurl[len-1] = '\0';

if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
is_relative = 0;
else {
is_relative = 1;
/*
* Prepend a './' to ensure all relative
* remoteurls start with './' or '../'
*/
if (!starts_with_dot_slash(remoteurl) &&
!starts_with_dot_dot_slash(remoteurl)) {
strbuf_reset(&sb);
strbuf_addf(&sb, "./%s", remoteurl);
free(remoteurl);
remoteurl = strbuf_detach(&sb, NULL);
}
}
/*
* When the url starts with '../', remove that and the
* last directory in remoteurl.
*/
while (url) {
if (starts_with_dot_dot_slash(url)) {
url += 3;
colonsep |= chop_last_dir(&remoteurl, is_relative);
} else if (starts_with_dot_slash(url))
url += 2;
else
break;
}
strbuf_reset(&sb);
strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
if (ends_with(url, "/"))
strbuf_setlen(&sb, sb.len - 1);
free(remoteurl);

if (starts_with_dot_slash(sb.buf))
out = xstrdup(sb.buf + 2);
else
out = xstrdup(sb.buf);

if (!up_path || !is_relative) {
strbuf_release(&sb);
return out;
}

strbuf_reset(&sb);
strbuf_addf(&sb, "%s%s", up_path, out);
free(out);
return strbuf_detach(&sb, NULL);
}

static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
{
char *remoteurl, *resolved_url;
Expand Down Expand Up @@ -592,6 +463,18 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
return 0;
}

static int starts_with_dot_slash(const char *const path)
{
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
PATH_MATCH_XPLATFORM);
}

static int starts_with_dot_dot_slash(const char *const path)
{
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
PATH_MATCH_XPLATFORM);
}

struct init_cb {
const char *prefix;
const char *superprefix;
Expand Down
8 changes: 4 additions & 4 deletions bundle.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ static int parse_bundle_signature(struct bundle_header *header, const char *line
return -1;
}

static int parse_bundle_header(int fd, struct bundle_header *header,
const char *report_path)
int read_bundle_header_fd(int fd, struct bundle_header *header,
const char *report_path)
{
struct strbuf buf = STRBUF_INIT;
int status = 0;
Expand Down Expand Up @@ -143,7 +143,7 @@ int read_bundle_header(const char *path, struct bundle_header *header)

if (fd < 0)
return error(_("could not open '%s'"), path);
return parse_bundle_header(fd, header, path);
return read_bundle_header_fd(fd, header, path);
}

int is_bundle(const char *path, int quiet)
Expand All @@ -153,7 +153,7 @@ int is_bundle(const char *path, int quiet)

if (fd < 0)
return 0;
fd = parse_bundle_header(fd, &header, quiet ? NULL : path);
fd = read_bundle_header_fd(fd, &header, quiet ? NULL : path);
if (fd >= 0)
close(fd);
bundle_header_release(&header);
Expand Down
2 changes: 2 additions & 0 deletions bundle.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ void bundle_header_release(struct bundle_header *header);

int is_bundle(const char *path, int quiet);
int read_bundle_header(const char *path, struct bundle_header *header);
int read_bundle_header_fd(int fd, struct bundle_header *header,
const char *report_path);
int create_bundle(struct repository *r, const char *path,
int argc, const char **argv, struct strvec *pack_options,
int version);
Expand Down
2 changes: 1 addition & 1 deletion compat/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -2830,7 +2830,7 @@ int is_valid_win32_path(const char *path, int allow_literal_nul)
}

c = path[i];
if (c && c != '.' && c != ':' && c != '/' && c != '\\')
if (c && c != '.' && c != ':' && !is_xplatform_dir_sep(c))
goto not_a_reserved_name;

/* contains reserved name */
Expand Down
6 changes: 1 addition & 5 deletions compat/win32/path-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ int win32_has_dos_drive_prefix(const char *path);

int win32_skip_dos_drive_prefix(char **path);
#define skip_dos_drive_prefix win32_skip_dos_drive_prefix
static inline int win32_is_dir_sep(int c)
{
return c == '/' || c == '\\';
}
#define is_dir_sep win32_is_dir_sep
#define is_dir_sep is_xplatform_dir_sep
static inline char *win32_find_last_dir_sep(const char *path)
{
char *ret = NULL;
Expand Down
33 changes: 20 additions & 13 deletions connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -473,14 +473,31 @@ void check_stateless_delimiter(int stateless_rpc,
die("%s", error);
}

static void send_capabilities(int fd_out, struct packet_reader *reader)
{
const char *hash_name;

if (server_supports_v2("agent", 0))
packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());

if (server_feature_v2("object-format", &hash_name)) {
int hash_algo = hash_algo_by_name(hash_name);
if (hash_algo == GIT_HASH_UNKNOWN)
die(_("unknown object format '%s' specified by server"), hash_name);
reader->hash_algo = &hash_algos[hash_algo];
packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name);
} else {
reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
}
}

struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
struct ref **list, int for_push,
struct transport_ls_refs_options *transport_options,
const struct string_list *server_options,
int stateless_rpc)
{
int i;
const char *hash_name;
struct strvec *ref_prefixes = transport_options ?
&transport_options->ref_prefixes : NULL;
const char **unborn_head_target = transport_options ?
Expand All @@ -490,18 +507,8 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
if (server_supports_v2("ls-refs", 1))
packet_write_fmt(fd_out, "command=ls-refs\n");

if (server_supports_v2("agent", 0))
packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());

if (server_feature_v2("object-format", &hash_name)) {
int hash_algo = hash_algo_by_name(hash_name);
if (hash_algo == GIT_HASH_UNKNOWN)
die(_("unknown object format '%s' specified by server"), hash_name);
reader->hash_algo = &hash_algos[hash_algo];
packet_write_fmt(fd_out, "object-format=%s", reader->hash_algo->name);
} else {
reader->hash_algo = &hash_algos[GIT_HASH_SHA1];
}
/* Send capabilities */
send_capabilities(fd_out, reader);

if (server_options && server_options->nr &&
server_supports_v2("server-option", 1))
Expand Down
29 changes: 29 additions & 0 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -3890,3 +3890,32 @@ void relocate_gitdir(const char *path, const char *old_git_dir, const char *new_

connect_work_tree_and_git_dir(path, new_git_dir, 0);
}

int path_match_flags(const char *const str, const enum path_match_flags flags)
{
const char *p = str;

if (flags & PATH_MATCH_NATIVE &&
flags & PATH_MATCH_XPLATFORM)
BUG("path_match_flags() must get one match kind, not multiple!");
else if (!(flags & PATH_MATCH_KINDS_MASK))
BUG("path_match_flags() must get at least one match kind!");

if (flags & PATH_MATCH_STARTS_WITH_DOT_SLASH &&
flags & PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH)
BUG("path_match_flags() must get one platform kind, not multiple!");
else if (!(flags & PATH_MATCH_PLATFORM_MASK))
BUG("path_match_flags() must get at least one platform kind!");

if (*p++ != '.')
return 0;
if (flags & PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH &&
*p++ != '.')
return 0;

if (flags & PATH_MATCH_NATIVE)
return is_dir_sep(*p);
else if (flags & PATH_MATCH_XPLATFORM)
return is_xplatform_dir_sep(*p);
BUG("unreachable");
}
63 changes: 63 additions & 0 deletions dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,4 +578,67 @@ void connect_work_tree_and_git_dir(const char *work_tree,
void relocate_gitdir(const char *path,
const char *old_git_dir,
const char *new_git_dir);

/**
* The "enum path_matches_kind" determines how path_match_flags() will
* behave. The flags come in sets, and one (and only one) must be
* provided out of each "set":
*
* PATH_MATCH_NATIVE:
* Path separator is is_dir_sep()
* PATH_MATCH_XPLATFORM:
* Path separator is is_xplatform_dir_sep()
*
* Do we use is_dir_sep() to check for a directory separator
* (*_NATIVE), or do we always check for '/' or '\' (*_XPLATFORM). The
* "*_NATIVE" version on Windows is the same as "*_XPLATFORM",
* everywhere else "*_NATIVE" means "only /".
*
* PATH_MATCH_STARTS_WITH_DOT_SLASH:
* Match a path starting with "./"
* PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH:
* Match a path starting with "../"
*
* The "/" in the above is adjusted based on the "*_NATIVE" and
* "*_XPLATFORM" flags.
*/
enum path_match_flags {
PATH_MATCH_NATIVE = 1 << 0,
PATH_MATCH_XPLATFORM = 1 << 1,
PATH_MATCH_STARTS_WITH_DOT_SLASH = 1 << 2,
PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH = 1 << 3,
};
#define PATH_MATCH_KINDS_MASK (PATH_MATCH_STARTS_WITH_DOT_SLASH | \
PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH)
#define PATH_MATCH_PLATFORM_MASK (PATH_MATCH_NATIVE | PATH_MATCH_XPLATFORM)

/**
* path_match_flags() checks if a given "path" matches a given "enum
* path_match_flags" criteria.
*/
int path_match_flags(const char *const path, const enum path_match_flags f);

/**
* starts_with_dot_slash_native(): convenience wrapper for
* path_match_flags() with PATH_MATCH_STARTS_WITH_DOT_SLASH and
* PATH_MATCH_NATIVE.
*/
static inline int starts_with_dot_slash_native(const char *const path)
{
const enum path_match_flags what = PATH_MATCH_STARTS_WITH_DOT_SLASH;

return path_match_flags(path, what | PATH_MATCH_NATIVE);
}

/**
* starts_with_dot_slash_native(): convenience wrapper for
* path_match_flags() with PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH and
* PATH_MATCH_NATIVE.
*/
static inline int starts_with_dot_dot_slash_native(const char *const path)
{
const enum path_match_flags what = PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH;

return path_match_flags(path, what | PATH_MATCH_NATIVE);
}
#endif
Loading