* Re: Adding a 'version' command to the server
From: Junio C Hamano @ 2008-06-27 23:15 UTC (permalink / raw)
To: Lea Wiemann; +Cc: git
In-Reply-To: <486572BC.9070201@gmail.com>
Lea Wiemann <lewiemann@gmail.com> writes:
> Junio C Hamano wrote:
>
>> It is still possible to connect to older remote end with new clients, but
>> you have to explicitly ask for "git-upload-pack" by using --upload-pack=
>> option when running "git fetch"
>
> Now that the current git won't work with older servers anyway,...
Whoa, Wait. Who said that?
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: Junio C Hamano @ 2008-06-27 23:14 UTC (permalink / raw)
To: Robert Anderson; +Cc: David Jeske, Jakub Narebski, git
In-Reply-To: <9af502e50806271555j3cd06ecau122b11217f612217@mail.gmail.com>
"Robert Anderson" <rwa000@gmail.com> writes:
> There are good reasons for desiring a workflow that does not routinely
> change history as part of the usual workflow. Maybe there are clones
> of your repo. Maybe as part of your workflow discipline you do not
> want HEAD states that cannot be pushed to public, because you don't
> want to manually keep track of when it is ok and when it is not ok to
> push HEAD to public, since git cannot tell you this.
Surely you can arrange that. You keep track of what you pushed out, and
you refrain from rebasing beyond that point.
And fast-forward check in the push to the public will notice if you break
that "workflow discipline" by accident.
^ permalink raw reply
* Adding a 'version' command to the server (was: git@vger.kernel.org)
From: Lea Wiemann @ 2008-06-27 23:07 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7viqvupm3l.fsf@gitster.siamese.dyndns.org>
Junio C Hamano wrote:
> It is still possible to connect to older remote end with new clients, but
> you have to explicitly ask for "git-upload-pack" by using --upload-pack=
> option when running "git fetch"
Now that the current git won't work with older servers anyway, what
about using this opportunity to add a 'version' command to the server?
With such a command, such problems would seem to be quite easily
avoidable in the future, since the client can discriminate based on the
server's version.
I'm not sure how to implement this (the problems seem to be that (a) it
needs to work with git-shell and real shells, and (b) that older clients
must not be supplied with a version number in order not to break them),
but perhaps this is worth pondering.
Apologies if this has been discussed before.
-- Lea
^ permalink raw reply
* Re: [PATCH, next version] git bisect: introduce 'fixed' and 'unfixed'
From: Junio C Hamano @ 2008-06-27 23:03 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Jeff King, git
In-Reply-To: <alpine.DEB.1.00.0806271446180.9925@racer>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> When you look for a fix instead of a regression, it can be quite hard
> to twist your brain into choosing the correct bisect command between
> 'git bisect bad' and 'git bisect good'.
Hmm, I do not currently see any differene between master and next version
of bisect. In what way is this 'next' version?
Aside from the 'visualize' issue this does not attempt to address, I
wonder if it may be a good idea to detect and warn mixed usage as well
(e.g. "You earlier said 'bad' but now you are saying 'fixed' -- are you
sure?"), and if so if it can be implemented easily.
^ permalink raw reply
* Re: BUG (v1.5.6.1): ./configure missing check for zlib.h
From: Jakub Narebski @ 2008-06-27 23:03 UTC (permalink / raw)
To: Mircea Bardac; +Cc: Tom Fogal, git
In-Reply-To: <20080627150732.D88F64B4002@artemis.sr.unh.edu>
On Fri, 27 Jun 2008, tom fogal wrote:
> Jakub Narebski <jnareb@gmail.com> writes:
>> Mircea Bardac <dev@mircea.bardac.net> writes:
>>
>>> $ ./configure
>> [...]
>>> configure: CHECKS for header files
>>> In file included from daemon.c:1:
>>> cache.h:9:18: error: zlib.h: No such file or directory
>>> make: *** [daemon.o] Error 1
>>>
>>> (installing zlib1g-dev on Ubuntu 7.10 fixed the problem)
>>
>> What should ./configure do (what ./configure for other programs
>> or packages do)?
>>
>> You cannot compile git without zlib!
>
> If one can determine during configure time that a required library is
> not found, it (IMHO) is nice to give an error message and bomb out (via
> AC_MSG_ERROR).
>
> The AC macro archive has a zlib macro which does this, as an example:
>
> http://autoconf-archive.cryp.to/check_zlib.html
>
> I should note, however, that I disagree with that macro's logic in that
> it `searches' for zlib if the user does not specify it. IMO, if the
> user does not give a --with option, and it doesn't work `out of the
> box' (without hacking FLAGS), macros should die with an error rather
> than retry with changed FLAGS.
On Fri, 27 Jun 2008, Mircea Bardac wrote:
>
> Well, as far as I know, if a program depends on any external headers,
> they should *all* be checked, not only "those that can be skipped by
> defining some macro" (I personally do not know which are these).
In git (not like usually in other projects) ./configure script (autoconf)
is used *only* to generate Makefile configuration. It tries to configure
compile (build) process in such a way that building git is possible even
if some features are missing or are found not in standard place (and also
use compat version of functions if they are not in library). It helps you
build system.
I'm not sure if checking if prerequisites exists and failing loudly
otherwise would be a good feature to have. Git would fail anyway during
build process, so it is not some new feature. The only advantage is that
required and unavoidable dependency would be found earlier; on the other
hand there is now disadvantage of build process (./configure process)
if it misdetects lack of needed header files, i.e. it is possible to
compile (build) git, but ./configure detects that it is not so. This
happened once to me, and is very annoying...
But as they say, "code speaks louder than words"
--
Jakub Narebski
Poland
^ permalink raw reply
* Re: An alternate model for preparing partial commits
From: Robert Anderson @ 2008-06-27 22:55 UTC (permalink / raw)
To: David Jeske; +Cc: Jakub Narebski, git
In-Reply-To: <-8386235276716376372@unknownmsgid>
On Fri, Jun 27, 2008 at 1:51 PM, David Jeske <jeske@willowmail.com> wrote:
> -- Jakub Narebski wrote:
>> git rebase --interactive?
>> Any patch management interface (StGIT, Guilt)?
>
> Yes, as I said, that set of operations can be performed with git today.
>
> What git can't do, is let me "supercede" the old DAG-subset, so people I shared
> them with can get my new changes without hurting their world. Currently git
> seems to rely on the idea that "if you accept changes into your tree that will
> be later rebased, it's up to you to figure it out". I don't see why that is the
> case.
Possibly a succinct way of moving this conversation forward is to say that:
What is desired is a workflow where partial commits can be tested,
when it is desirable not to change history.
There are good reasons for desiring a workflow that does not routinely
change history as part of the usual workflow. Maybe there are clones
of your repo. Maybe as part of your workflow discipline you do not
want HEAD states that cannot be pushed to public, because you don't
want to manually keep track of when it is ok and when it is not ok to
push HEAD to public, since git cannot tell you this.
Thanks,
Bob
^ permalink raw reply
* Re: [PATCH 1/2] clone: respect the settings in $HOME/.gitconfig and /etc/gitconfig
From: Junio C Hamano @ 2008-06-27 22:40 UTC (permalink / raw)
To: Daniel Barkalow; +Cc: Johannes Schindelin, Pieter de Bie, Git Mailinglist
In-Reply-To: <alpine.LNX.1.00.0806271149580.19665@iabervon.org>
Daniel Barkalow <barkalow@iabervon.org> writes:
> On Fri, 27 Jun 2008, Johannes Schindelin wrote:
>
>> After initializing the config in the newly-created repository, we
>> need to unset GIT_CONFIG so that the global configs are read again.
>
> This seems fine to me. OTOH, I'm not sure the environment variable should
> be needed in the first place; I think the config stuff should look in
> git_path("config") without it, and we set the git dir to the one we're
> initializing. So I think the use of the environment variable is just an
> artifact of how the shell script did it and how I was originally calling
> the init_db stuff.
>
> Just removing the "setenv()" line survives all of the tests for me, and I
> remember some of them failing before I'd gotten some sort of solution for
> the config stuff.
Ok, I take that you are Ok with 2/2 but you have a better replacement
patch coming for this 1/2?
^ permalink raw reply
* Re: [PATCH] shrink git-shell by avoiding redundant dependencies
From: Junio C Hamano @ 2008-06-27 22:34 UTC (permalink / raw)
To: Dmitry Potapov; +Cc: Git Mailing List
In-Reply-To: <20080627223107.GH5737@dpotapov.dyndns.org>
Dmitry Potapov <dpotapov@gmail.com> writes:
> On Fri, Jun 27, 2008 at 02:55:32PM -0700, Junio C Hamano wrote:
>> Dmitry Potapov <dpotapov@gmail.com> writes:
>>
>> > diff --git a/abspath.c b/abspath.c
>> > new file mode 100644
>> > index 0000000..4becedf
>> > --- /dev/null
>> > +++ b/abspath.c
>> > @@ -0,0 +1,80 @@
>> > +/*
>> > + * I'm tired of doing "vsnprintf()" etc just to open a
>> > + * file, so here's a "return static buffer with printf"
>> > + * interface for paths.
>> > + *
>> > + * It's obviously not thread-safe. Sue me. But it's quite
>> > + * useful for doing things like
>> > + *
>> > + * f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
>> > + *
>> > + * which is what it's designed for.
>> > + */
>>
>> This is not a comment you would want to move to the resulting file that
>> contains only make_absolute_path().
>
> I am sorry... I removed this comment. Here is the corrected patch.
No need to say nor be sorry. The rest looks sane from a quick glance,
except that we may want to have a separate clean-up patch that
consolidates MAXDEPTH in many places that limits our manual symlink
resolution.
^ permalink raw reply
* Re: [PATCH] shrink git-shell by avoiding redundant dependencies
From: Dmitry Potapov @ 2008-06-27 22:31 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Git Mailing List
In-Reply-To: <7vod5mpmp7.fsf@gitster.siamese.dyndns.org>
On Fri, Jun 27, 2008 at 02:55:32PM -0700, Junio C Hamano wrote:
> Dmitry Potapov <dpotapov@gmail.com> writes:
>
> > diff --git a/abspath.c b/abspath.c
> > new file mode 100644
> > index 0000000..4becedf
> > --- /dev/null
> > +++ b/abspath.c
> > @@ -0,0 +1,80 @@
> > +/*
> > + * I'm tired of doing "vsnprintf()" etc just to open a
> > + * file, so here's a "return static buffer with printf"
> > + * interface for paths.
> > + *
> > + * It's obviously not thread-safe. Sue me. But it's quite
> > + * useful for doing things like
> > + *
> > + * f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
> > + *
> > + * which is what it's designed for.
> > + */
>
> This is not a comment you would want to move to the resulting file that
> contains only make_absolute_path().
I am sorry... I removed this comment. Here is the corrected patch.
-- 8< --
From: Dmitry Potapov <dpotapov@gmail.com>
Date: Sat, 28 Jun 2008 00:46:42 +0400
Subject: [PATCH] shrink git-shell by avoiding redundant dependencies
A lot of modules that have nothing to do with git-shell functionality
were linked in, bloating git-shell more than 8 times.
This patch cuts off redundant dependencies by:
1. providing stubs for three functions that make no sense for git-shell;
2. moving quote_path_fully from environment.c to quote.c to make the
later self sufficient;
3. moving make_absolute_path into a new separate file.
The following numbers have been received with the default optimization
settings on master using GCC 4.1.2:
Before:
text data bss dec hex filename
143915 1348 93168 238431 3a35f git-shell
After:
text data bss dec hex filename
17670 788 8232 26690 6842 git-shell
---
Makefile | 1 +
abspath.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
environment.c | 1 -
path.c | 67 --------------------------------------------------------
quote.c | 2 +
shell.c | 8 ++++++
6 files changed, 79 insertions(+), 68 deletions(-)
create mode 100644 abspath.c
diff --git a/Makefile b/Makefile
index 3584b8c..bf77292 100644
--- a/Makefile
+++ b/Makefile
@@ -378,6 +378,7 @@ LIB_H += unpack-trees.h
LIB_H += utf8.h
LIB_H += wt-status.h
+LIB_OBJS += abspath.o
LIB_OBJS += alias.o
LIB_OBJS += alloc.o
LIB_OBJS += archive.o
diff --git a/abspath.c b/abspath.c
new file mode 100644
index 0000000..4f95a95
--- /dev/null
+++ b/abspath.c
@@ -0,0 +1,68 @@
+#include "cache.h"
+
+/* We allow "recursive" symbolic links. Only within reason, though. */
+#define MAXDEPTH 5
+
+const char *make_absolute_path(const char *path)
+{
+ static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
+ char cwd[1024] = "";
+ int buf_index = 1, len;
+
+ int depth = MAXDEPTH;
+ char *last_elem = NULL;
+ struct stat st;
+
+ if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+ die ("Too long path: %.*s", 60, path);
+
+ while (depth--) {
+ if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
+ char *last_slash = strrchr(buf, '/');
+ if (last_slash) {
+ *last_slash = '\0';
+ last_elem = xstrdup(last_slash + 1);
+ } else {
+ last_elem = xstrdup(buf);
+ *buf = '\0';
+ }
+ }
+
+ if (*buf) {
+ if (!*cwd && !getcwd(cwd, sizeof(cwd)))
+ die ("Could not get current working directory");
+
+ if (chdir(buf))
+ die ("Could not switch to '%s'", buf);
+ }
+ if (!getcwd(buf, PATH_MAX))
+ die ("Could not get current working directory");
+
+ if (last_elem) {
+ int len = strlen(buf);
+ if (len + strlen(last_elem) + 2 > PATH_MAX)
+ die ("Too long path name: '%s/%s'",
+ buf, last_elem);
+ buf[len] = '/';
+ strcpy(buf + len + 1, last_elem);
+ free(last_elem);
+ last_elem = NULL;
+ }
+
+ if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
+ len = readlink(buf, next_buf, PATH_MAX);
+ if (len < 0)
+ die ("Invalid symlink: %s", buf);
+ next_buf[len] = '\0';
+ buf = next_buf;
+ buf_index = 1 - buf_index;
+ next_buf = bufs[buf_index];
+ } else
+ break;
+ }
+
+ if (*cwd && chdir(cwd))
+ die ("Could not change back to '%s'", cwd);
+
+ return buf;
+}
diff --git a/environment.c b/environment.c
index 084ac8a..4a88a17 100644
--- a/environment.c
+++ b/environment.c
@@ -13,7 +13,6 @@ char git_default_email[MAX_GITNAME];
char git_default_name[MAX_GITNAME];
int user_ident_explicitly_given;
int trust_executable_bit = 1;
-int quote_path_fully = 1;
int has_symlinks = 1;
int ignore_case;
int assume_unchanged;
diff --git a/path.c b/path.c
index 6e3df18..496123c 100644
--- a/path.c
+++ b/path.c
@@ -327,9 +327,6 @@ const char *make_nonrelative_path(const char *path)
return buf;
}
-/* We allow "recursive" symbolic links. Only within reason, though. */
-#define MAXDEPTH 5
-
const char *make_relative_path(const char *abs, const char *base)
{
static char buf[PATH_MAX + 1];
@@ -346,67 +343,3 @@ const char *make_relative_path(const char *abs, const char *base)
strcpy(buf, abs + baselen);
return buf;
}
-
-const char *make_absolute_path(const char *path)
-{
- static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
- char cwd[1024] = "";
- int buf_index = 1, len;
-
- int depth = MAXDEPTH;
- char *last_elem = NULL;
- struct stat st;
-
- if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
- die ("Too long path: %.*s", 60, path);
-
- while (depth--) {
- if (stat(buf, &st) || !S_ISDIR(st.st_mode)) {
- char *last_slash = strrchr(buf, '/');
- if (last_slash) {
- *last_slash = '\0';
- last_elem = xstrdup(last_slash + 1);
- } else {
- last_elem = xstrdup(buf);
- *buf = '\0';
- }
- }
-
- if (*buf) {
- if (!*cwd && !getcwd(cwd, sizeof(cwd)))
- die ("Could not get current working directory");
-
- if (chdir(buf))
- die ("Could not switch to '%s'", buf);
- }
- if (!getcwd(buf, PATH_MAX))
- die ("Could not get current working directory");
-
- if (last_elem) {
- int len = strlen(buf);
- if (len + strlen(last_elem) + 2 > PATH_MAX)
- die ("Too long path name: '%s/%s'",
- buf, last_elem);
- buf[len] = '/';
- strcpy(buf + len + 1, last_elem);
- free(last_elem);
- last_elem = NULL;
- }
-
- if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) {
- len = readlink(buf, next_buf, PATH_MAX);
- if (len < 0)
- die ("Invalid symlink: %s", buf);
- next_buf[len] = '\0';
- buf = next_buf;
- buf_index = 1 - buf_index;
- next_buf = bufs[buf_index];
- } else
- break;
- }
-
- if (*cwd && chdir(cwd))
- die ("Could not change back to '%s'", cwd);
-
- return buf;
-}
diff --git a/quote.c b/quote.c
index d5cf9d8..6a52085 100644
--- a/quote.c
+++ b/quote.c
@@ -1,6 +1,8 @@
#include "cache.h"
#include "quote.h"
+int quote_path_fully = 1;
+
/* Help to copy the thing properly quoted for the shell safety.
* any single quote is replaced with '\'', any exclamation point
* is replaced with '\!', and the whole thing is enclosed in a
diff --git a/shell.c b/shell.c
index b27d01c..91ca7de 100644
--- a/shell.c
+++ b/shell.c
@@ -3,6 +3,14 @@
#include "exec_cmd.h"
#include "strbuf.h"
+/* Stubs for functions that make no sense for git-shell. These stubs
+ * are provided here to avoid linking in external redundant modules.
+ */
+void release_pack_memory(size_t need, int fd){}
+void trace_argv_printf(const char **argv, const char *fmt, ...){}
+void trace_printf(const char *fmt, ...){}
+
+
static int do_generic_cmd(const char *me, char *arg)
{
const char *my_argv[4];
--
1.5.6.1
^ permalink raw reply related
* Re: git@vger.kernel.org
From: Junio C Hamano @ 2008-06-27 22:14 UTC (permalink / raw)
To: git
In-Reply-To: <7viqvupm3l.fsf@gitster.siamese.dyndns.org>
Sorry, while trying to fudge the headers and messages to avoid triggering
vger's spam filter, I managed to mangle the subject of that message. It
should have read:
Subject: Glitches connecting to existing remote using 'next' git
^ permalink raw reply
* Re: [PATCH] cmd_reset: don't trash uncommitted changes unless told to
From: Junio C Hamano @ 2008-06-27 22:11 UTC (permalink / raw)
To: しらいしななこ
Cc: Theodore Tso, Avery Pennarun, Johannes Schindelin, Johannes Sixt,
Boaz Harrosh, Steven Walter, git, jeske
In-Reply-To: <20080627193325.6117@nanako3.lavabit.com>
しらいしななこ <nanako3@lavabit.com> writes:
> Quoting Junio C Hamano <gitster@pobox.com>:
>
>> > Theodore Tso <tytso@mit.edu> writes:
>> > ...
>> >> Stupid quesiton --- where is this documented? I don't see this
>> >> documented either in the man page for git or git-checkout.
>> >
>> > You are asking a wrong person. My git knowledge mostly comes from
>> > yearlong reading of the mailing list articles, and doing a bit myself also
>> > helps ;-).
>>
>> I couldn't find a good central place to place this as this is more or less
>> used consistently throughout the UI (log, diff, grep, and then I just
>> fixed reset as well).
>>
>> Whereever the description should end up to be in, here is what I think we
>> should talk about.
>
> Because it is where the convention that is used in all of the UI is
> described, I think gitcli documentation is an appropriate place.
I am still not convinced it is the best place but I guess it would be
better than not documenting it anywhere.
> Don't you also want to talk about distinction between --cached and
> --index that new people are often confused about? These options are
> defined consistently across commands but people who do not know it bring
> up discussions to rename --cached to some commands to --index to make it
> inconsistent and waste your time every once in a while.
^ permalink raw reply
* git@vger.kernel.org
From: Junio C Hamano @ 2008-06-27 22:08 UTC (permalink / raw)
To: git
[jc: trying to resend this message I sent late last night, because vger
did not seem to have relayed it to the list for some unknown reason.]
Some people noticed that they have trouble going to remote site over ssh
transport using 'next' version of git.
A brief git transport primer may be helpful to understand what is going
on. When you run "git fetch" (and remember, "git pull" runs it before it
runs "git merge") against a remote over ssh transport, it asks the other
side to run "git-upload-pack" program. We have always used the dashed
form "git-upload-pack" to make this request. Similarly, "git push" (and
"git send-pack") runs "git-receive-pack" and "git archive --remote" runs
"git-upload-archive" on the other end.
We have promised to move most of the git-$foobar programs out of the end
users' $PATH starting from 1.6.0. After git-upload-pack moves outside
$PATH, however, asking the shell invoked via ssh on the other and to run
git-upload-pack won't find it, because the program is not found anywhere
on $PATH. Hence, change to ask for "git upload-pack" is eventually
necessary. We cannot avoid it.
Now, when the remote side runs pre-1.6.0 software, and the ssh daemon on
it runs a real shell, asking for "git upload-pack" (i.e. dashless form)
does not have any problem. "git" will be on your $PATH and it always
knows where "git-upload-pack" is found, and it will run the program you
wanted to run just fine.
However, when the remote side does not let you run a real shell, this is
problematic. For example, your login shell can be set to "git-shell" (git
restricted shell), which refuses to run anything but git-upload-pack,
git-receive-pack, or git-upload-archive. Specifically, it does not allow
you to run "git" itself with arbitrary arguments. Asking such a server to
run "git upload-pack" will not work. gitosis is another example of such a
server. Both git-shell and gitosis already have patches to prepare them
to accept requests in either forms.
It is still possible to connect to older remote end with new clients, but
you have to explicitly ask for "git-upload-pack" by using --upload-pack=
option when running "git fetch", which is a bit cumbersome. Hence, we
have to wait before people can update their servers, and then update the
client side to start asking for "git upload-pack" and friends with
dashless form.
The patch to prepare the client side for this was prepared and queued in
"next" a few days ago. Consider this glitch as a part of proving the
change while in next. You have a real-world opportunity to make sure that
the workaround to use --upload-pack= actually works with older remote end
and send in success reports ;-)
In other words, Sorry, I screwed up.
I've cut v1.5.4.6 and v1.5.5.5 releases tonight (they are tagged and
pushed out already), both of which contain updates to "git-shell" so that
it accepts both dashed and non-dashed forms, to make it easier for people
to update their servers. At the same time, the change to the client side
has been reverted from 'next' for now.
Cooking and proving the client side change in next will still be needed,
but we'll postpone it for now.
Also, 1.6.0 will still install git-upload-pack and friends that are needed
on the server side in $(bindir) that is on your $PATH, so that older
clients will still work.
So the timeline will be:
* Futureproofed "git-shell" and gitosis are released. People slowly
start deploying them. Both old and (unreleased yet) new clients will
be able to talk to them.
* 1.6.0 installs git-upload-pack and friends in $(bindir) on your $PATH.
Both old clients and 1.6.0 clients will ask for git-upload-pack and the
real shell will still be able to find them.
* 6 months after 1.6.0 ships, these futureproofed "git-shell" and gitosis
will be in widespread use and nobody runs older servers anymore. A
major release after this happens will change the client to start asking
for "git upload-pack" (dashless form).
You would need --upload-pack=git-upload-pack option to talk to ancient
servers when this happens (and past few days were preview of this).
* 12 months after that major release ships, these new clients will be in
widespread use and nobody runs older clients anymore. A major release
after this happens will stop installing git-upload-pack and friends in
$(bindir).
Older clients (like v1.5.0) would use --upload-pack="git upload-pack"
to talk to new servers.
^ permalink raw reply
* [EGIT PATCH 23/23] Use new TransportException constructors
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-23-git-send-email-marek.zawirski@gmail.com>
Modify existing TransportException constructor calls to new ones with
URI as argument.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../spearce/jgit/transport/BasePackConnection.java | 6 +++---
.../jgit/transport/BasePackPushConnection.java | 12 ++++++------
.../org/spearce/jgit/transport/PushProcess.java | 6 +++---
.../spearce/jgit/transport/TransportGitAnon.java | 15 +++++++--------
.../spearce/jgit/transport/TransportGitSsh.java | 18 ++++++++----------
.../org/spearce/jgit/transport/TransportLocal.java | 3 +--
.../org/spearce/jgit/transport/TransportSftp.java | 12 +++++-------
7 files changed, 33 insertions(+), 39 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
index d119672..9b39ebc 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackConnection.java
@@ -125,7 +125,7 @@ abstract class BasePackConnection extends BaseConnection {
line = pckIn.readString();
} catch (EOFException eof) {
if (avail.isEmpty())
- throw new TransportException(uri + " not found.");
+ throw new TransportException(uri, "not found.");
throw eof;
}
@@ -155,7 +155,7 @@ abstract class BasePackConnection extends BaseConnection {
name = name.substring(0, name.length() - 3);
final Ref prior = avail.get(name);
if (prior == null)
- throw new PackProtocolException(uri + ": advertisement of "
+ throw new PackProtocolException(uri, "advertisement of "
+ name + "^{} came before " + name);
if (prior.getPeeledObjectId() != null)
@@ -185,7 +185,7 @@ abstract class BasePackConnection extends BaseConnection {
}
private PackProtocolException duplicateAdvertisement(final String name) {
- return new PackProtocolException(uri + ": duplicate advertisements of "
+ return new PackProtocolException(uri, "duplicate advertisements of "
+ name);
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
index 159e331..c56605a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
@@ -110,7 +110,7 @@ class BasePackPushConnection extends BasePackConnection implements
} catch (TransportException e) {
throw e;
} catch (Exception e) {
- throw new TransportException(uri + ": " + e.getMessage(), e);
+ throw new TransportException(uri, e.getMessage(), e);
} finally {
close();
}
@@ -146,7 +146,7 @@ class BasePackPushConnection extends BasePackConnection implements
}
if (monitor.isCancelled())
- throw new TransportException(uri + ": push cancelled");
+ throw new TransportException(uri, "push cancelled");
pckOut.end();
}
@@ -179,13 +179,13 @@ class BasePackPushConnection extends BasePackConnection implements
throws IOException {
final String unpackLine = pckIn.readString();
if (!unpackLine.startsWith("unpack "))
- throw new PackProtocolException(uri + ": unexpected report line: "
+ throw new PackProtocolException(uri, "unexpected report line: "
+ unpackLine);
final String unpackStatus = unpackLine.substring("unpack ".length());
if (!unpackStatus.equals("ok"))
- throw new TransportException(uri
- + ": error occurred during unpacking on the remote end: "
- + unpackStatus);
+ throw new TransportException(uri,
+ "error occurred during unpacking on the remote end: "
+ + unpackStatus);
String refLine;
while ((refLine = pckIn.readString()).length() > 0) {
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
index f742949..1b5f9c6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
@@ -178,9 +178,9 @@ class PushProcess {
} catch (MissingObjectException x) {
fastForward = false;
} catch (Exception x) {
- throw new TransportException(transport.getURI()
- + ": reading objects from local repository failed: "
- + x.getMessage(), x);
+ throw new TransportException(transport.getURI(),
+ "reading objects from local repository failed: "
+ + x.getMessage(), x);
}
rru.setFastForward(fastForward);
if (!fastForward && !rru.isForceUpdate())
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
index 6e49083..8a78099 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
@@ -82,12 +82,11 @@ class TransportGitAnon extends PackTransport {
try {
return new Socket(InetAddress.getByName(uri.getHost()), port);
} catch (IOException c) {
- final String us = uri.toString();
if (c instanceof UnknownHostException)
- throw new TransportException(us + ": Unknown host");
+ throw new TransportException(uri, "unknown host");
if (c instanceof ConnectException)
- throw new TransportException(us + ": " + c.getMessage());
- throw new TransportException(us + ": " + c.getMessage(), c);
+ throw new TransportException(uri, c.getMessage());
+ throw new TransportException(uri, c.getMessage(), c);
}
}
@@ -116,8 +115,8 @@ class TransportGitAnon extends PackTransport {
service("git-upload-pack", pckOut);
} catch (IOException err) {
close();
- throw new TransportException(uri.toString()
- + ": remote hung up unexpectedly", err);
+ throw new TransportException(uri,
+ "remote hung up unexpectedly", err);
}
readAdvertisedRefs();
}
@@ -149,8 +148,8 @@ class TransportGitAnon extends PackTransport {
service("git-receive-pack", pckOut);
} catch (IOException err) {
close();
- throw new TransportException(uri.toString()
- + ": remote hung up unexpectedly", err);
+ throw new TransportException(uri,
+ "remote hung up unexpectedly", err);
}
readAdvertisedRefs();
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index 55be4f6..46c60c3 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -162,13 +162,12 @@ class TransportGitSsh extends PackTransport {
session.connect();
return session;
} catch (JSchException je) {
- final String us = uri.toString();
final Throwable c = je.getCause();
if (c instanceof UnknownHostException)
- throw new TransportException(us + ": Unknown host");
+ throw new TransportException(uri, "unknown host");
if (c instanceof ConnectException)
- throw new TransportException(us + ": " + c.getMessage());
- throw new TransportException(us + ": " + je.getMessage(), je);
+ throw new TransportException(uri, c.getMessage());
+ throw new TransportException(uri, je.getMessage(), je);
}
}
@@ -189,8 +188,7 @@ class TransportGitSsh extends PackTransport {
channel.connect();
return channel;
} catch (JSchException je) {
- throw new TransportException(uri.toString() + ": "
- + je.getMessage(), je);
+ throw new TransportException(uri, je.getMessage(), je);
}
}
@@ -210,8 +208,8 @@ class TransportGitSsh extends PackTransport {
throw err;
} catch (IOException err) {
close();
- throw new TransportException(uri.toString()
- + ": remote hung up unexpectedly", err);
+ throw new TransportException(uri,
+ "remote hung up unexpectedly", err);
}
readAdvertisedRefs();
}
@@ -255,8 +253,8 @@ class TransportGitSsh extends PackTransport {
throw err;
} catch (IOException err) {
close();
- throw new TransportException(uri.toString()
- + ": remote hung up unexpectedly", err);
+ throw new TransportException(uri,
+ "remote hung up unexpectedly", err);
}
readAdvertisedRefs();
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
index f48dc6d..761d1b8 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
@@ -99,8 +99,7 @@ class TransportLocal extends PackTransport {
new StreamRewritingThread(proc.getErrorStream()).start();
return proc;
} catch (IOException err) {
- throw new TransportException(uri.toString() + ": "
- + err.getMessage(), err);
+ throw new TransportException(uri, err.getMessage(), err);
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java
index cfe22c1..21657ef 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportSftp.java
@@ -111,13 +111,12 @@ class TransportSftp extends WalkTransport {
session.connect();
return session;
} catch (JSchException je) {
- final String us = uri.toString();
final Throwable c = je.getCause();
if (c instanceof UnknownHostException)
- throw new TransportException(us + ": Unknown host");
+ throw new TransportException(uri, "unknown host");
if (c instanceof ConnectException)
- throw new TransportException(us + ": " + c.getMessage());
- throw new TransportException(us + ": " + je.getMessage(), je);
+ throw new TransportException(uri, c.getMessage());
+ throw new TransportException(uri, je.getMessage(), je);
}
}
@@ -127,8 +126,7 @@ class TransportSftp extends WalkTransport {
channel.connect();
return (ChannelSftp) channel;
} catch (JSchException je) {
- throw new TransportException(uri.toString() + ": "
- + je.getMessage(), je);
+ throw new TransportException(uri, je.getMessage(), je);
}
}
@@ -259,7 +257,7 @@ class TransportSftp extends WalkTransport {
} catch (FileNotFoundException notPacked) {
// Perhaps it wasn't worthwhile, or is just an older repository.
} catch (IOException e) {
- throw new TransportException(uri + ": error in packed-refs", e);
+ throw new TransportException(uri, "error in packed-refs", e);
}
readRef(avail, "../HEAD", "HEAD");
readLooseRefs(avail, "../refs", "refs/");
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 22/23] Add new handy constructors to TransportException, PackProtocolException
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-22-git-send-email-marek.zawirski@gmail.com>
Constructor takes additionally URI argument, to add prefix: uri + ": "
before real message. Now we don't have to remember about ugly (uri + ":
") prefix in each thrown message;
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../spearce/jgit/errors/PackProtocolException.java | 30 +++++++++++++++++++
.../spearce/jgit/errors/TransportException.java | 31 ++++++++++++++++++++
2 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java
index 525496a..7b5b4f6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/PackProtocolException.java
@@ -38,6 +38,7 @@
package org.spearce.jgit.errors;
+import org.spearce.jgit.transport.URIish;
/**
* Indicates a protocol error has occurred while fetching/pushing objects.
@@ -46,6 +47,35 @@ public class PackProtocolException extends TransportException {
private static final long serialVersionUID = 1L;
/**
+ * Constructs an PackProtocolException with the specified detail message
+ * prefixed with provided URI.
+ *
+ * @param uri
+ * URI used for transport
+ * @param s
+ * message
+ */
+ public PackProtocolException(final URIish uri, final String s) {
+ super(uri + ": " + s);
+ }
+
+ /**
+ * Constructs an PackProtocolException with the specified detail message
+ * prefixed with provided URI.
+ *
+ * @param uri
+ * URI used for transport
+ * @param s
+ * message
+ * @param cause
+ * root cause exception
+ */
+ public PackProtocolException(final URIish uri, final String s,
+ final Throwable cause) {
+ this(uri + ": " + s, cause);
+ }
+
+ /**
* Constructs an PackProtocolException with the specified detail message.
*
* @param s
diff --git a/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java b/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java
index 7b378db..13c7a28 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/errors/TransportException.java
@@ -40,6 +40,8 @@ package org.spearce.jgit.errors;
import java.io.IOException;
+import org.spearce.jgit.transport.URIish;
+
/**
* Indicates a protocol error has occurred while fetching/pushing objects.
*/
@@ -47,6 +49,35 @@ public class TransportException extends IOException {
private static final long serialVersionUID = 1L;
/**
+ * Constructs an TransportException with the specified detail message
+ * prefixed with provided URI.
+ *
+ * @param uri
+ * URI used for transport
+ * @param s
+ * message
+ */
+ public TransportException(final URIish uri, final String s) {
+ super(uri + ": " + s);
+ }
+
+ /**
+ * Constructs an TransportException with the specified detail message
+ * prefixed with provided URI.
+ *
+ * @param uri
+ * URI used for transport
+ * @param s
+ * message
+ * @param cause
+ * root cause exception
+ */
+ public TransportException(final URIish uri, final String s,
+ final Throwable cause) {
+ this(uri + ": " + s, cause);
+ }
+
+ /**
* Constructs an TransportException with the specified detail message.
*
* @param s
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 21/23] Don't accept RefSpec with null source for fetch
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-21-git-send-email-marek.zawirski@gmail.com>
RefSpec with null source has no sense, so let's inform about it.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../org/spearce/jgit/transport/FetchProcess.java | 4 ++++
.../src/org/spearce/jgit/transport/Transport.java | 5 +++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
index c765c12..f9c2266 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/FetchProcess.java
@@ -100,6 +100,10 @@ class FetchProcess {
result.setAdvertisedRefs(conn.getRefsMap());
final Set<Ref> matched = new HashSet<Ref>();
for (final RefSpec spec : toFetch) {
+ if (spec.getSource() == null)
+ throw new TransportException(
+ "Source ref not specified for refspec: " + spec);
+
if (spec.isWildcard())
expandWildcard(spec, matched);
else
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
index da5b41e..8260da6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
@@ -363,14 +363,15 @@ public abstract class Transport {
* @param toFetch
* specification of refs to fetch locally. May be null or the
* empty collection to use the specifications from the
- * RemoteConfig.
+ * RemoteConfig. Source for each RefSpec can't be null.
* @return information describing the tracking refs updated.
* @throws NotSupportedException
* this transport implementation does not support fetching
* objects.
* @throws TransportException
* the remote connection could not be established or object
- * copying (if necessary) failed.
+ * copying (if necessary) failed or update specification was
+ * incorrect.
*/
public FetchResult fetch(final ProgressMonitor monitor,
Collection<RefSpec> toFetch) throws NotSupportedException,
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 19/23] Repository search for command line tools
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-19-git-send-email-marek.zawirski@gmail.com>
Introducing some simple search for git repository in parent directories
of current directory.
Previous version was annoying: we had to be in directory that contains
.git/ or specify it explicitly by --git-dir.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/pgm/Main.java | 24 +++++++++++++++++--
1 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java
index 44f8a42..8afd0d7 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Main.java
@@ -85,12 +85,12 @@ public class Main {
private static void execute(final String[] argv) throws Exception {
int argi = 0;
- String gitdir = ".git";
+ File gitdir = null;
for (; argi < argv.length; argi++) {
final String arg = argv[argi];
if (arg.startsWith("--git-dir="))
- gitdir = arg.substring("--git-dir=".length());
+ gitdir = new File(arg.substring("--git-dir=".length()));
else if (arg.equals("--show-stack-trace"))
showStackTrace = true;
else if (arg.startsWith("--"))
@@ -101,8 +101,15 @@ public class Main {
if (argi == argv.length)
usage();
+ if (gitdir == null)
+ gitdir = findGitDir();
+ if (gitdir == null || !gitdir.isDirectory()) {
+ System.err.println("error: can't find git directory");
+ System.exit(1);
+ }
+
final TextBuiltin cmd = createCommand(argv[argi++]);
- cmd.db = new Repository(new File(gitdir));
+ cmd.db = new Repository(gitdir);
try {
cmd.execute(subarray(argv, argi));
} finally {
@@ -111,6 +118,17 @@ public class Main {
}
}
+ private static File findGitDir() {
+ File current = new File(".").getAbsoluteFile();
+ while (current != null) {
+ final File gitDir = new File(current, ".git");
+ if (gitDir.isDirectory())
+ return gitDir;
+ current = current.getParentFile();
+ }
+ return null;
+ }
+
private static String[] subarray(final String[] argv, final int i) {
return Arrays.asList(argv).subList(i, argv.length).toArray(
new String[0]);
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 20/23] Push command line utility
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-20-git-send-email-marek.zawirski@gmail.com>
pgm.Push class providing command line push utility, similar to C Git
one.
Some shared abbreviating methods for both Fetch and Push are moved to
TextBuiltin.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/pgm/Fetch.java | 36 +---
.../src/org/spearce/jgit/pgm/Push.java | 235 ++++++++++++++++++++
.../src/org/spearce/jgit/pgm/TextBuiltin.java | 21 ++
3 files changed, 262 insertions(+), 30 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java
index 3a81575..c9c997e 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Fetch.java
@@ -40,8 +40,6 @@ package org.spearce.jgit.pgm;
import java.util.ArrayList;
import java.util.List;
-import org.spearce.jgit.lib.Constants;
-import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.RefUpdate;
import org.spearce.jgit.lib.TextProgressMonitor;
import org.spearce.jgit.transport.FetchResult;
@@ -50,12 +48,6 @@ import org.spearce.jgit.transport.TrackingRefUpdate;
import org.spearce.jgit.transport.Transport;
class Fetch extends TextBuiltin {
- private static final String REFS_HEADS = Constants.HEADS_PREFIX + "/";
-
- private static final String REFS_REMOTES = Constants.REMOTES_PREFIX + "/";
-
- private static final String REFS_TAGS = Constants.TAGS_PREFIX + "/";
-
@Override
void execute(String[] args) throws Exception {
int argi = 0;
@@ -84,20 +76,8 @@ class Fetch extends TextBuiltin {
for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
final char type = shortTypeOf(u.getResult());
final String longType = longTypeOf(u);
-
- String src = u.getRemoteName();
- if (src.startsWith(REFS_HEADS))
- src = src.substring(REFS_HEADS.length());
- else if (src.startsWith(REFS_TAGS))
- src = src.substring(REFS_TAGS.length());
-
- String dst = u.getLocalName();
- if (dst.startsWith(REFS_HEADS))
- dst = dst.substring(REFS_HEADS.length());
- else if (dst.startsWith(REFS_TAGS))
- dst = dst.substring(REFS_TAGS.length());
- else if (dst.startsWith(REFS_REMOTES))
- dst = dst.substring(REFS_REMOTES.length());
+ final String src = abbreviateRef(u.getRemoteName(), false);
+ final String dst = abbreviateRef(u.getLocalName(), true);
out.format(" %c %-17s %-10s -> %s", type, longType, src, dst);
out.println();
@@ -121,14 +101,14 @@ class Fetch extends TextBuiltin {
}
if (r == RefUpdate.Result.FORCED) {
- final String aOld = abbreviate(u.getOldObjectId());
- final String aNew = abbreviate(u.getNewObjectId());
+ final String aOld = abbreviateObject(u.getOldObjectId());
+ final String aNew = abbreviateObject(u.getNewObjectId());
return aOld + "..." + aNew;
}
if (r == RefUpdate.Result.FAST_FORWARD) {
- final String aOld = abbreviate(u.getOldObjectId());
- final String aNew = abbreviate(u.getNewObjectId());
+ final String aOld = abbreviateObject(u.getOldObjectId());
+ final String aNew = abbreviateObject(u.getNewObjectId());
return aOld + ".." + aNew;
}
@@ -139,10 +119,6 @@ class Fetch extends TextBuiltin {
return "[" + r.name() + "]";
}
- private static String abbreviate(final ObjectId id) {
- return id.toString().substring(0, 7);
- }
-
private static char shortTypeOf(final RefUpdate.Result r) {
if (r == RefUpdate.Result.LOCK_FAILURE)
return '!';
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java
new file mode 100644
index 0000000..4130bc9
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/Push.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.lib.TextProgressMonitor;
+import org.spearce.jgit.transport.PushResult;
+import org.spearce.jgit.transport.RefSpec;
+import org.spearce.jgit.transport.RemoteRefUpdate;
+import org.spearce.jgit.transport.Transport;
+import org.spearce.jgit.transport.RemoteRefUpdate.Status;
+
+class Push extends TextBuiltin {
+
+ private boolean verbose = false;
+
+ private Transport transport;
+
+ private boolean first = true;
+
+ @Override
+ void execute(String[] args) throws Exception {
+ final LinkedList<RefSpec> refSpecs = new LinkedList<RefSpec>();
+ Boolean thin = null;
+ String exec = null;
+ boolean forceAll = false;
+
+ int argi = 0;
+ for (; argi < args.length; argi++) {
+ final String a = args[argi];
+ if ("--thin".equals(a))
+ thin = true;
+ else if ("--no-thin".equals(a))
+ thin = false;
+ else if ("-f".equals(a) || "--force".equals(a))
+ forceAll = true;
+ else if (a.startsWith("--exec="))
+ exec = a.substring("--exec=".length());
+ else if (a.startsWith("--receive-pack="))
+ exec = a.substring("--receive-pack=".length());
+ else if ("--tags".equals(a))
+ refSpecs.add(Transport.REFSPEC_TAGS);
+ else if ("--all".equals(a))
+ refSpecs.add(Transport.REFSPEC_PUSH_ALL);
+ else if ("-v".equals(a))
+ verbose = true;
+ else if ("--".equals(a)) {
+ argi++;
+ break;
+ } else if (a.startsWith("-"))
+ die("usage: push [--all] [--tags] [--force] [--thin]\n"
+ + "[--receive-pack=<git-receive-pack>] [<repository> [<refspec>]...]");
+ else
+ break;
+ }
+
+ final String repository;
+ if (argi == args.length)
+ repository = "origin";
+ else
+ repository = args[argi++];
+ transport = Transport.open(db, repository);
+ if (thin != null)
+ transport.setPushThin(thin);
+ if (exec != null)
+ transport.setOptionReceivePack(exec);
+
+ for (; argi < args.length; argi++) {
+ final RefSpec spec = new RefSpec(args[argi]);
+ if (forceAll)
+ spec.setForceUpdate(true);
+ refSpecs.add(spec);
+ }
+ final Collection<RemoteRefUpdate> toPush = transport
+ .findRemoteRefUpdatesFor(refSpecs);
+
+ final PushResult result = transport.push(new TextProgressMonitor(),
+ toPush);
+ printPushResult(result);
+ }
+
+ private void printPushResult(final PushResult result) {
+ boolean everythingUpToDate = true;
+ // at first, print up-to-date ones...
+ for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
+ if (rru.getStatus() == Status.UP_TO_DATE) {
+ if (verbose)
+ printRefUpdateResult(result, rru);
+ } else
+ everythingUpToDate = false;
+ }
+
+ for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
+ // ...then successful updates...
+ if (rru.getStatus() == Status.OK)
+ printRefUpdateResult(result, rru);
+ }
+
+ for (final RemoteRefUpdate rru : result.getRemoteUpdates()) {
+ // ...finally, others (problematic)
+ if (rru.getStatus() != Status.OK
+ && rru.getStatus() != Status.UP_TO_DATE)
+ printRefUpdateResult(result, rru);
+ }
+
+ if (everythingUpToDate)
+ out.println("Everything up-to-date");
+ }
+
+ private void printRefUpdateResult(final PushResult result,
+ final RemoteRefUpdate rru) {
+ if (first) {
+ first = false;
+ out.format("To %s\n", transport.getURI());
+ }
+
+ final String remoteName = rru.getRemoteName();
+ final String srcRef = rru.isDelete() ? null : rru.getSrcRef();
+
+ switch (rru.getStatus()) {
+ case OK:
+ if (rru.isDelete())
+ printUpdateLine('-', "[deleted]", null, remoteName, null);
+ else {
+ final Ref oldRef = result.getAdvertisedRef(remoteName);
+ if (oldRef == null) {
+ final String summary;
+ if (remoteName.startsWith(REFS_TAGS))
+ summary = "[new tag]";
+ else
+ summary = "[new branch]";
+ printUpdateLine('*', summary, srcRef, remoteName, null);
+ } else {
+ boolean fastForward = rru.isFastForward();
+ final char flag = fastForward ? ' ' : '+';
+ final String summary = abbreviateObject(oldRef
+ .getObjectId())
+ + (fastForward ? ".." : "...")
+ + abbreviateObject(rru.getNewObjectId());
+ final String message = fastForward ? null : "forced update";
+ printUpdateLine(flag, summary, srcRef, remoteName, message);
+ }
+ }
+ break;
+
+ case NON_EXISTING:
+ printUpdateLine('X', "[no match]", null, remoteName, null);
+ break;
+
+ case REJECTED_NODELETE:
+ printUpdateLine('!', "[rejected]", null, remoteName,
+ "remote side does not support deleting refs");
+ break;
+
+ case REJECTED_NONFASTFORWARD:
+ printUpdateLine('!', "[rejected]", srcRef, remoteName,
+ "non-fast forward");
+ break;
+
+ case REJECTED_REMOTE_CHANGED:
+ final String message = "remote ref object changed - is not expected one "
+ + abbreviateObject(rru.getExpectedOldObjectId());
+ printUpdateLine('!', "[rejected]", srcRef, remoteName, message);
+ break;
+
+ case REJECTED_OTHER_REASON:
+ printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru
+ .getMessage());
+ break;
+
+ case UP_TO_DATE:
+ if (verbose)
+ printUpdateLine('=', "[up to date]", srcRef, remoteName, null);
+ break;
+
+ case NOT_ATTEMPTED:
+ case AWAITING_REPORT:
+ printUpdateLine('?', "[unexpected push-process behavior]", srcRef,
+ remoteName, rru.getMessage());
+ break;
+ }
+ }
+
+ private void printUpdateLine(final char flag, final String summary,
+ final String srcRef, final String destRef, final String message) {
+ out.format(" %c %-17s", flag, summary);
+
+ if (srcRef != null)
+ out.format(" %s ->", abbreviateRef(srcRef, true));
+ out.format(" %s", abbreviateRef(destRef, true));
+
+ if (message != null)
+ out.format(" (%s)", message);
+
+ out.println();
+ }
+}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java b/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java
index 163f795..b3d8f39 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/pgm/TextBuiltin.java
@@ -43,10 +43,17 @@ import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import org.spearce.jgit.lib.Constants;
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.Repository;
abstract class TextBuiltin {
+ protected static final String REFS_HEADS = Constants.HEADS_PREFIX + "/";
+
+ protected static final String REFS_REMOTES = Constants.REMOTES_PREFIX + "/";
+
+ protected static final String REFS_TAGS = Constants.TAGS_PREFIX + "/";
+
protected PrintWriter out;
protected Repository db;
@@ -72,4 +79,18 @@ abstract class TextBuiltin {
protected static Die die(final String why) {
return new Die(why);
}
+
+ protected static String abbreviateObject(final ObjectId id) {
+ return id.toString().substring(0, 7);
+ }
+
+ protected String abbreviateRef(String dst, boolean abbreviateRemote) {
+ if (dst.startsWith(REFS_HEADS))
+ dst = dst.substring(REFS_HEADS.length());
+ else if (dst.startsWith(REFS_TAGS))
+ dst = dst.substring(REFS_TAGS.length());
+ else if (abbreviateRemote && dst.startsWith(REFS_REMOTES))
+ dst = dst.substring(REFS_REMOTES.length());
+ return dst;
+ }
}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 18/23] Test cases for RefSpec to RemoteRefUpdate conversions
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-18-git-send-email-marek.zawirski@gmail.com>
Tests for method Transport#findRemoteRefUpdatesFor().
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../org/spearce/jgit/transport/TransportTest.java | 181 ++++++++++++++++++++
1 files changed, 181 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
new file mode 100644
index 0000000..47d738b
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/TransportTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.spearce.jgit.lib.RepositoryConfig;
+import org.spearce.jgit.lib.RepositoryTestCase;
+
+public class TransportTest extends RepositoryTestCase {
+ private Transport transport;
+
+ private RemoteConfig remoteConfig;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ final RepositoryConfig config = db.getConfig();
+ remoteConfig = new RemoteConfig(config, "test");
+ remoteConfig.addURI(new URIish("http://everyones.loves.git/u/2"));
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion with simple RefSpec - no
+ * wildcard, no tracking ref in repo configuration.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesNoWildcardNoTracking()
+ throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "refs/heads/master:refs/heads/x")));
+
+ assertEquals(1, result.size());
+ final RemoteRefUpdate rru = result.iterator().next();
+ assertNull(rru.getExpectedOldObjectId());
+ assertFalse(rru.isForceUpdate());
+ assertEquals("refs/heads/master", rru.getSrcRef());
+ assertEquals(db.resolve("refs/heads/master"), rru.getNewObjectId());
+ assertEquals("refs/heads/x", rru.getRemoteName());
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion with no-destination RefSpec
+ * (destination should be set up for the same name as source).
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesNoWildcardNoDestination()
+ throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "+refs/heads/master")));
+
+ assertEquals(1, result.size());
+ final RemoteRefUpdate rru = result.iterator().next();
+ assertNull(rru.getExpectedOldObjectId());
+ assertTrue(rru.isForceUpdate());
+ assertEquals("refs/heads/master", rru.getSrcRef());
+ assertEquals(db.resolve("refs/heads/master"), rru.getNewObjectId());
+ assertEquals("refs/heads/master", rru.getRemoteName());
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion with wildcard RefSpec.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "+refs/heads/*:refs/heads/test/*")));
+
+ assertEquals(7, result.size());
+ boolean foundA = false;
+ boolean foundB = false;
+ for (final RemoteRefUpdate rru : result) {
+ if ("refs/heads/a".equals(rru.getSrcRef())
+ && "refs/heads/test/a".equals(rru.getRemoteName()))
+ foundA = true;
+ if ("refs/heads/b".equals(rru.getSrcRef())
+ && "refs/heads/test/b".equals(rru.getRemoteName()))
+ foundB = true;
+ }
+ assertTrue(foundA);
+ assertTrue(foundB);
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion for more than one RefSpecs
+ * handling.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b");
+ final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d");
+ final Collection<RefSpec> specs = Arrays.asList(specA, specC);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(specs);
+
+ assertEquals(2, result.size());
+ boolean foundA = false;
+ boolean foundC = false;
+ for (final RemoteRefUpdate rru : result) {
+ if ("refs/heads/a".equals(rru.getSrcRef())
+ && "refs/heads/b".equals(rru.getRemoteName()))
+ foundA = true;
+ if ("refs/heads/c".equals(rru.getSrcRef())
+ && "refs/heads/d".equals(rru.getRemoteName()))
+ foundC = true;
+ }
+ assertTrue(foundA);
+ assertTrue(foundC);
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion for tracking ref search.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesTrackingRef() throws IOException {
+ remoteConfig.addFetchRefSpec(new RefSpec(
+ "refs/heads/*:refs/remotes/test/*"));
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "+refs/heads/a:refs/heads/a")));
+
+ assertEquals(1, result.size());
+ final TrackingRefUpdate tru = result.iterator().next()
+ .getTrackingRefUpdate();
+ assertEquals("refs/remotes/test/a", tru.getLocalName());
+ assertEquals("refs/heads/a", tru.getRemoteName());
+ assertEquals(db.resolve("refs/heads/a"), tru.getNewObjectId());
+ assertNull(tru.getOldObjectId());
+ }
+}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 16/23] Transport* - general support for push() and implementations
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-16-git-send-email-marek.zawirski@gmail.com>
Implementation of push() at abstract Transport class level and
implementations of concrete protocols: SSH, local, git-daemon.
Some Transport* implementations required refactoring to share code
between pack and fetch connections.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/transport/Transport.java | 184 +++++++++++++++++++-
.../spearce/jgit/transport/TransportBundle.java | 6 +
.../spearce/jgit/transport/TransportGitAnon.java | 39 ++++
.../spearce/jgit/transport/TransportGitSsh.java | 51 ++++++
.../org/spearce/jgit/transport/TransportLocal.java | 113 ++++++++----
.../org/spearce/jgit/transport/WalkTransport.java | 7 +
6 files changed, 361 insertions(+), 39 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
index c4b71eb..da5b41e 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/Transport.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
*
* All rights reserved.
*
@@ -42,12 +43,16 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import org.spearce.jgit.errors.NotSupportedException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.NullProgressMonitor;
import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
import org.spearce.jgit.lib.Repository;
/**
@@ -105,6 +110,8 @@ public abstract class Transport {
tn.setOptionUploadPack(cfg.getUploadPack());
tn.fetch = cfg.getFetchRefSpecs();
tn.tagopt = cfg.getTagOpt();
+ tn.setOptionReceivePack(cfg.getReceivePack());
+ tn.push = cfg.getPushRefSpecs();
return tn;
}
@@ -152,6 +159,20 @@ public abstract class Transport {
*/
public static final boolean DEFAULT_PUSH_THIN = false;
+ /**
+ * Specification for fetch or push operations, to fetch or push all tags.
+ * Acts as --tags.
+ */
+ public static final RefSpec REFSPEC_TAGS = new RefSpec(
+ "refs/tags/*:refs/tags/*");
+
+ /**
+ * Specification for push operation, to push all refs under refs/heads. Acts
+ * as --all.
+ */
+ public static final RefSpec REFSPEC_PUSH_ALL = new RefSpec(
+ "refs/heads/*:refs/heads/*");
+
/** The repository this transport fetches into, or pushes out of. */
protected final Repository local;
@@ -162,7 +183,7 @@ public abstract class Transport {
private String optionUploadPack = RemoteConfig.DEFAULT_UPLOAD_PACK;
/** Specifications to apply during fetch. */
- private List<RefSpec> fetch = Collections.<RefSpec> emptyList();
+ private List<RefSpec> fetch = Collections.emptyList();
/**
* How {@link #fetch(ProgressMonitor, Collection)} should handle tags.
@@ -178,6 +199,12 @@ public abstract class Transport {
/** Should fetch request thin-pack if remote repository can produce it. */
private boolean fetchThin = DEFAULT_FETCH_THIN;
+ /** Name of the receive pack program, if it must be executed. */
+ private String optionReceivePack = RemoteConfig.DEFAULT_RECEIVE_PACK;
+
+ /** Specifications to apply during push. */
+ private List<RefSpec> push = Collections.emptyList();
+
/** Should push produce thin-pack when sending objects to remote repository. */
private boolean pushThin = DEFAULT_PUSH_THIN;
@@ -274,6 +301,31 @@ public abstract class Transport {
}
/**
+ * Default setting is: {@value RemoteConfig#DEFAULT_RECEIVE_PACK}
+ *
+ * @return remote executable providing receive-pack service for pack
+ * transports.
+ * @see PackTransport
+ */
+ public String getOptionReceivePack() {
+ return optionReceivePack;
+ }
+
+ /**
+ * Set remote executable providing receive-pack service for pack transports.
+ * Default setting is: {@value RemoteConfig#DEFAULT_RECEIVE_PACK}
+ *
+ * @param optionReceivePack
+ * remote executable, if null or empty default one is set;
+ */
+ public void setOptionReceivePack(String optionReceivePack) {
+ if (optionReceivePack != null && optionReceivePack.length() > 0)
+ this.optionReceivePack = optionReceivePack;
+ else
+ this.optionReceivePack = RemoteConfig.DEFAULT_RECEIVE_PACK;
+ }
+
+ /**
* Default setting is: {@value #DEFAULT_PUSH_THIN}
*
* @return true if push should produce thin-pack in pack transports
@@ -356,6 +408,98 @@ public abstract class Transport {
}
/**
+ * Push objects and refs from the local repository to the remote one.
+ * <p>
+ * This is a utility function providing standard push behavior. It updates
+ * remote refs and send there necessary objects according to remote ref
+ * update specification. After successful remote ref update, associated
+ * locally stored tracking branch is updated if set up accordingly. Detailed
+ * operation result is provided after execution.
+ * <p>
+ * For setting up remote ref update specification from ref spec, see helper
+ * method {@link #findRemoteRefUpdatesFor(Collection)}, predefined refspecs ({@link #REFSPEC_TAGS},
+ * {@link #REFSPEC_PUSH_ALL}) or consider using directly
+ * {@link RemoteRefUpdate} for more possibilities.
+ *
+ * @see RemoteRefUpdate
+ *
+ * @param monitor
+ * progress monitor to inform the user about our processing
+ * activity. Must not be null. Use {@link NullProgressMonitor} if
+ * progress updates are not interesting or necessary.
+ * @param toPush
+ * specification of refs to push. May be null or the empty
+ * collection to use the specifications from the RemoteConfig
+ * converted by {@link #findRemoteRefUpdatesFor(Collection)}. No
+ * more than 1 RemoteRefUpdate with the same remoteName is
+ * allowed.
+ * @return information about results of remote refs updates, tracking refs
+ * updates and refs advertised by remote repository.
+ * @throws NotSupportedException
+ * this transport implementation does not support pusing
+ * objects.
+ * @throws TransportException
+ * the remote connection could not be established or object
+ * copying (if necessary) failed at I/O or protocol level or
+ * update specification was incorrect.
+ */
+ public PushResult push(final ProgressMonitor monitor,
+ Collection<RemoteRefUpdate> toPush) throws NotSupportedException,
+ TransportException {
+ if (toPush == null || toPush.isEmpty()) {
+ // If the caller did not ask for anything use the defaults.
+ toPush = findRemoteRefUpdatesFor(push);
+ if (toPush.isEmpty())
+ throw new TransportException("Nothing to push.");
+ }
+ final PushProcess pushProcess = new PushProcess(this, toPush);
+ return pushProcess.execute(monitor);
+ }
+
+ /**
+ * Convert push remote refs update specification from {@link RefSpec} form
+ * to {@link RemoteRefUpdate}. Conversion expands wildcards by matching
+ * source part to local refs. expectedOldObjectId in RemoteRefUpdate is
+ * always set as null. Tracking branch is configured if RefSpec destination
+ * matches source of any fetch ref spec for this transport remote
+ * configuration.
+ *
+ * @param specs
+ * collection of RefSpec to convert.
+ * @return collection of set up {@link RemoteRefUpdate}.
+ * @throws TransportException
+ * when problem occurred during conversion or specification set
+ * up: most probably, missing objects or refs.
+ */
+ public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
+ final Collection<RefSpec> specs) throws TransportException {
+ final List<RemoteRefUpdate> result = new LinkedList<RemoteRefUpdate>();
+ final Collection<RefSpec> procRefs = expandPushWildcardsFor(specs);
+
+ for (final RefSpec spec : procRefs) {
+ try {
+ final String srcRef = spec.getSource();
+ // null destination (no-colon in ref-spec) is a special case
+ final String remoteName = (spec.getDestination() == null ? spec
+ .getSource() : spec.getDestination());
+ final boolean forceUpdate = spec.isForceUpdate();
+ final String localName = findTrackingRefName(remoteName);
+
+ final RemoteRefUpdate rru = new RemoteRefUpdate(local, srcRef,
+ remoteName, forceUpdate, localName, null);
+ result.add(rru);
+ } catch (TransportException x) {
+ throw x;
+ } catch (Exception x) {
+ throw new TransportException(
+ "Problem with resolving push ref spec \"" + spec
+ + "\" locally: " + x.getMessage(), x);
+ }
+ }
+ return result;
+ }
+
+ /**
* Begins a new connection for fetching from the remote repository.
*
* @return a fresh connection to fetch from the remote repository.
@@ -373,9 +517,41 @@ public abstract class Transport {
* @return a fresh connection to push into the remote repository.
* @throws NotSupportedException
* the implementation does not support pushing.
+ * @throws TransportException
+ * the remote connection could not be established
*/
- public final PushConnection openPush() throws NotSupportedException
- /* TransportException */{
- throw new NotSupportedException("No push support.");
+ public abstract PushConnection openPush() throws NotSupportedException,
+ TransportException;
+
+ private Collection<RefSpec> expandPushWildcardsFor(
+ final Collection<RefSpec> specs) {
+ final Map<String, Ref> localRefs = local.getAllRefs();
+ final Collection<RefSpec> procRefs = new HashSet<RefSpec>();
+
+ for (final RefSpec spec : specs) {
+ if (spec.isWildcard()) {
+ for (final Ref localRef : localRefs.values()) {
+ if (spec.matchSource(localRef))
+ procRefs.add(spec.expandFromSource(localRef));
+ }
+ } else {
+ procRefs.add(spec);
+ }
+ }
+ return procRefs;
+ }
+
+ private String findTrackingRefName(final String remoteName) {
+ // try to find matching tracking refs
+ for (final RefSpec fetchSpec : fetch) {
+ if (fetchSpec.matchSource(remoteName)) {
+ if (fetchSpec.isWildcard())
+ return fetchSpec.expandFromSource(remoteName)
+ .getDestination();
+ else
+ return fetchSpec.getDestination();
+ }
+ }
+ return null;
}
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
index 48120a8..1bf081a 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportBundle.java
@@ -95,6 +95,12 @@ class TransportBundle extends PackTransport {
return new BundleFetchConnection();
}
+ @Override
+ public PushConnection openPush() throws NotSupportedException {
+ throw new NotSupportedException(
+ "Push is not supported for bundle transport");
+ }
+
class BundleFetchConnection extends BaseFetchConnection {
FileInputStream in;
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
index a7a419e..6e49083 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitAnon.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
*
* All rights reserved.
*
@@ -71,6 +72,11 @@ class TransportGitAnon extends PackTransport {
return new TcpFetchConnection();
}
+ @Override
+ public PushConnection openPush() throws TransportException {
+ return new TcpPushConnection();
+ }
+
Socket openConnection() throws TransportException {
final int port = uri.getPort() > 0 ? uri.getPort() : GIT_PORT;
try {
@@ -131,4 +137,37 @@ class TransportGitAnon extends PackTransport {
}
}
}
+
+ class TcpPushConnection extends BasePackPushConnection {
+ private Socket sock;
+
+ TcpPushConnection() throws TransportException {
+ super(TransportGitAnon.this);
+ sock = openConnection();
+ try {
+ init(sock.getInputStream(), sock.getOutputStream());
+ service("git-receive-pack", pckOut);
+ } catch (IOException err) {
+ close();
+ throw new TransportException(uri.toString()
+ + ": remote hung up unexpectedly", err);
+ }
+ readAdvertisedRefs();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (sock != null) {
+ try {
+ sock.close();
+ } catch (IOException err) {
+ // Ignore errors during close.
+ } finally {
+ sock = null;
+ }
+ }
+ }
+ }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
index f6e456a..55be4f6 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportGitSsh.java
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
*
* All rights reserved.
*
@@ -88,6 +89,11 @@ class TransportGitSsh extends PackTransport {
return new SshFetchConnection();
}
+ @Override
+ public PushConnection openPush() throws TransportException {
+ return new SshPushConnection();
+ }
+
private static void sqMinimal(final StringBuilder cmd, final String val) {
if (val.matches("^[a-zA-Z0-9._/-]*$")) {
// If the string matches only generally safe characters
@@ -232,4 +238,49 @@ class TransportGitSsh extends PackTransport {
}
}
}
+
+ class SshPushConnection extends BasePackPushConnection {
+ private Session session;
+
+ private ChannelExec channel;
+
+ SshPushConnection() throws TransportException {
+ super(TransportGitSsh.this);
+ try {
+ session = openSession();
+ channel = exec(session, getOptionReceivePack());
+ init(channel.getInputStream(), channel.getOutputStream());
+ } catch (TransportException err) {
+ close();
+ throw err;
+ } catch (IOException err) {
+ close();
+ throw new TransportException(uri.toString()
+ + ": remote hung up unexpectedly", err);
+ }
+ readAdvertisedRefs();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (channel != null) {
+ try {
+ if (channel.isConnected())
+ channel.disconnect();
+ } finally {
+ channel = null;
+ }
+ }
+
+ if (session != null) {
+ try {
+ sch.releaseSession(session);
+ } finally {
+ session = null;
+ }
+ }
+ }
+ }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
index e109cf4..f48dc6d 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
@@ -2,6 +2,7 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
*
* All rights reserved.
*
@@ -43,6 +44,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import org.spearce.jgit.errors.NotSupportedException;
import org.spearce.jgit.errors.TransportException;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.util.FS;
@@ -83,50 +85,35 @@ class TransportLocal extends PackTransport {
return new LocalFetchConnection();
}
+ @Override
+ public PushConnection openPush() throws NotSupportedException,
+ TransportException {
+ return new LocalPushConnection();
+ }
+
+ protected Process startProcessWithErrStream(final String cmd)
+ throws TransportException {
+ try {
+ final Process proc = Runtime.getRuntime().exec(
+ new String[] { cmd, "." }, null, remoteGitDir);
+ new StreamRewritingThread(proc.getErrorStream()).start();
+ return proc;
+ } catch (IOException err) {
+ throw new TransportException(uri.toString() + ": "
+ + err.getMessage(), err);
+ }
+ }
+
class LocalFetchConnection extends BasePackFetchConnection {
private Process uploadPack;
LocalFetchConnection() throws TransportException {
super(TransportLocal.this);
- try {
- uploadPack = Runtime.getRuntime().exec(
- new String[] { getOptionUploadPack(), "." }, null,
- remoteGitDir);
- } catch (IOException err) {
- throw new TransportException(uri.toString() + ": "
- + err.getMessage(), err);
- }
- startErrorThread();
+ uploadPack = startProcessWithErrStream(getOptionReceivePack());
init(uploadPack.getInputStream(), uploadPack.getOutputStream());
readAdvertisedRefs();
}
- private void startErrorThread() {
- final InputStream errorStream = uploadPack.getErrorStream();
- new Thread("JGit " + getOptionUploadPack() + " Errors") {
- public void run() {
- final byte[] tmp = new byte[512];
- try {
- for (;;) {
- final int n = errorStream.read(tmp);
- if (n < 0)
- break;
- System.err.write(tmp, 0, n);
- System.err.flush();
- }
- } catch (IOException err) {
- // Ignore errors reading errors.
- } finally {
- try {
- errorStream.close();
- } catch (IOException err2) {
- // Ignore errors closing the pipe.
- }
- }
- }
- }.start();
- }
-
@Override
public void close() {
super.close();
@@ -142,4 +129,60 @@ class TransportLocal extends PackTransport {
}
}
}
+
+ class LocalPushConnection extends BasePackPushConnection {
+ private Process receivePack;
+
+ LocalPushConnection() throws TransportException {
+ super(TransportLocal.this);
+ receivePack = startProcessWithErrStream(getOptionReceivePack());
+ init(receivePack.getInputStream(), receivePack.getOutputStream());
+ readAdvertisedRefs();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (receivePack != null) {
+ try {
+ receivePack.waitFor();
+ } catch (InterruptedException ie) {
+ // Stop waiting and return anyway.
+ } finally {
+ receivePack = null;
+ }
+ }
+ }
+ }
+
+ class StreamRewritingThread extends Thread {
+ private final InputStream in;
+
+ StreamRewritingThread(final InputStream in) {
+ super("JGit " + getOptionUploadPack() + " Errors");
+ this.in = in;
+ }
+
+ public void run() {
+ final byte[] tmp = new byte[512];
+ try {
+ for (;;) {
+ final int n = in.read(tmp);
+ if (n < 0)
+ break;
+ System.err.write(tmp, 0, n);
+ System.err.flush();
+ }
+ } catch (IOException err) {
+ // Ignore errors reading errors.
+ } finally {
+ try {
+ in.close();
+ } catch (IOException err2) {
+ // Ignore errors closing the pipe.
+ }
+ }
+ }
+ }
}
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java
index ae51d6d..29dd661 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/WalkTransport.java
@@ -37,6 +37,7 @@
package org.spearce.jgit.transport;
+import org.spearce.jgit.errors.NotSupportedException;
import org.spearce.jgit.lib.Repository;
/**
@@ -55,4 +56,10 @@ abstract class WalkTransport extends Transport {
WalkTransport(final Repository local, final URIish u) {
super(local, u);
}
+
+ @Override
+ public PushConnection openPush() throws NotSupportedException {
+ throw new NotSupportedException(
+ "Push is not supported by object walking transports");
+ }
}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 17/23] Test cases for PushProcess
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-17-git-send-email-marek.zawirski@gmail.com>
Tests for push process with highly differentiated remote update cases,
that are possible in practice.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../spearce/jgit/transport/PushProcessTest.java | 407 ++++++++++++++++++++
1 files changed, 407 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java
diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java
new file mode 100644
index 0000000..f0cfe98
--- /dev/null
+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/transport/PushProcessTest.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.spearce.jgit.errors.NotSupportedException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.RepositoryTestCase;
+import org.spearce.jgit.lib.TextProgressMonitor;
+import org.spearce.jgit.lib.RefUpdate.Result;
+import org.spearce.jgit.transport.RemoteRefUpdate.Status;
+
+public class PushProcessTest extends RepositoryTestCase {
+ private PushProcess process;
+
+ private MockTransport transport;
+
+ private HashSet<RemoteRefUpdate> refUpdates;
+
+ private HashSet<Ref> advertisedRefs;
+
+ private Status connectionUpdateStatus;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ transport = new MockTransport(db, new URIish());
+ refUpdates = new HashSet<RemoteRefUpdate>();
+ advertisedRefs = new HashSet<Ref>();
+ connectionUpdateStatus = Status.OK;
+ }
+
+ /**
+ * Test for fast-forward remote update.
+ *
+ * @throws IOException
+ */
+ public void testUpdateFastForward() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.OK, true);
+ }
+
+ /**
+ * Test for non fast-forward remote update, when remote object is not known
+ * to local repository.
+ *
+ * @throws IOException
+ */
+ public void testUpdateNonFastForwardUnknownObject() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("0000000000000000000000000000000000000001"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);
+ }
+
+ /**
+ * Test for non fast-forward remote update, when remote object is known to
+ * local repository, but it is not an ancestor of new object.
+ *
+ * @throws IOException
+ */
+ public void testUpdateNonFastForward() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);
+ }
+
+ /**
+ * Test for non fast-forward remote update, when force update flag is set.
+ *
+ * @throws IOException
+ */
+ public void testUpdateNonFastForwardForced() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", true, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.OK, false);
+ }
+
+ /**
+ * Test for remote ref creation.
+ *
+ * @throws IOException
+ */
+ public void testUpdateCreateRef() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", false, null, null);
+ testOneUpdateStatus(rru, null, Status.OK, true);
+ }
+
+ /**
+ * Test for remote ref deletion.
+ *
+ * @throws IOException
+ */
+ public void testUpdateDelete() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db, null,
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.OK, true);
+ }
+
+ /**
+ * Test for remote ref deletion (try), when that ref doesn't exist on remote
+ * repo.
+ *
+ * @throws IOException
+ */
+ public void testUpdateDeleteNonExisting() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db, null,
+ "refs/heads/master", false, null, null);
+ testOneUpdateStatus(rru, null, Status.NON_EXISTING, null);
+ }
+
+ /**
+ * Test for remote ref update, when it is already up to date.
+ *
+ * @throws IOException
+ */
+ public void testUpdateUpToDate() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.UP_TO_DATE, null);
+ }
+
+ /**
+ * Test for remote ref update with expected remote object.
+ *
+ * @throws IOException
+ */
+ public void testUpdateExpectedRemote() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.OK, true);
+ }
+
+ /**
+ * Test for remote ref update with expected old object set, when old object
+ * is not that expected one.
+ *
+ * @throws IOException
+ */
+ public void testUpdateUnexpectedRemote() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, ObjectId
+ .fromString("0000000000000000000000000000000000000001"));
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
+ }
+
+ /**
+ * Test for remote ref update with expected old object set, when old object
+ * is not that expected one and force update flag is set (which should have
+ * lower priority) - shouldn't change behavior.
+ *
+ * @throws IOException
+ */
+ public void testUpdateUnexpectedRemoteVsForce() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", true, null, ObjectId
+ .fromString("0000000000000000000000000000000000000001"));
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
+ }
+
+ /**
+ * Test for remote ref udpate, when connection rejects update.
+ *
+ * @throws IOException
+ */
+ public void testUpdateRejectedByConnection() throws IOException {
+ connectionUpdateStatus = Status.REJECTED_OTHER_REASON;
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_OTHER_REASON, null);
+ }
+
+ /**
+ * Test for remote refs updates with mixed cases that shouldn't depend on
+ * each other.
+ *
+ * @throws IOException
+ */
+ public void testUpdateMixedCases() throws IOException {
+ final RemoteRefUpdate rruOk = new RemoteRefUpdate(db, null,
+ "refs/heads/master", false, null, null);
+ final Ref refToChange = new Ref("refs/heads/master", ObjectId
+ .fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ final RemoteRefUpdate rruReject = new RemoteRefUpdate(db, null,
+ "refs/heads/nonexisting", false, null, null);
+ refUpdates.add(rruOk);
+ refUpdates.add(rruReject);
+ advertisedRefs.add(refToChange);
+ executePush();
+ assertEquals(Status.OK, rruOk.getStatus());
+ assertEquals(true, rruOk.isFastForward());
+ assertEquals(Status.NON_EXISTING, rruReject.getStatus());
+ }
+
+ /**
+ * Test for local tracking ref update.
+ *
+ * @throws IOException
+ */
+ public void testTrackingRefUpdateEnabled() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, "refs/remotes/test/master", null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ refUpdates.add(rru);
+ advertisedRefs.add(ref);
+ final PushResult result = executePush();
+ final TrackingRefUpdate tru = result
+ .getTrackingRefUpdate("refs/remotes/test/master");
+ assertNotNull(tru);
+ assertEquals("refs/remotes/test/master", tru.getLocalName());
+ assertEquals(Result.NEW, tru.getResult());
+ }
+
+ /**
+ * Test for local tracking ref update disabled.
+ *
+ * @throws IOException
+ */
+ public void testTrackingRefUpdateDisabled() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ refUpdates.add(rru);
+ advertisedRefs.add(ref);
+ final PushResult result = executePush();
+ assertTrue(result.getTrackingRefUpdates().isEmpty());
+ }
+
+ /**
+ * Test for local tracking ref update when remote update has failed.
+ *
+ * @throws IOException
+ */
+ public void testTrackingRefUpdateOnReject() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ final PushResult result = testOneUpdateStatus(rru, ref,
+ Status.REJECTED_NONFASTFORWARD, null);
+ assertTrue(result.getTrackingRefUpdates().isEmpty());
+ }
+
+ /**
+ * Test for push operation result - that contains expected elements.
+ *
+ * @throws IOException
+ */
+ public void testPushResult() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, "refs/remotes/test/master", null);
+ final Ref ref = new Ref("refs/heads/master", ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ refUpdates.add(rru);
+ advertisedRefs.add(ref);
+ final PushResult result = executePush();
+ assertEquals(1, result.getTrackingRefUpdates().size());
+ assertEquals(1, result.getAdvertisedRefs().size());
+ assertEquals(1, result.getRemoteUpdates().size());
+ assertNotNull(result.getTrackingRefUpdate("refs/remotes/test/master"));
+ assertNotNull(result.getAdvertisedRef("refs/heads/master"));
+ assertNotNull(result.getRemoteUpdate("refs/heads/master"));
+ }
+
+ private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
+ final Ref advertisedRef, final Status expectedStatus,
+ Boolean fastForward) throws NotSupportedException,
+ TransportException {
+ refUpdates.add(rru);
+ if (advertisedRef != null)
+ advertisedRefs.add(advertisedRef);
+ final PushResult result = executePush();
+ assertEquals(expectedStatus, rru.getStatus());
+ if (fastForward != null)
+ assertEquals(fastForward.booleanValue(), rru.isFastForward());
+ return result;
+ }
+
+ private PushResult executePush() throws NotSupportedException,
+ TransportException {
+ process = new PushProcess(transport, refUpdates);
+ return process.execute(new TextProgressMonitor());
+ }
+
+ private class MockTransport extends Transport {
+ MockTransport(Repository local, URIish uri) {
+ super(local, uri);
+ }
+
+ @Override
+ public FetchConnection openFetch() throws NotSupportedException,
+ TransportException {
+ throw new NotSupportedException("mock");
+ }
+
+ @Override
+ public PushConnection openPush() throws NotSupportedException,
+ TransportException {
+ return new MockPushConnection();
+ }
+ }
+
+ private class MockPushConnection extends BaseConnection implements
+ PushConnection {
+ MockPushConnection() {
+ final Map<String, Ref> refsMap = new HashMap<String, Ref>();
+ for (final Ref r : advertisedRefs)
+ refsMap.put(r.getName(), r);
+ available(refsMap);
+ }
+
+ @Override
+ public void close() {
+ // nothing here
+ }
+
+ public void push(ProgressMonitor monitor,
+ Map<String, RemoteRefUpdate> refUpdates)
+ throws TransportException {
+ for (final RemoteRefUpdate rru : refUpdates.values()) {
+ assertEquals(Status.NOT_ATTEMPTED, rru.getStatus());
+ rru.setStatus(connectionUpdateStatus);
+ }
+ }
+ }
+}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 15/23] Add String versions of methods in RefSpec
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-15-git-send-email-marek.zawirski@gmail.com>
matchDestination(), matchSource(), expandFromSourec() can take String
as parameter now, not only Ref (we just need a ref name).
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/transport/RefSpec.java | 46 +++++++++++++++++--
1 files changed, 41 insertions(+), 5 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java b/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java
index 38489be..1589e19 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/RefSpec.java
@@ -281,6 +281,17 @@ public class RefSpec {
}
/**
+ * Does this specification's source description match the ref name?
+ *
+ * @param r
+ * ref name that should be tested.
+ * @return true if the names match; false otherwise.
+ */
+ public boolean matchSource(final String r) {
+ return match(r, getSource());
+ }
+
+ /**
* Does this specification's source description match the ref?
*
* @param r
@@ -288,7 +299,18 @@ public class RefSpec {
* @return true if the names match; false otherwise.
*/
public boolean matchSource(final Ref r) {
- return match(r, getSource());
+ return match(r.getName(), getSource());
+ }
+
+ /**
+ * Does this specification's destination description match the ref name?
+ *
+ * @param r
+ * ref name that should be tested.
+ * @return true if the names match; false otherwise.
+ */
+ public boolean matchDestination(final String r) {
+ return match(r, getDestination());
}
/**
@@ -299,7 +321,21 @@ public class RefSpec {
* @return true if the names match; false otherwise.
*/
public boolean matchDestination(final Ref r) {
- return match(r, getDestination());
+ return match(r.getName(), getDestination());
+ }
+
+ /**
+ * Expand this specification to exactly match a ref name.
+ * <p>
+ * Callers must first verify the passed ref name matches this specification,
+ * otherwise expansion results may be unpredictable.
+ *
+ * @param r
+ * a ref name that matched our source specification.
+ * @return a new specification that is not a wildcard.
+ */
+ public RefSpec expandFromSource(final String r) {
+ return isWildcard() ? new RefSpec(this, r) : this;
}
/**
@@ -316,12 +352,12 @@ public class RefSpec {
return isWildcard() ? new RefSpec(this, r.getName()) : this;
}
- private boolean match(final Ref r, final String s) {
+ private boolean match(final String refName, final String s) {
if (s == null)
return false;
if (isWildcard())
- return r.getName().startsWith(s.substring(0, s.length() - 1));
- return r.getName().equals(s);
+ return refName.startsWith(s.substring(0, s.length() - 1));
+ return refName.equals(s);
}
public int hashCode() {
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 14/23] Clarify Repository#resolve() documentation
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-14-git-send-email-marek.zawirski@gmail.com>
Say explicitly that this method returns null when revstr can't be
resolved.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/lib/Repository.java | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
index 64f93ff..2b43b2c 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/Repository.java
@@ -524,7 +524,7 @@ public class Repository {
* </ul>
*
* @param revstr A git object references expression
- * @return an ObjectId
+ * @return an ObjectId or null if revstr can't be resolved to any ObjectId
* @throws IOException on serious errors
*/
public ObjectId resolve(final String revstr) throws IOException {
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 13/23] Add PushProcess class implementing git-send-pack logic
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-13-git-send-email-marek.zawirski@gmail.com>
This class perform analogous operations as FetchProcess. It processes
refs advertised by connection, updates RemoteRefUpdates and
local tracking branches - TrackingRefUpdates.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../org/spearce/jgit/transport/PushProcess.java | 224 ++++++++++++++++++++
1 files changed, 224 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
new file mode 100644
index 0000000..f742949
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/PushProcess.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spearce.jgit.errors.MissingObjectException;
+import org.spearce.jgit.errors.NotSupportedException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.revwalk.RevObject;
+import org.spearce.jgit.revwalk.RevWalk;
+import org.spearce.jgit.transport.RemoteRefUpdate.Status;
+
+/**
+ * Class performing push operation on remote repository.
+ *
+ * @see Transport#push(ProgressMonitor, Collection)
+ */
+class PushProcess {
+ /** Task name for {@link ProgressMonitor} used during opening connection. */
+ static final String PROGRESS_OPENING_CONNECTION = "Opening connection";
+
+ /** Transport used to perform this operation. */
+ private final Transport transport;
+
+ /** Push operation connection created to perform this operation */
+ private PushConnection connection;
+
+ /** Refs to update on remote side. */
+ private final Map<String, RemoteRefUpdate> toPush;
+
+ /** Revision walker for checking some updates properties. */
+ private final RevWalk walker;
+
+ /**
+ * Create process for specified transport and refs updates specification.
+ *
+ * @param transport
+ * transport between remote and local repository, used to create
+ * connection.
+ * @param toPush
+ * specification of refs updates (and local tracking branches).
+ * @throws TransportException
+ */
+ PushProcess(final Transport transport,
+ final Collection<RemoteRefUpdate> toPush) throws TransportException {
+ this.walker = new RevWalk(transport.local);
+ this.transport = transport;
+ this.toPush = new HashMap<String, RemoteRefUpdate>();
+ for (final RemoteRefUpdate rru : toPush) {
+ if (this.toPush.put(rru.getRemoteName(), rru) != null)
+ throw new TransportException(
+ "Duplicate remote ref update is illegal. Affected remote name: "
+ + rru.getRemoteName());
+ }
+ }
+
+ /**
+ * Perform push operation between local and remote repository - set remote
+ * refs appropriately, send needed objects and update local tracking refs.
+ *
+ * @param monitor
+ * progress monitor used for feedback about operation.
+ * @return result of push operation with complete status description.
+ * @throws NotSupportedException
+ * when push operation is not supported by provided transport.
+ * @throws TransportException
+ * when some error occurred during operation, like I/O, protocol
+ * error, or local database consistency error.
+ */
+ PushResult execute(final ProgressMonitor monitor)
+ throws NotSupportedException, TransportException {
+ monitor.beginTask(PROGRESS_OPENING_CONNECTION, ProgressMonitor.UNKNOWN);
+ connection = transport.openPush();
+ try {
+ monitor.endTask();
+
+ final Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates();
+ if (!preprocessed.isEmpty())
+ connection.push(monitor, preprocessed);
+ } finally {
+ connection.close();
+ }
+ updateTrackingRefs();
+ return prepareOperationResult();
+ }
+
+ private Map<String, RemoteRefUpdate> prepareRemoteUpdates()
+ throws TransportException {
+ final Map<String, RemoteRefUpdate> result = new HashMap<String, RemoteRefUpdate>();
+ for (final RemoteRefUpdate rru : toPush.values()) {
+ final Ref advertisedRef = connection.getRef(rru.getRemoteName());
+ final ObjectId advertisedOld = (advertisedRef == null ? ObjectId
+ .zeroId() : advertisedRef.getObjectId());
+
+ if (rru.getNewObjectId().equals(advertisedOld)) {
+ if (rru.isDelete()) {
+ // ref does exist neither locally nor remotely
+ rru.setStatus(Status.NON_EXISTING);
+ } else {
+ // same object - nothing to do
+ rru.setStatus(Status.UP_TO_DATE);
+ }
+ continue;
+ }
+
+ // caller has explicitly specified expected old object id, while it
+ // has been changed in the mean time - reject
+ if (rru.isExpectingOldObjectId()
+ && !rru.getExpectedOldObjectId().equals(advertisedOld)) {
+ rru.setStatus(Status.REJECTED_REMOTE_CHANGED);
+ continue;
+ }
+
+ // create ref (hasn't existed on remote side) and delete ref
+ // are always fast-forward commands, feasible at this level
+ if (advertisedOld.equals(ObjectId.zeroId()) || rru.isDelete()) {
+ rru.setFastForward(true);
+ result.put(rru.getRemoteName(), rru);
+ continue;
+ }
+
+ // check for fast-forward:
+ // - both old and new ref must point to commits, AND
+ // - both of them must be known for us, exist in repository, AND
+ // - old commit must be ancestor of new commit
+ boolean fastForward = true;
+ try {
+ RevObject oldRev = walker.parseAny(advertisedOld);
+ final RevObject newRev = walker.parseAny(rru.getNewObjectId());
+ if (!(oldRev instanceof RevCommit)
+ || !(newRev instanceof RevCommit)
+ || !walker.isMergedInto((RevCommit) oldRev,
+ (RevCommit) newRev))
+ fastForward = false;
+ } catch (MissingObjectException x) {
+ fastForward = false;
+ } catch (Exception x) {
+ throw new TransportException(transport.getURI()
+ + ": reading objects from local repository failed: "
+ + x.getMessage(), x);
+ }
+ rru.setFastForward(fastForward);
+ if (!fastForward && !rru.isForceUpdate())
+ rru.setStatus(Status.REJECTED_NONFASTFORWARD);
+ else
+ result.put(rru.getRemoteName(), rru);
+ }
+ return result;
+ }
+
+ private void updateTrackingRefs() {
+ for (final RemoteRefUpdate rru : toPush.values()) {
+ final Status status = rru.getStatus();
+ if (rru.hasTrackingRefUpdate()
+ && (status == Status.UP_TO_DATE || status == Status.OK)) {
+ // update local tracking branch only when there is a chance that
+ // it has changed; this is possible for:
+ // -updated (OK) status,
+ // -up to date (UP_TO_DATE) status
+ try {
+ rru.updateTrackingRef(walker);
+ } catch (IOException e) {
+ // ignore as RefUpdate has stored I/O error status
+ }
+ }
+ }
+ }
+
+ private PushResult prepareOperationResult() {
+ final PushResult result = new PushResult();
+ result.setAdvertisedRefs(connection.getRefsMap());
+ result.setRemoteUpdates(toPush);
+
+ for (final RemoteRefUpdate rru : toPush.values()) {
+ final TrackingRefUpdate tru = rru.getTrackingRefUpdate();
+ if (tru != null)
+ result.add(tru);
+ }
+ return result;
+ }
+}
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 12/23] Fix: let RevWalk reset correctly before isMergedInto()
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-12-git-send-email-marek.zawirski@gmail.com>
Retained flags was wrongly computed for reset() call inside
isMergedInto().
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../src/org/spearce/jgit/revwalk/RevWalk.java | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java
index fc757a5..7976d75 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/revwalk/RevWalk.java
@@ -347,7 +347,7 @@ public class RevWalk implements Iterable<RevCommit> {
final TreeFilter oldTF = treeFilter;
try {
finishDelayedFreeFlags();
- reset(~freeFlags & ~RESERVED_FLAGS);
+ reset(~freeFlags & APP_FLAGS);
filter = RevFilter.MERGE_BASE;
treeFilter = TreeFilter.ALL;
markStart(tip);
--
1.5.5.3
^ permalink raw reply related
* [EGIT PATCH 11/23] Add BasePackPushConnection implementing git-send-pack protocol
From: Marek Zawirski @ 2008-06-27 22:06 UTC (permalink / raw)
To: robin.rosenberg, spearce; +Cc: git, Marek Zawirski
In-Reply-To: <1214604407-30572-11-git-send-email-marek.zawirski@gmail.com>
Implementation realies extensively on RemoteRefUpdate as input.
It supports report-status capability, and honors delete-refs one.
Signed-off-by: Marek Zawirski <marek.zawirski@gmail.com>
---
.../jgit/transport/BasePackPushConnection.java | 226 ++++++++++++++++++++
1 files changed, 226 insertions(+), 0 deletions(-)
create mode 100644 org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
new file mode 100644
index 0000000..159e331
--- /dev/null
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackPushConnection.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.transport;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.spearce.jgit.errors.PackProtocolException;
+import org.spearce.jgit.errors.TransportException;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.PackWriter;
+import org.spearce.jgit.lib.ProgressMonitor;
+import org.spearce.jgit.lib.Ref;
+import org.spearce.jgit.transport.RemoteRefUpdate.Status;
+
+/**
+ * Push implementation using the native Git pack transfer service.
+ * <p>
+ * This is the canonical implementation for transferring objects to the remote
+ * repository from the local repository by talking to the 'git-receive-pack'
+ * service. Objects are packed on the local side into a pack file and then sent
+ * to the remote repository.
+ * <p>
+ * This connection requires only a bi-directional pipe or socket, and thus is
+ * easily wrapped up into a local process pipe, anonymous TCP socket, or a
+ * command executed through an SSH tunnel.
+ * <p>
+ * This implementation honors {@link Transport#isPushThin()} option.
+ * <p>
+ * Concrete implementations should just call
+ * {@link #init(java.io.InputStream, java.io.OutputStream)} and
+ * {@link #readAdvertisedRefs()} methods in constructor or before any use. They
+ * should also handle resources releasing in {@link #close()} method if needed.
+ */
+class BasePackPushConnection extends BasePackConnection implements
+ PushConnection {
+ static final String CAPABILITY_REPORT_STATUS = "report-status";
+
+ static final String CAPABILITY_DELETE_REFS = "delete-refs";
+
+ private final boolean thinPack;
+
+ private boolean capableDeleteRefs;
+
+ private boolean capableReport;
+
+ private boolean sentCommand;
+
+ private boolean writePack;
+
+ BasePackPushConnection(final PackTransport transport) {
+ super(transport);
+ thinPack = transport.isPushThin();
+ }
+
+ public void push(final ProgressMonitor monitor,
+ final Map<String, RemoteRefUpdate> refUpdates)
+ throws TransportException {
+ markStartedOperation();
+ doPush(monitor, refUpdates);
+ }
+
+ protected void doPush(final ProgressMonitor monitor,
+ final Map<String, RemoteRefUpdate> refUpdates)
+ throws TransportException {
+ try {
+ writeCommands(refUpdates.values(), monitor);
+ if (writePack)
+ writePack(refUpdates, monitor);
+ if (sentCommand && capableReport)
+ readStatusReport(refUpdates);
+ } catch (TransportException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new TransportException(uri + ": " + e.getMessage(), e);
+ } finally {
+ close();
+ }
+ }
+
+ private void writeCommands(final Collection<RemoteRefUpdate> refUpdates,
+ final ProgressMonitor monitor) throws IOException {
+ final String capabilties = enableCapabilties();
+ for (final RemoteRefUpdate rru : refUpdates) {
+ if (!capableDeleteRefs && rru.isDelete()) {
+ rru.setStatus(Status.REJECTED_NODELETE);
+ continue;
+ }
+
+ final StringBuilder sb = new StringBuilder();
+ final Ref advertisedRef = getRef(rru.getRemoteName());
+ final ObjectId oldId = (advertisedRef == null ? ObjectId.zeroId()
+ : advertisedRef.getObjectId());
+ sb.append(oldId);
+ sb.append(' ');
+ sb.append(rru.getNewObjectId());
+ sb.append(' ');
+ sb.append(rru.getRemoteName());
+ if (!sentCommand) {
+ sentCommand = true;
+ sb.append(capabilties);
+ }
+
+ pckOut.writeString(sb.toString());
+ rru.setStatus(sentCommand ? Status.AWAITING_REPORT : Status.OK);
+ if (!rru.isDelete())
+ writePack = true;
+ }
+
+ if (monitor.isCancelled())
+ throw new TransportException(uri + ": push cancelled");
+ pckOut.end();
+ }
+
+ private String enableCapabilties() {
+ final StringBuilder line = new StringBuilder();
+ capableReport = wantCapability(line, CAPABILITY_REPORT_STATUS);
+ capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS);
+ if (line.length() > 0)
+ line.insert(0, '\0');
+ return line.toString();
+ }
+
+ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
+ final ProgressMonitor monitor) throws IOException {
+ final PackWriter writer = new PackWriter(local, out, monitor);
+ final ArrayList<ObjectId> remoteObjects = new ArrayList<ObjectId>(
+ getRefs().size());
+ final ArrayList<ObjectId> newObjects = new ArrayList<ObjectId>(
+ refUpdates.size());
+
+ for (final Ref r : getRefs())
+ remoteObjects.add(r.getObjectId());
+ for (final RemoteRefUpdate r : refUpdates.values())
+ newObjects.add(r.getNewObjectId());
+
+ writer.writePack(newObjects, remoteObjects, thinPack, true);
+ }
+
+ private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
+ throws IOException {
+ final String unpackLine = pckIn.readString();
+ if (!unpackLine.startsWith("unpack "))
+ throw new PackProtocolException(uri + ": unexpected report line: "
+ + unpackLine);
+ final String unpackStatus = unpackLine.substring("unpack ".length());
+ if (!unpackStatus.equals("ok"))
+ throw new TransportException(uri
+ + ": error occurred during unpacking on the remote end: "
+ + unpackStatus);
+
+ String refLine;
+ while ((refLine = pckIn.readString()).length() > 0) {
+ boolean ok = false;
+ int refNameEnd = -1;
+ if (refLine.startsWith("ok ")) {
+ ok = true;
+ refNameEnd = refLine.length();
+ } else if (refLine.startsWith("ng ")) {
+ ok = false;
+ refNameEnd = refLine.indexOf(" ", 3);
+ }
+ if (refNameEnd == -1)
+ throw new PackProtocolException(uri
+ + ": unexpected report line: " + refLine);
+ final String refName = refLine.substring(3, refNameEnd);
+ final String message = (ok ? null : refLine
+ .substring(refNameEnd + 1));
+
+ final RemoteRefUpdate rru = refUpdates.get(refName);
+ if (rru == null)
+ throw new PackProtocolException(uri
+ + ": unexpected ref report: " + refName);
+ if (ok) {
+ rru.setStatus(Status.OK);
+ } else {
+ rru.setStatus(Status.REJECTED_OTHER_REASON);
+ rru.setMessage(message);
+ }
+ }
+ for (final RemoteRefUpdate rru : refUpdates.values()) {
+ if (rru.getStatus() == Status.AWAITING_REPORT)
+ throw new PackProtocolException(uri
+ + ": expected report for ref " + rru.getRemoteName()
+ + " not received");
+ }
+ }
+}
--
1.5.5.3
^ 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