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

builtin: implement, document and test url-parse #1715

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
/git-update-server-info
/git-upload-archive
/git-upload-pack
/git-url-parse
/git-var
/git-verify-commit
/git-verify-pack
Expand Down
59 changes: 59 additions & 0 deletions Documentation/git-url-parse.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
git-url-parse(1)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the Git mailing list, Ghanshyam Thakkar wrote (reply to this):

On Sun, 28 Apr 2024, Matheus Afonso Martins Moreira via GitGitGadget <[email protected]> wrote:
> +* Print the path:
> ++
> +------------
> +$ git url-parse --component path https://example.com/user/repo
> +/usr/repo

s/usr/user/

Thanks.

================

NAME
----
git-url-parse - Parse and extract git URL components

SYNOPSIS
--------
[verse]
'git url-parse' [<options>] [--] <url>...

DESCRIPTION
-----------

Git supports many ways to specify URLs, some of them non-standard.
For example, git supports the scp style [user@]host:[path] format.
This command eases interoperability with git URLs by enabling the
parsing and extraction of the components of all git URLs.

OPTIONS
-------

-c <arg>::
--component <arg>::
Extract the `<arg>` component from the given git URLs.
`<arg>` can be one of:
`protocol`, `user`, `password`, `host`, `port`, `path`.

EXAMPLES
--------

* Print the host name:
+
------------
$ git url-parse --component host https://example.com/user/repo
example.com
------------

* Print the path:
+
------------
$ git url-parse --component path https://example.com/user/repo
/usr/repo
$ git url-parse --component path example.com:~user/repo
~user/repo
$ git url-parse --component path example.com:user/repo
/user/repo
------------

* Validate URLs without outputting anything:
+
------------
$ git url-parse https://example.com/user/repo example.com:~user/repo
------------

GIT
---
Part of the linkgit:git[1] suite
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ BUILTIN_OBJS += builtin/update-ref.o
BUILTIN_OBJS += builtin/update-server-info.o
BUILTIN_OBJS += builtin/upload-archive.o
BUILTIN_OBJS += builtin/upload-pack.o
BUILTIN_OBJS += builtin/url-parse.o
BUILTIN_OBJS += builtin/var.o
BUILTIN_OBJS += builtin/verify-commit.o
BUILTIN_OBJS += builtin/verify-pack.o
Expand Down
1 change: 1 addition & 0 deletions builtin.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix);
int cmd_upload_archive(int argc, const char **argv, const char *prefix);
int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix);
int cmd_upload_pack(int argc, const char **argv, const char *prefix);
int cmd_url_parse(int argc, const char **argv, const char *prefix);
int cmd_var(int argc, const char **argv, const char *prefix);
int cmd_verify_commit(int argc, const char **argv, const char *prefix);
int cmd_verify_tag(int argc, const char **argv, const char *prefix);
Expand Down
132 changes: 132 additions & 0 deletions builtin/url-parse.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* SPDX-License-Identifier: GPL-2.0-only
*
* url-parse - parses git URLs and extracts their components
*
* Copyright © 2024 Matheus Afonso Martins Moreira
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2.
*/

#include "builtin.h"
#include "gettext.h"
#include "parse-options.h"
#include "urlmatch.h"

static const char * const builtin_url_parse_usage[] = {
N_("git url-parse [<options>] [--] <url>..."),
NULL
};

static char *component_arg = NULL;

static struct option builtin_url_parse_options[] = {
OPT_STRING('c', "component", &component_arg, "<component>", \
N_("which URL component to extract")),
OPT_END(),
};

enum url_component {
URL_NONE = 0,
URL_PROTOCOL,
URL_USER,
URL_PASSWORD,
URL_HOST,
URL_PORT,
URL_PATH,
};

static void parse_or_die(const char *url, struct url_info *info)
{
if (url_parse(url, info)) {
return;
} else {
die("invalid git URL '%s', %s", url, info->err);
}
}

static enum url_component get_component_or_die(const char *arg)
{
if (!strcmp("path", arg))
return URL_PATH;
if (!strcmp("host", arg))
return URL_HOST;
if (!strcmp("protocol", arg))
return URL_PROTOCOL;
if (!strcmp("user", arg))
return URL_USER;
if (!strcmp("password", arg))
return URL_PASSWORD;
if (!strcmp("port", arg))
return URL_PORT;
die("invalid git URL component '%s'", arg);
}

static char *extract(enum url_component component, struct url_info *info)
{
size_t offset, length;

switch (component) {
case URL_PROTOCOL:
offset = 0;
length = info->scheme_len;
break;
case URL_USER:
offset = info->user_off;
length = info->user_len;
break;
case URL_PASSWORD:
offset = info->passwd_off;
length = info->passwd_len;
break;
case URL_HOST:
offset = info->host_off;
length = info->host_len;
break;
case URL_PORT:
offset = info->port_off;
length = info->port_len;
break;
case URL_PATH:
offset = info->path_off;
length = info->path_len;
break;
case URL_NONE:
return NULL;
}

return xstrndup(info->url + offset, length);
}

int cmd_url_parse(int argc, const char **argv, const char *prefix)
{
struct url_info info;
enum url_component selected = URL_NONE;
char *extracted;
int i;

argc = parse_options(argc, argv, prefix,
builtin_url_parse_options,
builtin_url_parse_usage,
0);

if (component_arg)
selected = get_component_or_die(component_arg);

for (i = 0; i < argc; ++i) {
parse_or_die(argv[i], &info);

if (selected != URL_NONE) {
extracted = extract(selected, &info);
if (extracted) {
puts(extracted);
free(extracted);
}
}

free(info.url);
}

return 0;
}
1 change: 1 addition & 0 deletions command-list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ git-update-ref plumbingmanipulators
git-update-server-info synchingrepositories
git-upload-archive synchelpers
git-upload-pack synchelpers
git-url-parse plumbinginterrogators
git-var plumbinginterrogators
git-verify-commit ancillaryinterrogators
git-verify-pack plumbinginterrogators
Expand Down
8 changes: 0 additions & 8 deletions connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,14 +693,6 @@ enum protocol {
PROTO_GIT
};

int url_is_local_not_ssh(const char *url)
{
const char *colon = strchr(url, ':');
const char *slash = strchr(url, '/');
return !colon || (slash && slash < colon) ||
(has_dos_drive_prefix(url) && is_valid_path(url));
}

static const char *prot_name(enum protocol protocol)
{
switch (protocol) {
Expand Down
1 change: 0 additions & 1 deletion connect.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ int git_connection_is_socket(struct child_process *conn);
int server_supports(const char *feature);
int parse_feature_request(const char *features, const char *feature);
const char *server_feature_value(const char *feature, size_t *len_ret);
int url_is_local_not_ssh(const char *url);

struct packet_reader;
enum protocol_version discover_version(struct packet_reader *reader);
Expand Down
1 change: 1 addition & 0 deletions git.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ static struct cmd_struct commands[] = {
{ "upload-archive", cmd_upload_archive, NO_PARSEOPT },
{ "upload-archive--writer", cmd_upload_archive_writer, NO_PARSEOPT },
{ "upload-pack", cmd_upload_pack },
{ "url-parse", cmd_url_parse, NO_PARSEOPT },
{ "var", cmd_var, RUN_SETUP_GENTLY | NO_PARSEOPT },
{ "verify-commit", cmd_verify_commit, RUN_SETUP },
{ "verify-pack", cmd_verify_pack },
Expand Down
1 change: 1 addition & 0 deletions remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "gettext.h"
#include "hex.h"
#include "remote.h"
#include "url.h"
#include "urlmatch.h"
#include "refs.h"
#include "refspec.h"
Expand Down