* [PATCH 10/14] imap-send.c: remove unused field imap_store::trashnc
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 9616e80..70abe9b 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -127,7 +127,6 @@ struct imap_store {
int uidvalidity;
struct imap *imap;
const char *prefix;
- unsigned /*currentnc:1,*/ trashnc:1;
};
struct imap_cmd_cb {
@@ -1079,7 +1078,6 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
} /* !preauth */
ctx->prefix = "";
- ctx->trashnc = 1;
return (struct store *)ctx;
bail:
--
1.8.0.3
^ permalink raw reply related
* [PATCH 13/14] imap-send.c: remove unused field imap_store::uidvalidity
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
I suspect that the existence of both imap_store::uidvalidity and
store::uidvalidity was an accident.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/imap-send.c b/imap-send.c
index 31fdbf3..4d24faf 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -124,7 +124,6 @@ struct imap {
struct imap_store {
struct store gen;
- int uidvalidity;
struct imap *imap;
const char *prefix;
};
--
1.8.0.3
^ permalink raw reply related
* [PATCH 14/14] imap-send.c: fold struct store into struct imap_store
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 4d24faf..1b665bb 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -33,12 +33,6 @@ typedef void *SSL;
#include <openssl/hmac.h>
#endif
-struct store {
- /* currently open mailbox */
- const char *name; /* foreign! maybe preset? */
- int uidvalidity;
-};
-
static const char imap_send_usage[] = "git imap-send < <mbox>";
#undef DRV_OK
@@ -123,7 +117,9 @@ struct imap {
};
struct imap_store {
- struct store gen;
+ /* currently open mailbox */
+ const char *name; /* foreign! maybe preset? */
+ int uidvalidity;
struct imap *imap;
const char *prefix;
};
@@ -618,7 +614,7 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
*p++ = 0;
arg = next_arg(&s);
if (!strcmp("UIDVALIDITY", arg)) {
- if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg))) {
+ if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg))) {
fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n");
return RESP_BAD;
}
@@ -636,7 +632,7 @@ static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
for (; isspace((unsigned char)*p); p++);
fprintf(stderr, "*** IMAP ALERT *** %s\n", p);
} else if (cb && cb->ctx && !strcmp("APPENDUID", arg)) {
- if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg)) ||
+ if (!(arg = next_arg(&s)) || !(ctx->uidvalidity = atoi(arg)) ||
!(arg = next_arg(&s)) || !(*(int *)cb->ctx = atoi(arg))) {
fprintf(stderr, "IMAP error: malformed APPENDUID status\n");
return RESP_BAD;
@@ -1124,7 +1120,7 @@ static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
cb.dlen = msg->len;
cb.data = strbuf_detach(msg, NULL);
- box = ctx->gen.name;
+ box = ctx->name;
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
cb.create = 0;
ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\"", prefix, box);
@@ -1336,7 +1332,7 @@ int main(int argc, char **argv)
}
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
- ctx->gen.name = imap_folder;
+ ctx->name = imap_folder;
while (1) {
unsigned percent = n * 100 / total;
--
1.8.0.3
^ permalink raw reply related
* [PATCH 01/14] imap-send.c: remove msg_data::flags, which was always zero
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
This removes the need for function imap_make_flags(), so delete it,
too.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 40 +++-------------------------------------
1 file changed, 3 insertions(+), 37 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index e521e2f..451d502 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -70,7 +70,6 @@ struct store {
struct msg_data {
struct strbuf data;
- unsigned char flags;
};
static const char imap_send_usage[] = "git imap-send < <mbox>";
@@ -225,14 +224,6 @@ static const char *cap_list[] = {
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd);
-static const char *Flags[] = {
- "Draft",
- "Flagged",
- "Answered",
- "Seen",
- "Deleted",
-};
-
#ifndef NO_OPENSSL
static void ssl_socket_perror(const char *func)
{
@@ -1246,23 +1237,6 @@ bail:
return NULL;
}
-static int imap_make_flags(int flags, char *buf)
-{
- const char *s;
- unsigned i, d;
-
- for (i = d = 0; i < ARRAY_SIZE(Flags); i++)
- if (flags & (1 << i)) {
- buf[d++] = ' ';
- buf[d++] = '\\';
- for (s = Flags[i]; *s; s++)
- buf[d++] = *s;
- }
- buf[0] = '(';
- buf[d++] = ')';
- return d;
-}
-
static void lf_to_crlf(struct strbuf *msg)
{
size_t new_len;
@@ -1311,8 +1285,7 @@ static int imap_store_msg(struct store *gctx, struct msg_data *msg)
struct imap *imap = ctx->imap;
struct imap_cmd_cb cb;
const char *prefix, *box;
- int ret, d;
- char flagstr[128];
+ int ret;
lf_to_crlf(&msg->data);
memset(&cb, 0, sizeof(cb));
@@ -1320,17 +1293,10 @@ static int imap_store_msg(struct store *gctx, struct msg_data *msg)
cb.dlen = msg->data.len;
cb.data = strbuf_detach(&msg->data, NULL);
- d = 0;
- if (msg->flags) {
- d = imap_make_flags(msg->flags, flagstr);
- flagstr[d++] = ' ';
- }
- flagstr[d] = 0;
-
box = gctx->name;
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
cb.create = 0;
- ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr);
+ ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\"", prefix, box);
imap->caps = imap->rcaps;
if (ret != DRV_OK)
return ret;
@@ -1483,7 +1449,7 @@ static int git_imap_config(const char *key, const char *val, void *cb)
int main(int argc, char **argv)
{
struct strbuf all_msgs = STRBUF_INIT;
- struct msg_data msg = {STRBUF_INIT, 0};
+ struct msg_data msg = {STRBUF_INIT};
struct store *ctx = NULL;
int ofs = 0;
int r;
--
1.8.0.3
^ permalink raw reply related
* [PATCH 03/14] iamp-send.c: remove unused struct imap_store_conf
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index a8cb66a..d675e70 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -130,11 +130,6 @@ static struct imap_server_conf server = {
NULL, /* auth_method */
};
-struct imap_store_conf {
- struct store_conf gen;
- struct imap_server_conf *server;
-};
-
#define NIL (void *)0x1
#define LIST (void *)0x2
--
1.8.0.3
^ permalink raw reply related
* [PATCH 07/14] imap-send.c: inline imap_parse_list() in imap_list()
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
The function is only called from here.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index fe2bfab..452e73e 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -669,21 +669,16 @@ bail:
return -1;
}
-static struct imap_list *parse_imap_list(struct imap *imap, char **sp)
+static struct imap_list *parse_list(char **sp)
{
struct imap_list *head;
- if (!parse_imap_list_l(imap, sp, &head, 0))
+ if (!parse_imap_list_l(NULL, sp, &head, 0))
return head;
free_list(head);
return NULL;
}
-static struct imap_list *parse_list(char **sp)
-{
- return parse_imap_list(NULL, sp);
-}
-
static void parse_capability(struct imap *imap, char *cmd)
{
char *arg;
--
1.8.0.3
^ permalink raw reply related
* [PATCH 12/14] imap-send.c: use struct imap_store instead of struct store
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
In fact, all struct store instances are upcasts of struct imap_store
anyway, so stop making the distinction.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 3167dcc..31fdbf3 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -781,9 +781,9 @@ static void imap_close_server(struct imap_store *ictx)
free(imap);
}
-static void imap_close_store(struct store *ctx)
+static void imap_close_store(struct imap_store *ctx)
{
- imap_close_server((struct imap_store *)ctx);
+ imap_close_server(ctx);
free(ctx);
}
@@ -868,7 +868,7 @@ static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const cha
return 0;
}
-static struct store *imap_open_store(struct imap_server_conf *srvc)
+static struct imap_store *imap_open_store(struct imap_server_conf *srvc)
{
struct imap_store *ctx;
struct imap *imap;
@@ -1078,10 +1078,10 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
} /* !preauth */
ctx->prefix = "";
- return (struct store *)ctx;
+ return ctx;
bail:
- imap_close_store(&ctx->gen);
+ imap_close_store(ctx);
return NULL;
}
@@ -1112,9 +1112,8 @@ static void lf_to_crlf(struct strbuf *msg)
* Store msg to IMAP. Also detach and free the data from msg->data,
* leaving msg->data empty.
*/
-static int imap_store_msg(struct store *gctx, struct strbuf *msg)
+static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
{
- struct imap_store *ctx = (struct imap_store *)gctx;
struct imap *imap = ctx->imap;
struct imap_cmd_cb cb;
const char *prefix, *box;
@@ -1126,7 +1125,7 @@ static int imap_store_msg(struct store *gctx, struct strbuf *msg)
cb.dlen = msg->len;
cb.data = strbuf_detach(msg, NULL);
- box = gctx->name;
+ box = ctx->gen.name;
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
cb.create = 0;
ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\"", prefix, box);
@@ -1282,7 +1281,7 @@ int main(int argc, char **argv)
{
struct strbuf all_msgs = STRBUF_INIT;
struct strbuf msg = STRBUF_INIT;
- struct store *ctx = NULL;
+ struct imap_store *ctx = NULL;
int ofs = 0;
int r;
int total, n = 0;
@@ -1338,7 +1337,7 @@ int main(int argc, char **argv)
}
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
- ctx->name = imap_folder;
+ ctx->gen.name = imap_folder;
while (1) {
unsigned percent = n * 100 / total;
--
1.8.0.3
^ permalink raw reply related
* [PATCH 09/14] imap-send.c: remove namespace fields from struct imap
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
They are unused, and their removal means that a bunch of list-related
infrastructure can be disposed of.
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 74 +++++++------------------------------------------------------
1 file changed, 8 insertions(+), 66 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 5238c74..9616e80 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -99,15 +99,6 @@ static struct imap_server_conf server = {
NULL, /* auth_method */
};
-#define NIL (void *)0x1
-#define LIST (void *)0x2
-
-struct imap_list {
- struct imap_list *next, *child;
- char *val;
- int len;
-};
-
struct imap_socket {
int fd[2];
SSL *ssl;
@@ -124,7 +115,6 @@ struct imap_cmd;
struct imap {
int uidnext; /* from SELECT responses */
- struct imap_list *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
unsigned caps, rcaps; /* CAPABILITY results */
/* command queue */
int nexttag, num_in_progress, literal_pending;
@@ -554,34 +544,9 @@ static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
}
}
-static int is_atom(struct imap_list *list)
-{
- return list && list->val && list->val != NIL && list->val != LIST;
-}
-
-static int is_list(struct imap_list *list)
-{
- return list && list->val == LIST;
-}
-
-static void free_list(struct imap_list *list)
-{
- struct imap_list *tmp;
-
- for (; list; list = tmp) {
- tmp = list->next;
- if (is_list(list))
- free_list(list->child);
- else if (is_atom(list))
- free(list->val);
- free(list);
- }
-}
-
-static int parse_imap_list_l(char **sp, struct imap_list **curp, int level)
+static int skip_imap_list_l(char **sp, int level)
{
- struct imap_list *cur;
- char *s = *sp, *p;
+ char *s = *sp;
for (;;) {
while (isspace((unsigned char)*s))
@@ -590,36 +555,23 @@ static int parse_imap_list_l(char **sp, struct imap_list **curp, int level)
s++;
break;
}
- *curp = cur = xmalloc(sizeof(*cur));
- curp = &cur->next;
- cur->val = NULL; /* for clean bail */
if (*s == '(') {
/* sublist */
s++;
- cur->val = LIST;
- if (parse_imap_list_l(&s, &cur->child, level + 1))
+ if (skip_imap_list_l(&s, level + 1))
goto bail;
} else if (*s == '"') {
/* quoted string */
s++;
- p = s;
for (; *s != '"'; s++)
if (!*s)
goto bail;
- cur->len = s - p;
s++;
- cur->val = xmemdupz(p, cur->len);
} else {
/* atom */
- p = s;
for (; *s && !isspace((unsigned char)*s); s++)
if (level && *s == ')')
break;
- cur->len = s - p;
- if (cur->len == 3 && !memcmp("NIL", p, 3))
- cur->val = NIL;
- else
- cur->val = xmemdupz(p, cur->len);
}
if (!level)
@@ -628,22 +580,15 @@ static int parse_imap_list_l(char **sp, struct imap_list **curp, int level)
goto bail;
}
*sp = s;
- *curp = NULL;
return 0;
bail:
- *curp = NULL;
return -1;
}
-static struct imap_list *parse_list(char **sp)
+static void skip_list(char **sp)
{
- struct imap_list *head;
-
- if (!parse_imap_list_l(sp, &head, 0))
- return head;
- free_list(head);
- return NULL;
+ skip_imap_list_l(sp, 0);
}
static void parse_capability(struct imap *imap, char *cmd)
@@ -722,9 +667,9 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
}
if (!strcmp("NAMESPACE", arg)) {
- imap->ns_personal = parse_list(&cmd);
- imap->ns_other = parse_list(&cmd);
- imap->ns_shared = parse_list(&cmd);
+ skip_list(&cmd);
+ skip_list(&cmd);
+ skip_list(&cmd);
} else if (!strcmp("OK", arg) || !strcmp("BAD", arg) ||
!strcmp("NO", arg) || !strcmp("BYE", arg)) {
if ((resp = parse_response_code(ctx, NULL, cmd)) != RESP_OK)
@@ -834,9 +779,6 @@ static void imap_close_server(struct imap_store *ictx)
imap_exec(ictx, NULL, "LOGOUT");
socket_shutdown(&imap->buf.sock);
}
- free_list(imap->ns_personal);
- free_list(imap->ns_other);
- free_list(imap->ns_shared);
free(imap);
}
--
1.8.0.3
^ permalink raw reply related
* [PATCH 11/14] imap-send.c: simplify logic in lf_to_crlf()
From: Michael Haggerty @ 2013-01-14 5:32 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jeff King, git, Michael Haggerty
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
imap-send.c | 31 ++++++++-----------------------
1 file changed, 8 insertions(+), 23 deletions(-)
diff --git a/imap-send.c b/imap-send.c
index 70abe9b..3167dcc 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1089,36 +1089,21 @@ static void lf_to_crlf(struct strbuf *msg)
{
size_t new_len;
char *new;
- int i, j, lfnum = 0;
+ int i, j = 0, lfnum = 0;
+ char lastc;
- if (msg->buf[0] == '\n')
- lfnum++;
- for (i = 1; i < msg->len; i++) {
- if (msg->buf[i - 1] != '\r' && msg->buf[i] == '\n')
+ for (i = 0, lastc = '\0'; i < msg->len; i++) {
+ if (msg->buf[i] == '\n' && lastc != '\r')
lfnum++;
+ lastc = msg->buf[i];
}
new_len = msg->len + lfnum;
new = xmalloc(new_len + 1);
- if (msg->buf[0] == '\n') {
- new[0] = '\r';
- new[1] = '\n';
- i = 1;
- j = 2;
- } else {
- new[0] = msg->buf[0];
- i = 1;
- j = 1;
- }
- for ( ; i < msg->len; i++) {
- if (msg->buf[i] != '\n') {
- new[j++] = msg->buf[i];
- continue;
- }
- if (msg->buf[i - 1] != '\r')
+ for (i = 0, lastc = '\0'; i < msg->len; i++) {
+ if (msg->buf[i] == '\n' && lastc != '\r')
new[j++] = '\r';
- /* otherwise it already had CR before */
- new[j++] = '\n';
+ lastc = new[j++] = msg->buf[i];
}
strbuf_attach(msg, new, new_len, new_len + 1);
}
--
1.8.0.3
^ permalink raw reply related
* Re: [PATCH 01/14] imap-send.c: remove msg_data::flags, which was always zero
From: Jonathan Nieder @ 2013-01-14 5:57 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, Jeff King, git
In-Reply-To: <1358141566-26081-2-git-send-email-mhagger@alum.mit.edu>
Hi,
Michael Haggerty wrote:
> This removes the need for function imap_make_flags(), so delete it,
> too.
[...]
> --- a/imap-send.c
> +++ b/imap-send.c
[...]
> box = gctx->name;
> prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
> cb.create = 0;
> - ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr);
> + ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\"", prefix, box);
Before this change, the command is
"APPEND" SP mailbox SP "{" msglen "}" CRLF
. After this change, it leaves out the space before the brace. If I
understand RFC3501 correctly, the space is required. Intentional?
With the below squashed in,
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
diff --git i/imap-send.c w/imap-send.c
index 451d5027..f1c8f5a5 100644
--- i/imap-send.c
+++ w/imap-send.c
@@ -1296,7 +1296,7 @@ static int imap_store_msg(struct store *gctx, struct msg_data *msg)
box = gctx->name;
prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix;
cb.create = 0;
- ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\"", prefix, box);
+ ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" ", prefix, box);
imap->caps = imap->rcaps;
if (ret != DRV_OK)
return ret;
^ permalink raw reply related
* Re: [PATCH 00/14] Remove unused code from imap-send.c
From: Jeff King @ 2013-01-14 6:06 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, git
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
On Mon, Jan 14, 2013 at 06:32:32AM +0100, Michael Haggerty wrote:
> As discussed before [1], imap-send.c was copied from isync, including
> a lot of code that is not used within the git project. This patch
> series rips a bunch of it out.
Thanks, this looks like a good direction.
I did not notice any problems reading through the patches, but my brain
is frazzled from a day of flying. I missed the problem Jonathan noticed.
:)
Some of the things you are removing are for advanced IMAP features that
imap-send does not need. In theory, somebody might extend it to use them
in the future. But since it has not seen any active feature development
in years, and since anybody could resurrect the code by reverting your
commits, I don't think it is a big risk.
I suspect you could go even further in ripping things out (e.g., I do
not think a server will generate an untagged namespace response at all
if we do not ask for it by issuing a namespace command). But you've
certainly grabbed the low-hanging fruit that can mostly be verified by
the compiler, and I don't know if it's worth the effort to go much
further, as it would require a lot of manual verification (and
understanding of IMAP, which will rot your brain).
-Peff
^ permalink raw reply
* Announcing git-reparent
From: Mark Lodato @ 2013-01-14 6:15 UTC (permalink / raw)
To: git list
I threw together a small utility called "git-reparent", available on GitHub at:
https://github.com/MarkLodato/git-reparent
I welcome any comments or suggestions. To make discussion easier,
I've copied the README and code below.
--- 8< ---
NAME
====
git-reparent - Recommit HEAD with a new set of parents.
SYNOPSIS
========
``git reparent [OPTIONS] ((-p <parent>)... | --no-parent)``
DESCRIPTION
===========
Create a new commit object that has the same tree and commit message as HEAD
but with a different set of parents. If ``--no-reset`` is given, the full
object id of this commit is printed and the program exits; otherwise, ``git
reset`` is used to update HEAD and the current branch to this new commit.
This command can be used to manually shape the history of a repository.
Whereas ``git rebase`` moves around *diffs*, ``git reparent`` moves around
*snapshots*. See EXAMPLES for a reason why you might want to use this
command.
OPTIONS
=======
-h, --help show the help
-e, --edit edit the commit message in an editor first
-m, --message <message> use the given message instead of that of HEAD
-p, --parent <commit> new parent to use; may be given multiple times
--no-parent create a parentless commit
-q, --quiet be quiet; only report errors
--no-reset print the new object id instead of updating HEAD
INSTALLATION
============
Make executable and place somewhere in your $PATH.
EXAMPLES
========
Reparenting the tip of a branch
-------------------------------
Suppose we create some commit *B* and then accidentally pass the ``--amend``
flag when creating new commit *C*, resulting in the following history::
B
/
...---A---C (HEAD)
What we really wanted was one linear history, ``...---A--B--C``. If we
were to use ``git rebase`` or ``git cherry-pick`` to reconstruct the history,
this would try to apply the *diff* of *A..C* onto *B*, which might fail.
Instead, what we really want to do is use the exact message and tree from *C*
but with parent *B* instead of *A*. To do this, we run ::
$ git reparent -p B
where the name *B* can be found by running ``git reflog`` and looking for the
first "commit (amend)". The resulting history is now just what we wanted::
C
/
...---A---B---C' (HEAD)
Reparenting an inner commit
---------------------------
We can also update the parents of a commit other than the most recent.
Suppose that we want to perform a rebase-like operation, moving *master* onto
*origin/master*, but we want to completely ignore any changes made in the
remote branch. That is, our history currently looks like this::
B---C (master, HEAD)
/
...---A---D---E (origin/master)
and we want to make it look like this::
B---C (origin/master)
/ /
...---A---D---E---B'---C' (master, HEAD)
We can accomplish this by using ``git rebase --interactive`` along with ``git
reparent``::
$ git rebase -i A
# select the "edit" command for commit B
# git rebase will dump us out at commit B
$ git reparent -p origin/master
$ git rebase --continue
Now the history will look as desired, and the trees, commit messages, and
authors of *B'* and *C'* will be identical to those of *B* and *C*,
respectively.
SEE ALSO
========
git-filter-branch(1) combined with either git grafts or git-replace(1) can be
used to achieve the same effect
git-rebase(1) can be used to re-apply the *diffs* of the current branch to
another
AUTHOR
======
Mark Lodato <lodatom@gmail.com>
--- 8< ---
#!/bin/sh
# Copyright (c) Mark Lodato, 2013
OPTIONS_SPEC="\
git reparent [OPTIONS] ((-p <parent>)... | --no-parent)
Recommit HEAD with a new set of parents.
--
h,help show the help
e,edit edit the commit message in an editor first
m,message= use the given message instead of that of HEAD
p,parent=! new parent to use; may be given multiple times
no-parent! create a parentless commit
q,quiet be quiet; only report errors
reset* default behavior
no-reset! print the new object id instead of updating HEAD
"
SUBDIRECTORY_OK=Yes
. "$(git --exec-path)/git-sh-setup" || exit $?
require_clean_work_tree reparent "Please commit or stash them first."
# Location of the temporary message.
msg_file="$GIT_DIR/reparent-msg"
die_with_usage() {
echo "error: $1" >&2
usage
}
edit=
message=
no_parent=
no_reset=
parent_flags=
quiet=
while [ $# -gt 0 ]; do
case "$1" in
-p)
[ $# -eq 0 ] && die_with_usage "-p requires an argument"
shift
parent_flags="$parent_flags$(git rev-parse --sq-quote -p "$1")"
;;
--no-parent) no_parent=1 ;;
-e) edit=1 ;;
--no-edit) edit= ;;
-m) message="$2"; shift ;;
--no-message)message= ;;
-q) quiet=-q ;;
--no-quiet) quiet= ;;
--reset) no_reset= ;;
--no-reset) no_reset=1 ;;
--) shift; break ;;
*) die "internal error: unknown flag $1" ;;
esac
shift
done
[ $# -gt 0 ] && \
die_with_usage "no positional arguments expected"
[ -z "$no_parent" -a -z "$parent_flags" ] && \
die_with_usage "either -p or --no-parent is required"
[ -n "$no_parent" -a -n "$parent_flags" ] && \
die_with_usage "-p and --no-parent are mutually exclusive"
# Create the commit.
if [ -n "$message" ]; then
echo "$message" > "$msg_file"
else
git cat-file commit HEAD | sed "1,/^$/d" > "$msg_file"
fi
if [ -n "$edit" ]; then
# TODO: use the normal `git commit` comment stripping stuff
git_editor "$msg_file" || die "no editor configured"
[ -s "$msg_file" ] || die "aborting due to empty commit message"
fi
eval "$(get_author_ident_from_commit HEAD)"
old_head="$(git rev-parse --short HEAD)" || exit $?
new_head="$(eval "git commit-tree HEAD: $parent_flags" '< $msg_file')" || \
exit $?
rm "$msg_file"
# Print out the commit if --no-reset; otherwise update HEAD.
if [ -n "$no_reset" ]; then
echo "$new_head"
else
set_reflog_action reparent
git reset $quiet "$new_head" || exit $?
new_abbrev="$(git rev-parse --short HEAD)" || exit $?
[ -z "$quiet" ] && echo "Moved HEAD to $new_abbrev (was $old_head)"
fi
^ permalink raw reply
* Re: [PATCH 06/14] imap-send.c: remove some unused fields from struct store
From: Jonathan Nieder @ 2013-01-14 6:19 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, Jeff King, git
In-Reply-To: <1358141566-26081-7-git-send-email-mhagger@alum.mit.edu>
Michael Haggerty wrote:
> --- a/imap-send.c
> +++ b/imap-send.c
[...]
> @@ -772,13 +767,10 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
> !strcmp("NO", arg) || !strcmp("BYE", arg)) {
> if ((resp = parse_response_code(ctx, NULL, cmd)) != RESP_OK)
> return resp;
> - } else if (!strcmp("CAPABILITY", arg))
> + } else if (!strcmp("CAPABILITY", arg)) {
> parse_capability(imap, cmd);
> - else if ((arg1 = next_arg(&cmd))) {
> - if (!strcmp("EXISTS", arg1))
> - ctx->gen.count = atoi(arg);
> - else if (!strcmp("RECENT", arg1))
> - ctx->gen.recent = atoi(arg);
> + } else if ((arg1 = next_arg(&cmd))) {
> + /* unused */
Neat. Let me try to understand what was going on here:
When opening a mailbox with the SELECT command, an IMAP server
responds with tagged data indicating how many messages exist and how
many are marked Recent. But git imap-send never reads mailboxes and
in particular never uses the SELECT command, so there is no need for
us to parse or record such responses.
Out of paranoia we are keeping the parsing for now, but the parsed
response is unused, hence the comment above.
If I've understood correctly so far (a big assumption), I still am not
sure what it would mean if we hit this ((arg1 = next_arg(&cmd))) case.
Does it mean:
A. The server has gone haywire and given a tagged response where
one is not allowed, but let's tolerate it because we always have
done so? Or
B. This is a perfectly normal response to some of the commands we
send, and we have always been deliberately ignoring it because it
is not important for what imap-send does?
Curious,
Jonathan
^ permalink raw reply
* Re: cvs-fast-export release announcement
From: Jonathan Nieder @ 2013-01-14 6:28 UTC (permalink / raw)
To: Eric S. Raymond; +Cc: git, vcs-fast-import-devs, Johan Herland
In-Reply-To: <20130114001300.57D3640661@snark.thyrsus.com>
Eric S. Raymond wrote:
> cvs-fast-export. Project page, with links to documentation and the
> public repository, is at <http://www.catb.org/esr/cvs-fast-export/>.
Yay, thanks for building this.
^ permalink raw reply
* Re: [PATCH 09/14] imap-send.c: remove namespace fields from struct imap
From: Jonathan Nieder @ 2013-01-14 6:43 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, Jeff King, git
In-Reply-To: <1358141566-26081-10-git-send-email-mhagger@alum.mit.edu>
Michael Haggerty wrote:
[...]
> @@ -722,9 +667,9 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
> }
>
> if (!strcmp("NAMESPACE", arg)) {
> - imap->ns_personal = parse_list(&cmd);
> - imap->ns_other = parse_list(&cmd);
> - imap->ns_shared = parse_list(&cmd);
> + skip_list(&cmd);
> + skip_list(&cmd);
> + skip_list(&cmd);
This codepath would only be triggered if we emit a NAMESPACE command,
right? If I am understanding correctly, a comment could make this
less mystifying:
/* rfc2342 NAMESPACE response. */
skip_list(&cmd); /* Personal mailboxes */
skip_list(&cmd); /* Others' mailboxes */
skip_list(&cmd); /* Shared mailboxes */
Though that's probably academic since hopefully this if branch
will die soon. :)
The rest of the patch is clear and pleasant and also looks correct.
With the above change,
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
Thanks.
^ permalink raw reply
* Re: [PATCH 11/14] imap-send.c: simplify logic in lf_to_crlf()
From: Jonathan Nieder @ 2013-01-14 6:47 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, Jeff King, git
In-Reply-To: <1358141566-26081-12-git-send-email-mhagger@alum.mit.edu>
Michael Haggerty wrote:
> Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
> ---
> imap-send.c | 31 ++++++++-----------------------
> 1 file changed, 8 insertions(+), 23 deletions(-)
I like the code reduction, but my nighttime brain doesn't have the
patience to understand the preimage or postimage, and the above
description doesn't give any hints. Maybe a comment right above the
function definition describing its contract would help to prepare the
daunted reader (and to let the uninterested understand call sites
without reading the implementation).
Thanks,
Jonathan
^ permalink raw reply
* Re: [PATCH 12/14] imap-send.c: use struct imap_store instead of struct store
From: Jonathan Nieder @ 2013-01-14 6:52 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, Jeff King, git
In-Reply-To: <1358141566-26081-13-git-send-email-mhagger@alum.mit.edu>
Michael Haggerty wrote:
> In fact, all struct store instances are upcasts of struct imap_store
> anyway, so stop making the distinction.
Nice.
It is tempting to fold "struct store" into "struct imap_store" at the same
time, as in
struct imap_store {
struct {
struct store_conf *conf; /* foreign */
/* currently open mailbox */
const char *name; /* foreign! maybe preset? */
char *path; /* own */
struct message *msgs; /* own */
int uidvalidity;
unsigned char opts; /* maybe preset? */
/* note that the following do _not_ reflect stats from msgs, but mailbox totals */
int count; /* # of messages */
int recent; /* # of recent messages - don't trust this beyond the initial read */
} gen;
int uidvalidity;
struct imap *imap;
const char *prefix;
unsigned /*currentnc:1,*/ trashnc:1;
};
to help the reader verify that objects of type "struct store" are not
used except through the gen field of imap_store after this change.
But verifying directly worked fine, so never mind. ;-)
^ permalink raw reply
* Re: [PATCH 00/14] Remove unused code from imap-send.c
From: Jonathan Nieder @ 2013-01-14 6:57 UTC (permalink / raw)
To: Michael Haggerty; +Cc: Junio C Hamano, Jeff King, git
In-Reply-To: <1358141566-26081-1-git-send-email-mhagger@alum.mit.edu>
Michael Haggerty wrote:
> imap-send.c | 286 +++++++++---------------------------------------------------
> 1 file changed, 39 insertions(+), 247 deletions(-)
See my replies for comments on patches 1, 6, 9, 11, and 12. The rest
are
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
The series is tasteful and easy to follow and it's hard to argue with
the resulting code reduction. Thanks for a pleasant read.
^ permalink raw reply
* Re: git list files
From: Jonathan Nieder @ 2013-01-14 7:08 UTC (permalink / raw)
To: Jeff King
Cc: Стойчо Слепцов,
git, Jakub Narębski, Matthieu Moy
In-Reply-To: <20130113201027.GA4436@sigill.intra.peff.net>
Jeff King wrote:
> As far as I recall, that script works. However, I have a pure-C
> blame-tree implementation that is much faster, which may also be of
> interest. I need to clean up and put a few finishing touches on it to
> send it to the list, but it has been in production at GitHub for a few
> months. You can find it here:
>
> git://github.com/peff/git jk/blame-tree
Oh, neat. Would that make sense as an item in
<https://git.wiki.kernel.org/index.php/Interfaces,_frontends,_and_tools>?
^ permalink raw reply
* Re: Announcing git-reparent
From: Jonathan Nieder @ 2013-01-14 7:16 UTC (permalink / raw)
To: Mark Lodato; +Cc: git list
In-Reply-To: <CAHREChhnf44CprHnS=z9KO5aOkfDPSG6Xb2GU=Kvaz38eTgbUg@mail.gmail.com>
Hi Mark,
Mark Lodato wrote:
> Create a new commit object that has the same tree and commit message as HEAD
> but with a different set of parents. If ``--no-reset`` is given, the full
> object id of this commit is printed and the program exits
I've been wishing for something like this for a long time. I used to
fake it using "cat-file commit", sed, and "hash-object -w" when
stitching together poorly imported history using "git replace".
Thanks for writing it.
Ciao,
Jonathan
^ permalink raw reply
* [PATCH v2 1/6] Makefile: add description on PERL/PYTHON_PATH
From: Junio C Hamano @ 2013-01-14 7:25 UTC (permalink / raw)
To: git
In-Reply-To: <1358148351-31552-1-git-send-email-gitster@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Makefile | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Makefile b/Makefile
index 1b30d7b..1695075 100644
--- a/Makefile
+++ b/Makefile
@@ -241,11 +241,16 @@ all::
# apostrophes to be ASCII so that cut&pasting examples to the shell
# will work.
#
+# Define PERL_PATH to the path of your Perl binary (usually /usr/bin/perl).
+#
# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
# MakeMaker (e.g. using ActiveState under Cygwin).
#
# Define NO_PERL if you do not want Perl scripts or libraries at all.
#
+# Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
+# but /usr/bin/python2.7 on some platforms).
+#
# Define NO_PYTHON if you do not want Python scripts or libraries at all.
#
# Define NO_TCLTK if you do not want Tcl/Tk GUI.
--
1.8.1.421.g6236851
^ permalink raw reply related
* [PATCH v2 0/6] A smoother transition plan for cvsimport
From: Junio C Hamano @ 2013-01-14 7:25 UTC (permalink / raw)
To: git
In-Reply-To: <7v8v7wiv3a.fsf@alter.siamese.dyndns.org>
The theme is the same as the previous 3-patch series ($gmane/213415).
The first one is unrelated.
The last two are new, adding the "dual-use test" framework hinted
at the end of the previous round.
Oh, also this time the series is formatted with "format-patch -M",
to avoid overwhelming the readers with the rename.
Junio C Hamano (6):
Makefile: add description on PERL/PYTHON_PATH
cvsimport: allow setting a custom cvsps (2.x) program name
cvsimport: introduce a version-switch wrapper
cvsimport: start adding cvsps 3.x support
cvsimport: make tests reusable for cvsimport-3
cvsimport-3: add a sample test
.gitignore | 1 +
Makefile | 43 +++-
git-cvsimport.perl => git-cvsimport-2.perl | 4 +-
git-cvsimport-3.py | 344 +++++++++++++++++++++++++++++
git-cvsimport.sh | 5 +
t/lib-cvs.sh | 55 ++++-
t/t9650-cvsimport3.sh | 4 +
7 files changed, 440 insertions(+), 16 deletions(-)
rename git-cvsimport.perl => git-cvsimport-2.perl (99%)
create mode 100755 git-cvsimport-3.py
create mode 100755 git-cvsimport.sh
create mode 100755 t/t9650-cvsimport3.sh
--
1.8.1.421.g6236851
^ permalink raw reply
* [PATCH v2 2/6] cvsimport: allow setting a custom cvsps (2.x) program name
From: Junio C Hamano @ 2013-01-14 7:25 UTC (permalink / raw)
To: git
In-Reply-To: <1358148351-31552-1-git-send-email-gitster@pobox.com>
Distros may ship old cvsps under a different name, or the user may
install it outside the normal $PATH. Allow setting CVSPS2_PATH from
the build environment.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Makefile | 9 +++++++--
git-cvsimport.perl | 4 +++-
t/lib-cvs.sh | 4 +++-
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 1695075..dd2a024 100644
--- a/Makefile
+++ b/Makefile
@@ -576,9 +576,11 @@ endif
ifndef PYTHON_PATH
PYTHON_PATH = /usr/bin/python
endif
+ifndef CVSPS2_PATH
+ CVSPS2_PATH = cvsps
+endif
-export PERL_PATH
-export PYTHON_PATH
+export PERL_PATH PYTHON_PATH CVSPS2_PATH
LIB_FILE = libgit.a
XDIFF_LIB = xdiff/lib.a
@@ -1516,6 +1518,7 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
+CVSPS2_PATH_SQ = $(subst ','\'',$(CVSPS2_PATH))
DIFF_SQ = $(subst ','\'',$(DIFF))
LIBS = $(GITLIBS) $(EXTLIBS)
@@ -1729,6 +1732,7 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl GIT-VERSION-FILE
-e ' H' \
-e ' x' \
-e '}' \
+ -e 's|@@CVSPS2_PATH@@|$(CVSPS2_PATH_SQ)|g' \
-e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \
$@.perl >$@+ && \
chmod +x $@+ && \
@@ -2107,6 +2111,7 @@ GIT-LDFLAGS: FORCE
GIT-BUILD-OPTIONS: FORCE
@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
@echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@
+ @echo CVSPS2_PATH=\''$(subst ','\'',$(CVSPS2_PATH_SQ))'\' >>$@
@echo DIFF=\''$(subst ','\'',$(subst ','\'',$(DIFF)))'\' >>$@
@echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 0a31ebd..ad460a5 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -33,6 +33,8 @@
our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R);
my (%conv_author_name, %conv_author_email, %conv_author_tz);
+my $cvsps2 = "@@CVSPS2_PATH@@";
+
sub usage(;$) {
my $msg = shift;
print(STDERR "Error: $msg\n") if $msg;
@@ -751,7 +753,7 @@ sub munge_user_filename {
unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
push @opt, '--cvs-direct';
}
- exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
+ exec($cvsps2,"--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
die "Could not start cvsps: $!\n";
}
($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh
index 44263ad..bdab63c 100644
--- a/t/lib-cvs.sh
+++ b/t/lib-cvs.sh
@@ -13,7 +13,9 @@ fi
CVS="cvs -f"
export CVS
-cvsps_version=`cvsps -h 2>&1 | sed -ne 's/cvsps version //p'`
+CVSPS="$CVSPS2_PATH"
+
+cvsps_version=`$CVSPS -h 2>&1 | sed -ne 's/cvsps version //p'`
case "$cvsps_version" in
2.1 | 2.2*)
;;
--
1.8.1.421.g6236851
^ permalink raw reply related
* [PATCH v2 5/6] cvsimport: make tests reusable for cvsimport-3
From: Junio C Hamano @ 2013-01-14 7:25 UTC (permalink / raw)
To: git
In-Reply-To: <1358148351-31552-1-git-send-email-gitster@pobox.com>
This way, a dual-use test can be dot-sourced into a new test script
after defining GIT_CVSPS_VERSION=3 to test that the new cvsimport
with cvsps (3.x) works on simple test histories that old cvsimport
can grok correctly.
Also allow CVSPS2_PATH and CVSPS3_PATH to be defined as "NoThanks"
to cause the tests in t96?? series to be skipped.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
t/lib-cvs.sh | 57 +++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 47 insertions(+), 10 deletions(-)
diff --git a/t/lib-cvs.sh b/t/lib-cvs.sh
index bdab63c..3a55b8a 100644
--- a/t/lib-cvs.sh
+++ b/t/lib-cvs.sh
@@ -1,5 +1,8 @@
#!/bin/sh
+: ${TEST_CVSPS_VERSION=2}
+export TEST_CVSPS_VERSION
+
. ./test-lib.sh
unset CVS_SERVER
@@ -13,22 +16,56 @@ fi
CVS="cvs -f"
export CVS
-CVSPS="$CVSPS2_PATH"
-
-cvsps_version=`$CVSPS -h 2>&1 | sed -ne 's/cvsps version //p'`
-case "$cvsps_version" in
-2.1 | 2.2*)
+skip_all=
+case "$TEST_CVSPS_VERSION" in
+2)
+ if test "$CVSPS2_PATH" = NoThanks
+ then
+ skip_all='skipping cvsimport tests, cvsps(2) not used'
+ else
+ case $($CVSPS2_PATH -h 2>&1 | sed -ne 's/cvsps version //p') in
+ 2.1 | 2.2*)
+ ;;
+ '')
+ skip_all='skipping cvsimport tests, cvsps(2) not found'
+ ;;
+ *)
+ skip_all='skipping cvsimport tests, unsupported cvsps(2)'
+ ;;
+ esac
+ fi
;;
-'')
- skip_all='skipping cvsimport tests, cvsps not found'
- test_done
+3)
+ if test "$CVSPS3_PATH" = NoThanks
+ then
+ skip_all='skipping cvsimport tests, cvsps(3) not used'
+ else
+ case $($CVSPS3_PATH -h 2>&1 | sed -ne 's/cvsps version //p') in
+ 3.*)
+ ;;
+ '')
+ skip_all='skipping cvsimport tests, cvsps(3) not found'
+ ;;
+ *)
+ skip_all='skipping cvsimport tests, unsupported cvsps(3)'
+ ;;
+ esac
+ fi
;;
*)
- skip_all='skipping cvsimport tests, unsupported cvsps version'
- test_done
+ echo >&2 "Bug in test: set TEST_CVSPS_VESION to either 2 or 3"
+ exit 1
;;
esac
+GIT_CVSPS_VERSION=$TEST_CVSPS_VERSION
+export GIT_CVSPS_VERSION
+
+if test -n "$skip_all"
+then
+ test_done
+fi
+
setup_cvs_test_repository () {
CVSROOT="$(pwd)/.cvsroot" &&
cp -r "$TEST_DIRECTORY/$1/cvsroot" "$CVSROOT" &&
--
1.8.1.421.g6236851
^ permalink raw reply related
* [PATCH v2 4/6] cvsimport: start adding cvsps 3.x support
From: Junio C Hamano @ 2013-01-14 7:25 UTC (permalink / raw)
To: git
In-Reply-To: <1358148351-31552-1-git-send-email-gitster@pobox.com>
The new cvsps 3.x series lacks support of some options cvsps 2.x
series had and used by cvsimport-2; add a replacement program from
the author of cvsps 3.x and allow users to choose it by setting the
GIT_CVSPS_VERSION environment variable to 3. We would later add
support to auto-detect the version of installed cvsps to this code
when the environment variable is not set.
Note that in this step, cvsimport-3 that relies on cvsps 3.x does
not have any test coverage. As cvsimport-3 supports most of the
command line options cvsimport-2, we should be able to tweak some of
the t96?? tests and run them with GIT_CVSPS_VERSION set to both 2
and 3, but that is a topic of later patches that should come on top.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
Makefile | 22 +++-
git-cvsimport-3.py | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++
git-cvsimport.sh | 4 +-
3 files changed, 363 insertions(+), 7 deletions(-)
create mode 100755 git-cvsimport-3.py
diff --git a/Makefile b/Makefile
index f3113a9..00bd3a6 100644
--- a/Makefile
+++ b/Makefile
@@ -256,6 +256,9 @@ all::
# Define CVSPS2_PATH if you cannot invoke cvsps (version 2.x) as "cvsps"
# using your $PATH; if you do not have any, define CVSPS2_PATH=NoThanks.
#
+# Define CVSPS3_PATH if you cannot invoke cvsps (version 3.x) as "cvsps"
+# using your $PATH; if you do not have any, define CVSPS3_PATH=NoThanks.
+#
# Define NO_TCLTK if you do not want Tcl/Tk GUI.
#
# The TCL_PATH variable governs the location of the Tcl interpreter
@@ -480,9 +483,11 @@ SCRIPT_PERL += git-relink.perl
SCRIPT_PERL += git-send-email.perl
SCRIPT_PERL += git-svn.perl
+ifneq ($(CVSPS3_PATH),NoThanks)
+SCRIPT_PYTHON += git-cvsimport-3.py
+endif
SCRIPT_PYTHON += git-p4.py
SCRIPT_PYTHON += git-remote-testpy.py
-SCRIPT_PYTHON += git-p4.py
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
$(patsubst %.perl,%,$(SCRIPT_PERL)) \
@@ -586,8 +591,11 @@ endif
ifndef CVSPS2_PATH
CVSPS2_PATH = cvsps
endif
+ifndef CVSPS3_PATH
+ CVSPS3_PATH = cvsps
+endif
-export PERL_PATH PYTHON_PATH CVSPS2_PATH
+export PERL_PATH PYTHON_PATH CVSPS2_PATH CVSPS3_PATH
LIB_FILE = libgit.a
XDIFF_LIB = xdiff/lib.a
@@ -1526,6 +1534,7 @@ PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
CVSPS2_PATH_SQ = $(subst ','\'',$(CVSPS2_PATH))
+CVSPS3_PATH_SQ = $(subst ','\'',$(CVSPS3_PATH))
DIFF_SQ = $(subst ','\'',$(DIFF))
LIBS = $(GITLIBS) $(EXTLIBS)
@@ -1768,12 +1777,14 @@ ifndef NO_PYTHON
$(patsubst %.py,%,$(SCRIPT_PYTHON)): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
$(patsubst %.py,%,$(SCRIPT_PYTHON)): % : %.py
$(QUIET_GEN)$(RM) $@ $@+ && \
- INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
+ INSTLIBDIR_SQ=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
--no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
- instlibdir` && \
+ instlibdir | \
+ sed -e "s/'/'\''/g"` && \
sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
-e 's|\(os\.getenv("GITPYTHONLIB"\)[^)]*)|\1,"@@INSTLIBDIR@@")|' \
- -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
+ -e 's|@@CVSPS3_PATH@@|$(CVSPS3_PATH_SQ)|g' \
+ -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR_SQ"'|g' \
$@.py >$@+ && \
chmod +x $@+ && \
mv $@+ $@
@@ -2119,6 +2130,7 @@ GIT-BUILD-OPTIONS: FORCE
@echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@
@echo PERL_PATH=\''$(subst ','\'',$(PERL_PATH_SQ))'\' >>$@
@echo CVSPS2_PATH=\''$(subst ','\'',$(CVSPS2_PATH_SQ))'\' >>$@
+ @echo CVSPS3_PATH=\''$(subst ','\'',$(CVSPS3_PATH_SQ))'\' >>$@
@echo DIFF=\''$(subst ','\'',$(subst ','\'',$(DIFF)))'\' >>$@
@echo PYTHON_PATH=\''$(subst ','\'',$(PYTHON_PATH_SQ))'\' >>$@
@echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@
diff --git a/git-cvsimport-3.py b/git-cvsimport-3.py
new file mode 100755
index 0000000..57f13b7
--- /dev/null
+++ b/git-cvsimport-3.py
@@ -0,0 +1,344 @@
+#!/usr/bin/env python
+#
+# Import CVS history into git
+#
+# Intended to be a near-workalike of Matthias Urlichs's Perl implementation.
+#
+# By Eric S. Raymond <esr@thyrsus.com>, December 2012
+# May be redistributed under the license of the git project.
+
+import sys
+
+if sys.hexversion < 0x02060000:
+ sys.stderr.write("git cvsimport: requires Python 2.6 or later.\n")
+ sys.exit(1)
+
+import os, getopt, subprocess, tempfile, shutil
+
+DEBUG_COMMANDS = 1
+
+class Fatal(Exception):
+ "Unrecoverable error."
+ def __init__(self, msg):
+ Exception.__init__(self)
+ self.msg = msg
+
+def do_or_die(dcmd, legend=""):
+ "Either execute a command or raise a fatal exception."
+ if legend:
+ legend = " " + legend
+ if verbose >= DEBUG_COMMANDS:
+ sys.stdout.write("git cvsimport: executing '%s'%s\n" % (dcmd, legend))
+ try:
+ retcode = subprocess.call(dcmd, shell=True)
+ if retcode < 0:
+ raise Fatal("git cvsimport: child was terminated by signal %d." % -retcode)
+ elif retcode != 0:
+ raise Fatal("git cvsimport: child returned %d." % retcode)
+ except (OSError, IOError) as e:
+ raise Fatal("git cvsimport: execution of %s%s failed: %s" % (dcmd, legend, e))
+
+def capture_or_die(dcmd, legend=""):
+ "Either execute a command and capture its output or die."
+ if legend:
+ legend = " " + legend
+ if verbose >= DEBUG_COMMANDS:
+ sys.stdout.write("git cvsimport: executing '%s'%s\n" % (dcmd, legend))
+ try:
+ return subprocess.check_output(dcmd, shell=True)
+ except subprocess.CalledProcessError as e:
+ if e.returncode < 0:
+ sys.stderr.write("git cvsimport: child was terminated by signal %d." % -e.returncode)
+ elif e.returncode != 0:
+ sys.stderr.write("git cvsimport: child returned %d." % e.returncode)
+ sys.exit(1)
+
+class cvsps:
+ "Method class for cvsps back end."
+
+ cvsps = "@@CVSPS3_PATH@@"
+ def __init__(self):
+ self.opts = ""
+ self.revmap = None
+ def set_repo(self, val):
+ "Set the repository root option."
+ if not val.startswith(":"):
+ if not val.startswith(os.sep):
+ val = os.path.abspath(val)
+ val = ":local:" + val
+ self.opts += " --root '%s'" % val
+ def set_authormap(self, val):
+ "Set the author-map file."
+ self.opts += " -A '%s'" % val
+ def set_fuzz(self, val):
+ "Set the commit-similarity window."
+ self.opts += " -z %s" % val
+ def set_nokeywords(self):
+ "Suppress CVS keyword expansion."
+ self.opts += " -k"
+ def add_opts(self, val):
+ "Add options to the engine command line."
+ self.opts += " " + val
+ def set_exclusion(self, val):
+ "Set a file exclusion regexp."
+ self.opts += " -n -f '%s'" % val
+ def set_after(self, val):
+ "Set a date threshold for incremental import."
+ self.opts += " -d '%s'" % val
+ def set_revmap(self, val):
+ "Set the file to which the engine should dump a reference map."
+ self.revmap = val
+ self.opts += " -R '%s'" % self.revmap
+ def set_module(self, val):
+ "Set the module to query."
+ self.opts += " " + val
+ def command(self):
+ "Emit the command implied by all previous options."
+ return self.cvsps + "--fast-export " + self.opts
+
+class cvs2git:
+ "Method class for cvs2git back end."
+ def __init__(self):
+ self.opts = ""
+ self.modulepath = "."
+ def set_authormap(self, _val):
+ "Set the author-map file."
+ sys.stderr.write("git cvsimport: author maping is not supported with cvs2git.\n")
+ sys.exit(1)
+ def set_repo(self, _val):
+ "Set the repository root option."
+ sys.stderr.write("git cvsimport: cvs2git must run within a repository checkout directory.\n")
+ sys.exit(1)
+ def set_fuzz(self, _val):
+ "Set the commit-similarity window."
+ sys.stderr.write("git cvsimport: fuzz setting is not supported with cvs2git.\n")
+ sys.exit(1)
+ def set_nokeywords(self):
+ "Suppress CVS keyword expansion."
+ self.opts += " --keywords-off"
+ def add_opts(self, val):
+ "Add options to the engine command line."
+ self.opts += " " + val
+ def set_exclusion(self, val):
+ "Set a file exclusion regexp."
+ self.opts += " --exclude='%s'" % val
+ def set_after(self, _val):
+ "Set a date threshold for incremental import."
+ sys.stderr.write("git cvsimport: incremental import is not supported with cvs2git.\n")
+ sys.exit(1)
+ def set_revmap(self, _val):
+ "Set the file to which the engine should dump a reference map."
+ sys.stderr.write("git cvsimport: can't get a reference map from cvs2git.\n")
+ sys.exit(1)
+ def set_module(self, val):
+ "Set the module to query."
+ self.modulepath = " " + val
+ def command(self):
+ "Emit the command implied by all previous options."
+ return "(cvs2git --username=git-cvsimport --quiet --quiet --blobfile={0} --dumpfile={1} {2} {3} && cat {0} {1} && rm {0} {1})".format(tempfile.mkstemp()[1], tempfile.mkstemp()[1], self.opts, self.modulepath)
+
+class filesource:
+ "Method class for file-source back end."
+ def __init__(self, filename):
+ self.filename = filename
+ def __complain(self, legend):
+ sys.stderr.write("git cvsimport: %s with file source.\n" % legend)
+ sys.exit(1)
+ def set_repo(self, _val):
+ "Set the repository root option."
+ self.__complain("repository can't be set")
+ def set_authormap(self, _val):
+ "Set the author-map file."
+ sys.stderr.write("git cvsimport: author mapping is not supported with filesource.\n")
+ sys.exit(1)
+ def set_fuzz(self, _val):
+ "Set the commit-similarity window."
+ self.__complain("fuzz can't be set")
+ def set_nokeywords(self, _val):
+ "Suppress CVS keyword expansion."
+ self.__complain("keyword suppression can't be set")
+ def add_opts(self, _val):
+ "Add options to the engine command line."
+ self.__complain("other options can't be set")
+ def set_exclusion(self, _val):
+ "Set a file exclusion regexp."
+ self.__complain("exclusions can't be set")
+ def set_after(self, _val):
+ "Set a date threshold for incremental import."
+ pass
+ def set_revmap(self, _val):
+ "Set the file to which the engine should dump a reference map."
+ sys.stderr.write("git cvsimport: can't get a reference map from cvs2git.\n")
+ sys.exit(1)
+ def set_module(self, _val):
+ "Set the module to query."
+ self.__complain("module can't be set")
+ def command(self):
+ "Emit the command implied by all previous options."
+ return "cat " + self.filename
+
+if __name__ == '__main__':
+ if sys.hexversion < 0x02060000:
+ sys.stderr.write("git cvsimport: requires Python 2.6 or later.\n")
+ sys.exit(1)
+ (options, arguments) = getopt.getopt(sys.argv[1:], "vbe:d:C:r:o:ikus:p:z:P:S:aL:A:Rh")
+ verbose = 0
+ bare = False
+ root = None
+ outdir = os.getcwd()
+ remotize = False
+ import_only = False
+ underscore_to_dot = False
+ slashsubst = None
+ authormap = None
+ revisionmap = False
+ backend = cvsps()
+ for (opt, val) in options:
+ if opt == '-v':
+ verbose += 1
+ elif opt == '-b':
+ bare = True
+ elif opt == '-e':
+ for cls in (cvsps, cvs2git):
+ if cls.__name__ == val:
+ backend = cls()
+ break
+ else:
+ sys.stderr.write("git cvsimport: unknown engine %s.\n" % val)
+ sys.exit(1)
+ elif opt == '-d':
+ backend.set_repo(val)
+ elif opt == '-C':
+ outdir = val
+ elif opt == '-r':
+ remotize = True
+ elif opt == '-o':
+ sys.stderr.write("git cvsimport: -o is no longer supported.\n")
+ sys.exit(1)
+ elif opt == '-i':
+ import_only = True
+ elif opt == '-k':
+ backend.set_nokeywords()
+ elif opt == '-u':
+ underscore_to_dot = True
+ elif opt == '-s':
+ slashsubst = val
+ elif opt == '-p':
+ backend.add_opts(val.replace(",", " "))
+ elif opt == '-z':
+ backend.set_fuzz(val)
+ elif opt == '-P':
+ backend = filesource(val)
+ sys.exit(1)
+ elif opt in ('-m', '-M'):
+ sys.stderr.write("git cvsimport: -m and -M are no longer supported: use reposurgeon instead.\n")
+ sys.exit(1)
+ elif opt == '-S':
+ backend.set_exclusion(val)
+ elif opt == '-a':
+ sys.stderr.write("git cvsimport: -a is no longer supported.\n")
+ sys.exit(1)
+ elif opt == '-L':
+ sys.stderr.write("git cvsimport: -L is no longer supported.\n")
+ sys.exit(1)
+ elif opt == '-A':
+ authormap = os.path.abspath(val)
+ elif opt == '-R':
+ revisionmap = True
+ else:
+ print """\
+git cvsimport [-A <author-conv-file>] [-C <git_repository>] [-b] [-d <CVSROOT>]
+ [-e engine] [-h] [-i] [-k] [-p <options-for-cvsps>] [-P <source-file>]
+ [-r <remote>] [-R] [-s <subst>] [-S <regex>] [-u] [-v] [-z <fuzz>]
+ [<CVS_module>]
+"""
+ def metadata(fn, outdir='.'):
+ if bare:
+ return os.path.join(outdir, fn)
+ else:
+ return os.path.join(outdir, ".git", fn)
+
+ try:
+ if outdir:
+ try:
+ # If the output directory does not exist, create it
+ # and initialize it as a git repository.
+ os.mkdir(outdir)
+ do_or_die("git init --quiet " + outdir)
+ except OSError:
+ # Otherwise, assume user wants incremental import.
+ if not bare and not os.path.exists(os.path.join(outdir, ".git")):
+ raise Fatal("output directory is not a git repository")
+ threshold = capture_or_die("git log -1 --format=%ct").strip()
+ backend.set_after(threshold)
+ if revisionmap:
+ backend.set_revmap(tempfile.mkstemp()[1])
+ markmap = tempfile.mkstemp()[1]
+ if arguments:
+ backend.set_module(arguments[0])
+ gitopts = ""
+ if bare:
+ gitopts += " --bare"
+ if revisionmap:
+ gitopts += " --export-marks='%s'" % markmap
+ if authormap:
+ shutil.copyfile(authormap, metadata("cvs-authors", outdir))
+ if os.path.exists(metadata("cvs-authors", outdir)):
+ backend.set_authormap(metadata("cvs-authors", outdir))
+ do_or_die("%s | (cd %s >/dev/null; git fast-import --quiet %s)" \
+ % (backend.command(), outdir, gitopts))
+ os.chdir(outdir)
+ if underscore_to_dot or slashsubst:
+ tagnames = capture_or_die("git tag -l")
+ for tag in tagnames.split():
+ if tag:
+ changed = tag
+ if underscore_to_dot:
+ changed = changed.replace("_", ".")
+ if slashsubst:
+ changed = changed.replace(os.sep, slashsubst)
+ if changed != tag:
+ do_or_die("git tag -f %s %s >/dev/null" % (tag, changed))
+ if underscore_to_dot or slashsubst or remotize:
+ branchnames = capture_or_die("git branch -l")
+ for branch in branchnames.split():
+ if branch:
+ # Ugh - fragile dependency on branch -l output format
+ branch = branch[2:]
+ changed = branch
+ if underscore_to_dot:
+ changed = changed.replace("_", ".")
+ if slashsubst:
+ changed = changed.replace(os.sep, slashsubst)
+ if remotize:
+ changed = os.path.join("remotes", remotize, branch)
+ if changed != branch:
+ do_or_die("branch --m %s %s >/dev/null" % (branch, changed))
+ if revisionmap:
+ refd = {}
+ for line in open(backend.revmap):
+ if line.startswith("#"):
+ continue
+ (fn, rev, mark) = line.split()
+ refd[(fn, rev)] = mark
+ markd = {}
+ for line in open(markmap):
+ if line.startswith("#"):
+ continue
+ (mark, hashd) = line.split()
+ markd[mark] = hashd
+ with open(metadata("cvs-revisions"), "a") as wfp:
+ for ((fn, rev), val) in refd.items():
+ if val in markd:
+ wfp.write("%s %s %s\n" % (fn, rev, markd[val]))
+ os.remove(markmap)
+ os.remove(backend.revmap)
+ if not import_only and not bare:
+ do_or_die("git checkout -q")
+ except Fatal, err:
+ sys.stderr.write("git_cvsimport: " + err.msg + "\n")
+ sys.exit(1)
+ except KeyboardInterrupt:
+ pass
+
+# end
diff --git a/git-cvsimport.sh b/git-cvsimport.sh
index 71ba11d..52ce112 100755
--- a/git-cvsimport.sh
+++ b/git-cvsimport.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-GIT_CVSPS_VERSION=2
+: ${GIT_CVSPS_VERSION=2}
-exec git cvsimport-$GIT_CVSPS_VERSION "$@"
+exec git "cvsimport-$GIT_CVSPS_VERSION" "$@"
--
1.8.1.421.g6236851
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox