#include "remote.h"
#include "run-command.h"
#include "transport.h"
+#include "version.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
static int no_done;
static int fetch_fsck_objects = -1;
static int transfer_fsck_objects = -1;
+static int agent_supported;
static struct fetch_pack_args args = {
/* .uploadpack = */ "git-upload-pack",
};
if (args.no_progress) strbuf_addstr(&c, " no-progress");
if (args.include_tag) strbuf_addstr(&c, " include-tag");
if (prefer_ofs_delta) strbuf_addstr(&c, " ofs-delta");
+ if (agent_supported) strbuf_addf(&c, " agent=%s",
+ git_user_agent_sanitized());
packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
strbuf_release(&c);
} else
{
struct ref *ref = copy_ref_list(orig_ref);
unsigned char sha1[20];
+ const char *agent_feature;
+ int agent_len;
sort_ref_list(&ref, ref_compare_name);
fprintf(stderr, "Server supports side-band\n");
use_sideband = 1;
}
+ if (!server_supports("thin-pack"))
+ args.use_thin_pack = 0;
+ if (!server_supports("no-progress"))
+ args.no_progress = 0;
+ if (!server_supports("include-tag"))
+ args.include_tag = 0;
if (server_supports("ofs-delta")) {
if (args.verbose)
fprintf(stderr, "Server supports ofs-delta\n");
} else
prefer_ofs_delta = 0;
+
+ if ((agent_feature = server_feature_value("agent", &agent_len))) {
+ agent_supported = 1;
+ if (args.verbose && agent_len)
+ fprintf(stderr, "Server version is %.*s\n",
+ agent_len, agent_feature);
+ }
+
if (everything_local(&ref, nr_match, match)) {
packet_flush(fd[1]);
goto all_done;
#include "string-list.h"
#include "sha1-array.h"
#include "connected.h"
+#include "version.h"
static const char receive_pack_usage[] = "git receive-pack <git-dir>";
if (sent_capabilities)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
- packet_write(1, "%s %s%c%s%s\n",
+ packet_write(1, "%s %s%c%s%s agent=%s\n",
sha1_to_hex(sha1), path, 0,
" report-status delete-refs side-band-64k quiet",
- prefer_ofs_delta ? " ofs-delta" : "");
+ prefer_ofs_delta ? " ofs-delta" : "",
+ git_user_agent_sanitized());
sent_capabilities = 1;
}
#include "send-pack.h"
#include "quote.h"
#include "transport.h"
+#include "version.h"
static const char send_pack_usage[] =
"git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
int status_report = 0;
int use_sideband = 0;
int quiet_supported = 0;
+ int agent_supported = 0;
unsigned cmds_sent = 0;
int ret;
struct async demux;
use_sideband = 1;
if (server_supports("quiet"))
quiet_supported = 1;
+ if (server_supports("agent"))
+ agent_supported = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
char *new_hex = sha1_to_hex(ref->new_sha1);
int quiet = quiet_supported && (args->quiet || !args->progress);
- if (!cmds_sent && (status_report || use_sideband || args->quiet)) {
- packet_buf_write(&req_buf, "%s %s %s%c%s%s%s",
+ if (!cmds_sent && (status_report || use_sideband ||
+ quiet || agent_supported)) {
+ packet_buf_write(&req_buf,
+ "%s %s %s%c%s%s%s%s%s",
old_hex, new_hex, ref->name, 0,
status_report ? " report-status" : "",
use_sideband ? " side-band-64k" : "",
- quiet ? " quiet" : "");
+ quiet ? " quiet" : "",
+ agent_supported ? " agent=" : "",
+ agent_supported ? git_user_agent_sanitized() : ""
+ );
}
else
packet_buf_write(&req_buf, "%s %s %s",
};
extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
-extern const char *parse_feature_request(const char *features, const char *feature);
+extern int parse_feature_request(const char *features, const char *feature);
+extern const char *server_feature_value(const char *feature, int *len_ret);
+extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret);
extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
return list;
}
-int server_supports(const char *feature)
-{
- return !!parse_feature_request(server_capabilities, feature);
-}
-
-const char *parse_feature_request(const char *feature_list, const char *feature)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
{
int len;
const char *found = strstr(feature_list, feature);
if (!found)
return NULL;
- if ((feature_list == found || isspace(found[-1])) &&
- (!found[len] || isspace(found[len]) || found[len] == '='))
- return found;
+ if (feature_list == found || isspace(found[-1])) {
+ const char *value = found + len;
+ /* feature with no value (e.g., "thin-pack") */
+ if (!*value || isspace(*value)) {
+ if (lenp)
+ *lenp = 0;
+ return value;
+ }
+ /* feature with a value (e.g., "agent=git/1.2.3") */
+ else if (*value == '=') {
+ value++;
+ if (lenp)
+ *lenp = strcspn(value, " \t\n");
+ return value;
+ }
+ /*
+ * otherwise we matched a substring of another feature;
+ * keep looking
+ */
+ }
feature_list = found + 1;
}
return NULL;
}
+int parse_feature_request(const char *feature_list, const char *feature)
+{
+ return !!parse_feature_value(feature_list, feature, NULL);
+}
+
+const char *server_feature_value(const char *feature, int *len)
+{
+ return parse_feature_value(server_capabilities, feature, len);
+}
+
+int server_supports(const char *feature)
+{
+ return !!server_feature_value(feature, NULL);
+}
+
enum protocol {
PROTO_LOCAL = 1,
PROTO_SSH,
#include "list-objects.h"
#include "run-command.h"
#include "sigchain.h"
+#include "version.h"
static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
}
if (capabilities)
- packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons,
+ packet_write(1, "%s %s%c%s%s agent=%s\n",
+ sha1_to_hex(sha1), refname_nons,
0, capabilities,
- stateless_rpc ? " no-done" : "");
+ stateless_rpc ? " no-done" : "",
+ git_user_agent_sanitized());
else
packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
capabilities = NULL;
#include "git-compat-util.h"
#include "version.h"
+#include "strbuf.h"
const char git_version_string[] = GIT_VERSION;
return agent;
}
+
+const char *git_user_agent_sanitized(void)
+{
+ static const char *agent = NULL;
+
+ if (!agent) {
+ struct strbuf buf = STRBUF_INIT;
+ int i;
+
+ strbuf_addstr(&buf, git_user_agent());
+ strbuf_trim(&buf);
+ for (i = 0; i < buf.len; i++) {
+ if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
+ buf.buf[i] = '.';
+ }
+ agent = buf.buf;
+ }
+
+ return agent;
+}
extern const char git_version_string[];
const char *git_user_agent(void);
+const char *git_user_agent_sanitized(void);
#endif /* VERSION_H */