Merge branch 'ds/bundle-uri'
Preliminary code refactoring around transport and bundle code. * ds/bundle-uri: bundle.h: make "fd" version of read_bundle_header() public remote: allow relative_url() to return an absolute url remote: move relative_url() http: make http_get_file() external fetch-pack: move --keep=* option filling to a function fetch-pack: add a deref_without_lazy_fetch_extended() dir API: add a generalized path_match_flags() function connect.c: refactor sending of agent & object-format
This commit is contained in:
commit
b3b2ddced2
@ -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;
|
||||
@ -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;
|
||||
|
8
bundle.c
8
bundle.c
@ -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;
|
||||
@ -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)
|
||||
@ -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);
|
||||
|
2
bundle.h
2
bundle.h
@ -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);
|
||||
|
@ -2830,7 +2830,7 @@ not_a_reserved_name:
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -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;
|
||||
|
35
connect.c
35
connect.c
@ -473,22 +473,9 @@ void check_stateless_delimiter(int stateless_rpc,
|
||||
die("%s", error);
|
||||
}
|
||||
|
||||
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)
|
||||
static void send_capabilities(int fd_out, struct packet_reader *reader)
|
||||
{
|
||||
int i;
|
||||
const char *hash_name;
|
||||
struct strvec *ref_prefixes = transport_options ?
|
||||
&transport_options->ref_prefixes : NULL;
|
||||
const char **unborn_head_target = transport_options ?
|
||||
&transport_options->unborn_head_target : NULL;
|
||||
*list = NULL;
|
||||
|
||||
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());
|
||||
@ -502,6 +489,26 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
|
||||
} 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;
|
||||
struct strvec *ref_prefixes = transport_options ?
|
||||
&transport_options->ref_prefixes : NULL;
|
||||
const char **unborn_head_target = transport_options ?
|
||||
&transport_options->unborn_head_target : NULL;
|
||||
*list = NULL;
|
||||
|
||||
if (server_supports_v2("ls-refs", 1))
|
||||
packet_write_fmt(fd_out, "command=ls-refs\n");
|
||||
|
||||
/* Send capabilities */
|
||||
send_capabilities(fd_out, reader);
|
||||
|
||||
if (server_options && server_options->nr &&
|
||||
server_supports_v2("server-option", 1))
|
||||
|
29
dir.c
29
dir.c
@ -3955,3 +3955,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
dir.h
63
dir.h
@ -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
|
||||
|
45
fetch-pack.c
45
fetch-pack.c
@ -115,11 +115,12 @@ static void for_each_cached_alternate(struct fetch_negotiator *negotiator,
|
||||
cb(negotiator, cache.items[i]);
|
||||
}
|
||||
|
||||
static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
|
||||
int mark_tags_complete)
|
||||
static struct commit *deref_without_lazy_fetch_extended(const struct object_id *oid,
|
||||
int mark_tags_complete,
|
||||
enum object_type *type,
|
||||
unsigned int oi_flags)
|
||||
{
|
||||
enum object_type type;
|
||||
struct object_info info = { .typep = &type };
|
||||
struct object_info info = { .typep = type };
|
||||
struct commit *commit;
|
||||
|
||||
commit = lookup_commit_in_graph(the_repository, oid);
|
||||
@ -128,9 +129,9 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
|
||||
|
||||
while (1) {
|
||||
if (oid_object_info_extended(the_repository, oid, &info,
|
||||
OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK))
|
||||
oi_flags))
|
||||
return NULL;
|
||||
if (type == OBJ_TAG) {
|
||||
if (*type == OBJ_TAG) {
|
||||
struct tag *tag = (struct tag *)
|
||||
parse_object(the_repository, oid);
|
||||
|
||||
@ -144,7 +145,7 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
|
||||
}
|
||||
}
|
||||
|
||||
if (type == OBJ_COMMIT) {
|
||||
if (*type == OBJ_COMMIT) {
|
||||
struct commit *commit = lookup_commit(the_repository, oid);
|
||||
if (!commit || repo_parse_commit(the_repository, commit))
|
||||
return NULL;
|
||||
@ -154,6 +155,16 @@ static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static struct commit *deref_without_lazy_fetch(const struct object_id *oid,
|
||||
int mark_tags_complete)
|
||||
{
|
||||
enum object_type type;
|
||||
unsigned flags = OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK;
|
||||
return deref_without_lazy_fetch_extended(oid, mark_tags_complete,
|
||||
&type, flags);
|
||||
}
|
||||
|
||||
static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
|
||||
const struct object_id *oid)
|
||||
{
|
||||
@ -836,6 +847,16 @@ static void parse_gitmodules_oids(int fd, struct oidset *gitmodules_oids)
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static void add_index_pack_keep_option(struct strvec *args)
|
||||
{
|
||||
char hostname[HOST_NAME_MAX + 1];
|
||||
|
||||
if (xgethostname(hostname, sizeof(hostname)))
|
||||
xsnprintf(hostname, sizeof(hostname), "localhost");
|
||||
strvec_pushf(args, "--keep=fetch-pack %"PRIuMAX " on %s",
|
||||
(uintmax_t)getpid(), hostname);
|
||||
}
|
||||
|
||||
/*
|
||||
* If packfile URIs were provided, pass a non-NULL pointer to index_pack_args.
|
||||
* The strings to pass as the --index-pack-arg arguments to http-fetch will be
|
||||
@ -905,14 +926,8 @@ static int get_pack(struct fetch_pack_args *args,
|
||||
strvec_push(&cmd.args, "-v");
|
||||
if (args->use_thin_pack)
|
||||
strvec_push(&cmd.args, "--fix-thin");
|
||||
if ((do_keep || index_pack_args) && (args->lock_pack || unpack_limit)) {
|
||||
char hostname[HOST_NAME_MAX + 1];
|
||||
if (xgethostname(hostname, sizeof(hostname)))
|
||||
xsnprintf(hostname, sizeof(hostname), "localhost");
|
||||
strvec_pushf(&cmd.args,
|
||||
"--keep=fetch-pack %"PRIuMAX " on %s",
|
||||
(uintmax_t)getpid(), hostname);
|
||||
}
|
||||
if ((do_keep || index_pack_args) && (args->lock_pack || unpack_limit))
|
||||
add_index_pack_keep_option(&cmd.args);
|
||||
if (!index_pack_args && args->check_self_contained_and_connected)
|
||||
strvec_push(&cmd.args, "--check-self-contained-and-connected");
|
||||
else
|
||||
|
23
fsck.c
23
fsck.c
@ -975,27 +975,16 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like builtin/submodule--helper.c's starts_with_dot_slash, but without
|
||||
* relying on the platform-dependent is_dir_sep helper.
|
||||
*
|
||||
* This is for use in checking whether a submodule URL is interpreted as
|
||||
* relative to the current directory on any platform, since \ is a
|
||||
* directory separator on Windows but not on other platforms.
|
||||
*/
|
||||
static int starts_with_dot_slash(const char *str)
|
||||
static int starts_with_dot_slash(const char *const path)
|
||||
{
|
||||
return str[0] == '.' && (str[1] == '/' || str[1] == '\\');
|
||||
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
|
||||
PATH_MATCH_XPLATFORM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like starts_with_dot_slash, this is a variant of submodule--helper's
|
||||
* helper of the same name with the twist that it accepts backslash as a
|
||||
* directory separator even on non-Windows platforms.
|
||||
*/
|
||||
static int starts_with_dot_dot_slash(const char *str)
|
||||
static int starts_with_dot_dot_slash(const char *const path)
|
||||
{
|
||||
return str[0] == '.' && starts_with_dot_slash(str + 1);
|
||||
return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
|
||||
PATH_MATCH_XPLATFORM);
|
||||
}
|
||||
|
||||
static int submodule_url_is_relative(const char *url)
|
||||
|
@ -236,6 +236,12 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
/* Used by compat/win32/path-utils.h, and more */
|
||||
static inline int is_xplatform_dir_sep(int c)
|
||||
{
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#include "compat/win32/path-utils.h"
|
||||
#endif
|
||||
@ -416,11 +422,11 @@ static inline int git_skip_dos_drive_prefix(char **path)
|
||||
#define skip_dos_drive_prefix git_skip_dos_drive_prefix
|
||||
#endif
|
||||
|
||||
#ifndef is_dir_sep
|
||||
static inline int git_is_dir_sep(int c)
|
||||
{
|
||||
return c == '/';
|
||||
}
|
||||
#ifndef is_dir_sep
|
||||
#define is_dir_sep git_is_dir_sep
|
||||
#endif
|
||||
|
||||
|
4
http.c
4
http.c
@ -1989,8 +1989,8 @@ int http_get_strbuf(const char *url,
|
||||
* If a previous interrupted download is detected (i.e. a previous temporary
|
||||
* file is still around) the download is resumed.
|
||||
*/
|
||||
static int http_get_file(const char *url, const char *filename,
|
||||
struct http_get_options *options)
|
||||
int http_get_file(const char *url, const char *filename,
|
||||
struct http_get_options *options)
|
||||
{
|
||||
int ret;
|
||||
struct strbuf tmpfile = STRBUF_INIT;
|
||||
|
9
http.h
9
http.h
@ -163,6 +163,15 @@ struct http_get_options {
|
||||
*/
|
||||
int http_get_strbuf(const char *url, struct strbuf *result, struct http_get_options *options);
|
||||
|
||||
/*
|
||||
* Downloads a URL and stores the result in the given file.
|
||||
*
|
||||
* If a previous interrupted download is detected (i.e. a previous temporary
|
||||
* file is still around) the download is resumed.
|
||||
*/
|
||||
int http_get_file(const char *url, const char *filename,
|
||||
struct http_get_options *options);
|
||||
|
||||
int http_fetch_ref(const char *base, struct ref *ref);
|
||||
|
||||
/* Helpers for fetching packs */
|
||||
|
2
path.c
2
path.c
@ -1413,7 +1413,7 @@ int is_ntfs_dotgit(const char *name)
|
||||
|
||||
for (;;) {
|
||||
c = *(name++);
|
||||
if (!c || c == '\\' || c == '/' || c == ':')
|
||||
if (!c || is_xplatform_dir_sep(c) || c == ':')
|
||||
return 1;
|
||||
if (c != '.' && c != ' ')
|
||||
return 0;
|
||||
|
99
remote.c
99
remote.c
@ -14,6 +14,7 @@
|
||||
#include "strvec.h"
|
||||
#include "commit-reach.h"
|
||||
#include "advice.h"
|
||||
#include "connect.h"
|
||||
|
||||
enum map_direction { FROM_SRC, FROM_DST };
|
||||
|
||||
@ -2729,3 +2730,101 @@ void remote_state_clear(struct remote_state *remote_state)
|
||||
hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
|
||||
hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
size_t len;
|
||||
|
||||
if (!url_is_local_not_ssh(url) || is_absolute_path(url))
|
||||
return xstrdup(url);
|
||||
|
||||
len = strlen(remote_url);
|
||||
if (!len)
|
||||
BUG("invalid empty remote_url");
|
||||
|
||||
remoteurl = xstrdup(remote_url);
|
||||
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_native(remoteurl) &&
|
||||
!starts_with_dot_dot_slash_native(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_native(url)) {
|
||||
url += 3;
|
||||
colonsep |= chop_last_dir(&remoteurl, is_relative);
|
||||
} else if (starts_with_dot_slash_native(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_native(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);
|
||||
}
|
||||
|
32
remote.h
32
remote.h
@ -409,4 +409,36 @@ int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
|
||||
int is_empty_cas(const struct push_cas_option *);
|
||||
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* http://a.com/b http://d.org/e http://d.org/e as is
|
||||
* NEEDSWORK: Given how chop_last_dir() works, this function is broken
|
||||
* when a local part has a colon in its path component, too.
|
||||
*/
|
||||
char *relative_url(const char *remote_url, const char *url,
|
||||
const char *up_path);
|
||||
|
||||
#endif
|
||||
|
@ -204,17 +204,17 @@ int check_submodule_name(const char *name)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Look for '..' as a path component. Check both '/' and '\\' as
|
||||
* Look for '..' as a path component. Check is_xplatform_dir_sep() as
|
||||
* separators rather than is_dir_sep(), because we want the name rules
|
||||
* to be consistent across platforms.
|
||||
*/
|
||||
goto in_component; /* always start inside component */
|
||||
while (*name) {
|
||||
char c = *name++;
|
||||
if (c == '/' || c == '\\') {
|
||||
if (is_xplatform_dir_sep(c)) {
|
||||
in_component:
|
||||
if (name[0] == '.' && name[1] == '.' &&
|
||||
(!name[2] || name[2] == '/' || name[2] == '\\'))
|
||||
(!name[2] || is_xplatform_dir_sep(name[2])))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user