* Re: [PATCH v4 00/13] New remote-hg helper
From: Thomas Adam @ 2012-11-02 23:18 UTC (permalink / raw)
To: Felipe Contreras
Cc: Jeff King, Michael J Gruber, Johannes Schindelin, git list,
Junio C Hamano, Sverre Rabbelier, Ilari Liusvaara,
Daniel Barkalow
In-Reply-To: <CAMP44s0N3k4b9SoKpkR=2-zSBb41tKW37tYhuxFfbooiLu59Kw@mail.gmail.com>
On 2 November 2012 18:39, Felipe Contreras <felipe.contreras@gmail.com> wrote:
> I disagree. The open source process works not by making favors to each
> other, but by everyone sharing and improving the code, by
> *collaborating*. "I review your code if you review mine", or "if you
> by me a bear in the next conference" is not the spirit of open source,
> although it might happen often.
So shunning any attempt at explanation, and peddling your own thoughts
over and over again, irrespective of whether you contribute code or
not -- doesn't mean to say you're right, Felipe. And that's the
fundamental issue here -- your code speaks for itself, sure, no one
denies that, but the code is not even *half* of what makes up the
discussion. And so far, the surrounding context and attitude from you
doesn't help or enhance the process under which your code is reviewed.
And no, you cannot philosophise this, or wriggle out of it through
idealism or some other "charter" or "code of conduct" -- as reviewers
of your code, we have to interact with you to be able to better it.
But you seem very reluctant to do that.
The fact that we're even having the conversation is evident of that.
-- Thomas Adam
^ permalink raw reply
* Re: [PATCH v4 00/13] New remote-hg helper
From: Felipe Contreras @ 2012-11-02 23:52 UTC (permalink / raw)
To: Thomas Adam
Cc: Jeff King, Michael J Gruber, Johannes Schindelin, git list,
Junio C Hamano, Sverre Rabbelier, Ilari Liusvaara,
Daniel Barkalow
In-Reply-To: <CA+39Oz7vbAwQSfL0PMjjYgQ=njQpu5i_3BSTCzznQJozKOKeXQ@mail.gmail.com>
On Sat, Nov 3, 2012 at 12:18 AM, Thomas Adam <thomas@xteddy.org> wrote:
> On 2 November 2012 18:39, Felipe Contreras <felipe.contreras@gmail.com> wrote:
>> I disagree. The open source process works not by making favors to each
>> other, but by everyone sharing and improving the code, by
>> *collaborating*. "I review your code if you review mine", or "if you
>> by me a bear in the next conference" is not the spirit of open source,
>> although it might happen often.
>
> So shunning any attempt at explanation, and peddling your own thoughts
> over and over again, irrespective of whether you contribute code or
> not -- doesn't mean to say you're right, Felipe.
Who is saying I'm right? Certainly not me.
I have explained patches over and over, even to the point that people
apparently get offended, and now you say I should explain more?
I'm sorry, but no, you cannot have your cake and eat it at the same
time. Either you want me to explain things, or not.
> And that's the
> fundamental issue here -- your code speaks for itself, sure, no one
> denies that, but the code is not even *half* of what makes up the
> discussion. And so far, the surrounding context and attitude from you
> doesn't help or enhance the process under which your code is reviewed.
I would say it's the other way around, it's the attitude of other
people that believe they are entitled to their opinion not being
shined in a critical fashion, while at the same time being very
critical themselves.
If you want to disagree, fine, but it's still the project that gets
hurt, not me, reviewing code is still for the benefit of the project.
> And no, you cannot philosophise this, or wriggle out of it through
> idealism or some other "charter" or "code of conduct" -- as reviewers
> of your code, we have to interact with you to be able to better it.
That's right, for the benefit of the project.
> But you seem very reluctant to do that.
Reluctant to what? Interact? I've answered every single question, and
then some. I've also implemented tests, and addressed every criticism
of this patch series however rude that criticism was thrown.
It's actually the other way around. There's a thread about netiquette,
precisely to avoid certain kinds of discussion.
Show me a *single* instance where I've ignored a review comment, or
whatever you mean by being reluctant to interact.
> The fact that we're even having the conversation is evident of that.
The fact that the sun raised at east and set at the west was evident
that it was rotating around the Earth, but that, like many other
assumptions, was wrong.
Cheers.
--
Felipe Contreras
^ permalink raw reply
* Re: Wrap commit messages on `git commit -m`
From: Jonathan Nieder @ 2012-11-03 6:38 UTC (permalink / raw)
To: Ramkumar Ramachandra; +Cc: Kevin, Lars Gullik Bjønnes, git
In-Reply-To: <CALkWK0n3nvu4neica==bXaGCtDish8cfUhcsmJT0w3ihrq6coA@mail.gmail.com>
Ramkumar Ramachandra wrote:
> Jonathan Nieder wrote:
>> Ram, what platform do your colleagues use?
>
> Red Hat Enterprise Linux 5.
Oh, ok. In that case I blame habit.
I think the best option you have is to just complain to your
colleagues about the long lines. Then they would get a chance to
explore what the UI currently offers and to complain to this list
(perhaps via you :)) about missing features that would make their work
easier.
To put it another way: I don't see yet how a hypothetical "git commit
--wrap-lines -m 'long message'" would make life easier than just
running "git commit" and entering the message using $EDITOR. There's
probably a UI or documentation bug lurking somewhere, so thanks for
thinking about these things.
Regards,
Jonathan
^ permalink raw reply
* Re: Wrap commit messages on `git commit -m`
From: David Aguilar @ 2012-11-03 7:41 UTC (permalink / raw)
To: Ramkumar Ramachandra
Cc: Kevin, Lars Gullik Bjønnes, git, Jonathan Nieder
In-Reply-To: <20121103063855.GA8326@elie.Belkin>
On Fri, Nov 2, 2012 at 11:38 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:
> Ramkumar Ramachandra wrote:
>> Jonathan Nieder wrote:
>
>>> Ram, what platform do your colleagues use?
>>
>> Red Hat Enterprise Linux 5.
>
> Oh, ok. In that case I blame habit.
>
> I think the best option you have is to just complain to your
> colleagues about the long lines. Then they would get a chance to
> explore what the UI currently offers and to complain to this list
> (perhaps via you :)) about missing features that would make their work
> easier.
>
> To put it another way: I don't see yet how a hypothetical "git commit
> --wrap-lines -m 'long message'" would make life easier than just
> running "git commit" and entering the message using $EDITOR. There's
> probably a UI or documentation bug lurking somewhere, so thanks for
> thinking about these things.
>
> Regards,
> Jonathan
If your colleagues do not mind using a GUI then git-cola
might help them form better commit messages.
It auto-wraps long lines and enforces a very clear distinction
between the one-line summary and extended description.
--
David
^ permalink raw reply
* Re: git-p4 clone @all error
From: Pete Wyckoff @ 2012-11-03 14:09 UTC (permalink / raw)
To: Arthur; +Cc: git
In-Reply-To: <1351593879401-7570219.post@n2.nabble.com>
a.foulon@amesys.fr wrote on Tue, 30 Oct 2012 03:44 -0700:
> So, i want import my perforce projet on my server git.
>
> perforce my project tree :
>
> depot
> dev_data
> mainline
> release_1.0
> release_1.0.0
>
> my command is :
>
> git-p4 clone -v --detect-branches //depot@all /home/user/projets/deport
>
> The problem :
>
> Importing revision 7727 (100%)Traceback (most recent call last):
> File "/usr/bin/git-p4", line 3183, in <module>
> main()
> File "/usr/bin/git-p4", line 3177, in main
> if not cmd.run(args):
> File "/usr/bin/git-p4", line 3048, in run
> if not P4Sync.run(self, depotPaths):
> File "/usr/bin/git-p4", line 2911, in run
> self.importChanges(changes)
> File "/usr/bin/git-p4", line 2618, in importChanges
> self.initialParent)
> File "/usr/bin/git-p4", line 2198, in commit
> epoch = details["time"]
> KeyError: 'time'
This isn't the --detect-branches code path, as far as I can tell.
Line 2618, importChanges, is the not-detect case. But either
way, I suspect that p4 returns results we weren't expecting, and
this is just the symptom of that problem.
> if i make a p4 sync //depot/...#head on my perforce server i've this error :
> Librarian checkout
> depot/mainline/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/api429decryption.txt failed.
> open for read: depot/mainline/xxxxxxxxxxxxxxxxxx/api429decryption.txt,v: Le
> fichier spcifi est introuvable.
>
> My p4 clone can't checking out files after importing revision..
I've seen this before at our site. If you search for "librarian
checout" you'll see lots of messages suggesting there's some sort
of problem with the p4 server.
I'm going to work on a patch to git-p4 to make it print a more
useful diagnostic in the case of your error above. Can you
make this problem occur reliably?
-- Pete
^ permalink raw reply
* Re: [PATCH] Enable parallelism in git submodule update.
From: Jens Lehmann @ 2012-11-03 15:42 UTC (permalink / raw)
To: Stefan Zager; +Cc: git, Heiko Voigt, Junio C Hamano
In-Reply-To: <CAHOQ7J-e=KBOsjoeTWsf1f+LNgaAxN974-FXNMeOy7B-FR0wyg@mail.gmail.com>
Am 30.10.2012 19:11, schrieb Stefan Zager:
> This is a refresh of a conversation from a couple of months ago.
>
> I didn't try to implement all the desired features (e.g., smart logic
> for passing a -j parameter to recursive submodule invocations), but I
> did address the one issue that Junio insisted on: the code makes a
> best effort to detect whether xargs supports parallel execution on the
> host platform, and if it doesn't, then it prints a warning and falls
> back to serial execution.
I suspect not passing on --jobs recursively like you do here is the
right thing to do, as that would give exponential growth of jobs with
recursion depth, which makes no sense to me.
A still unsolved issue is the unstructured output from the different
update jobs. It'll be hard (if not impossible) to see in what submodule
which update took place (or failed). I think we should have a solution
for that too (maybe one of those Heiko mentioned or something as simple
as implying "-q"?).
> Stefan
>
> On Tue, Oct 30, 2012 at 11:03 AM, <szager@google.com> wrote:
>> The --jobs parameter may be used to set the degree of per-submodule
>> parallel execution.
>
>> Signed-off-by: Stefan Zager <szager@google.com>
>> ---
>> Documentation/git-submodule.txt | 8 ++++++-
>> git-submodule.sh | 40 ++++++++++++++++++++++++++++++++++++++-
>> 2 files changed, 46 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
>> index b4683bb..cb23ba7 100644
>> --- a/Documentation/git-submodule.txt
>> +++ b/Documentation/git-submodule.txt
>> @@ -14,7 +14,8 @@ SYNOPSIS
>> 'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
>> 'git submodule' [--quiet] init [--] [<path>...]
>> 'git submodule' [--quiet] update [--init] [-N|--no-fetch] [--rebase]
>> - [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
>> + [--reference <repository>] [--merge] [--recursive]
>> + [-j|--jobs [jobs]] [--] [<path>...]
>> 'git submodule' [--quiet] summary [--cached|--files] [(-n|--summary-limit) <n>]
>> [commit] [--] [<path>...]
>> 'git submodule' [--quiet] foreach [--recursive] <command>
>> @@ -146,6 +147,11 @@ If the submodule is not yet initialized, and you just want to use the
>> setting as stored in .gitmodules, you can automatically initialize the
>> submodule with the `--init` option.
>> +
>> +By default, each submodule is treated serially. You may specify a degree of
>> +parallel execution with the --jobs flag. If a parameter is provided, it is
>> +the maximum number of jobs to run in parallel; without a parameter, all jobs are
>> +run in parallel.
>> ++
The new "--jobs" option should be documented under "OPTIONS", (and maybe
include that "--jobs 0" does the same as "--jobs" alone and that this is
not supported on all platforms).
>> If `--recursive` is specified, this command will recurse into the
>> registered submodules, and update any nested submodules within.
>> +
>> diff --git a/git-submodule.sh b/git-submodule.sh
>> index ab6b110..60a5f96 100755
>> --- a/git-submodule.sh
>> +++ b/git-submodule.sh
>> @@ -8,7 +8,7 @@ dashless=$(basename "$0" | sed -e 's/-/ /')
>> USAGE="[--quiet] add [-b branch] [-f|--force] [--reference <repository>] [--] <repository> [<path>]
>> or: $dashless [--quiet] status [--cached] [--recursive] [--] [<path>...]
>> or: $dashless [--quiet] init [--] [<path>...]
>> - or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [--] [<path>...]
>> + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference <repository>] [--merge] [--recursive] [-j|--jobs [jobs]] [--] [<path>...]
>> or: $dashless [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
>> or: $dashless [--quiet] foreach [--recursive] <command>
>> or: $dashless [--quiet] sync [--] [<path>...]"
>> @@ -500,6 +500,7 @@ cmd_update()
>> {
>> # parse $args after "submodule ... update".
>> orig_flags=
>> + jobs="1"
>> while test $# -ne 0
>> do
>> case "$1" in
>> @@ -518,6 +519,20 @@ cmd_update()
>> -r|--rebase)
>> update="rebase"
>> ;;
>> + -j|--jobs)
>> + case "$2" in
>> + ''|-*)
>> + jobs="0"
>> + ;;
>> + *)
>> + jobs="$2"
>> + shift
>> + ;;
>> + esac
>> + # Don't preserve this arg.
>> + shift
>> + continue
>> + ;;
>> --reference)
>> case "$2" in '') usage ;; esac
>> reference="--reference=$2"
>> @@ -551,11 +566,34 @@ cmd_update()
>> shift
>> done
>>
>> + # Correctly handle the case where '-q' came before 'update' on the command line.
>> + if test -n "$GIT_QUIET"
>> + then
>> + orig_flags="$orig_flags -q"
>> + fi
>> +
>> if test -n "$init"
>> then
>> cmd_init "--" "$@" || return
>> fi
>>
>> + if test "$jobs" != 1
>> + then
>> + if ( echo test | xargs -P "$jobs" true 2>/dev/null )
>> + then
>> + if ( echo test | xargs --max-lines=1 true 2>/dev/null ); then
>> + max_lines="--max-lines=1"
>> + else
>> + max_lines="-L 1"
>> + fi
>> + module_list "$@" | awk '{print $4}' |
>> + xargs $max_lines -P "$jobs" git submodule update $orig_flags
>> + return
>> + else
>> + echo "Warn: parallel execution is not supported on this platform."
>> + fi
>> + fi
>> +
>> cloned_modules=
>> module_list "$@" | {
>> err=
>> --
>> 1.7.7.3
>>
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH] Enable parallelism in git submodule update.
From: Phil Hord @ 2012-11-03 18:44 UTC (permalink / raw)
To: Jens Lehmann; +Cc: Stefan Zager, git, Heiko Voigt, Junio C Hamano
In-Reply-To: <50953B52.3070107@web.de>
On Sat, Nov 3, 2012 at 11:42 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:
> Am 30.10.2012 19:11, schrieb Stefan Zager:
>> This is a refresh of a conversation from a couple of months ago.
>>
>> I didn't try to implement all the desired features (e.g., smart logic
>> for passing a -j parameter to recursive submodule invocations), but I
>> did address the one issue that Junio insisted on: the code makes a
>> best effort to detect whether xargs supports parallel execution on the
>> host platform, and if it doesn't, then it prints a warning and falls
>> back to serial execution.
>
> I suspect not passing on --jobs recursively like you do here is the
> right thing to do, as that would give exponential growth of jobs with
> recursion depth, which makes no sense to me.
On the other hand, since $jobs is still defined when the recursive
call to is made to 'eval cmd_update "$orig_flags"', I suspect the
value *is* passed down recursively. Maybe $jobs should be manually
reset before recursing -- unless it is "0" -- though I expect someone
would feel differently if she had one submodule on level 1 and 10
submodules on level 2. She would be surprised, then, when --jobs=10
seemed to have little affect on performance. So maybe it is best to
leave it as it is, excepting that the apparent attempt not to pass the
switch down is probably misleading.
Phil
^ permalink raw reply
* Re: Wrap commit messages on `git commit -m`
From: Phil Hord @ 2012-11-03 18:51 UTC (permalink / raw)
To: David Aguilar
Cc: Ramkumar Ramachandra, Kevin, Lars Gullik Bjønnes, git,
Jonathan Nieder
In-Reply-To: <CAJDDKr4ta2Xu5zO6yASSNewZXxu=LWuNO0zU8YnSP4Kq9ZJn-g@mail.gmail.com>
On Sat, Nov 3, 2012 at 3:41 AM, David Aguilar <davvid@gmail.com> wrote:
> On Fri, Nov 2, 2012 at 11:38 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:
>> Ramkumar Ramachandra wrote:
>>> Jonathan Nieder wrote:
>>
>>>> Ram, what platform do your colleagues use?
>>>
>>> Red Hat Enterprise Linux 5.
>>
>> Oh, ok. In that case I blame habit.
>>
>> I think the best option you have is to just complain to your
>> colleagues about the long lines. Then they would get a chance to
>> explore what the UI currently offers and to complain to this list
>> (perhaps via you :)) about missing features that would make their work
>> easier.
>>
>> To put it another way: I don't see yet how a hypothetical "git commit
>> --wrap-lines -m 'long message'" would make life easier than just
>> running "git commit" and entering the message using $EDITOR. There's
>> probably a UI or documentation bug lurking somewhere, so thanks for
>> thinking about these things.
>>
>> Regards,
>> Jonathan
>
> If your colleagues do not mind using a GUI then git-cola
> might help them form better commit messages.
>
> It auto-wraps long lines and enforces a very clear distinction
> between the one-line summary and extended description.
vim also does this nicely with syntax highlighting turned on, though I
do not know how this feature is triggered.
Specifically, it wraps all lines at 72 characters; it colors line 1
yellow out to 50 characters and white after that; and it colors any
text on line 2 with a red background (should be empty).
Phil
^ permalink raw reply
* Re: [PATCH] Enable parallelism in git submodule update.
From: Jens Lehmann @ 2012-11-03 19:07 UTC (permalink / raw)
To: Stefan Zager; +Cc: git, gitster, hvoigt
In-Reply-To: <501558AD.6010402@web.de>
Am 29.07.2012 17:37, schrieb Jens Lehmann:
> Am 27.07.2012 20:37, schrieb Stefan Zager:
>> The --jobs parameter may be used to set the degree of per-submodule
>> parallel execution.
>
> I think this is a sound idea, but it would be good to see some
> actual measurements. What are the performance numbers with and
> without this change? Which cases do benefit and are there some
> which run slower when run in parallel?
ping?
^ permalink raw reply
* Re: [PATCH] Enable parallelism in git submodule update.
From: Jens Lehmann @ 2012-11-03 19:13 UTC (permalink / raw)
To: Phil Hord; +Cc: Stefan Zager, git, Heiko Voigt, Junio C Hamano
In-Reply-To: <CABURp0pkv714k_+S2seTtdHMNJFzkgijYuNuWcfNvnF+c21cDg@mail.gmail.com>
Am 03.11.2012 19:44, schrieb Phil Hord:
> On Sat, Nov 3, 2012 at 11:42 AM, Jens Lehmann <Jens.Lehmann@web.de> wrote:
>> Am 30.10.2012 19:11, schrieb Stefan Zager:
>>> This is a refresh of a conversation from a couple of months ago.
>>>
>>> I didn't try to implement all the desired features (e.g., smart logic
>>> for passing a -j parameter to recursive submodule invocations), but I
>>> did address the one issue that Junio insisted on: the code makes a
>>> best effort to detect whether xargs supports parallel execution on the
>>> host platform, and if it doesn't, then it prints a warning and falls
>>> back to serial execution.
>>
>> I suspect not passing on --jobs recursively like you do here is the
>> right thing to do, as that would give exponential growth of jobs with
>> recursion depth, which makes no sense to me.
>
> On the other hand, since $jobs is still defined when the recursive
> call to is made to 'eval cmd_update "$orig_flags"', I suspect the
> value *is* passed down recursively.
But for $jobs != 1 Stefan's code doesn't use eval cmd_update but
starts the submodule script again:
+ xargs $max_lines -P "$jobs" git submodule update $orig_flags
That should get rid of the $jobs setting, or am I missing something?
> Maybe $jobs should be manually
> reset before recursing -- unless it is "0" -- though I expect someone
> would feel differently if she had one submodule on level 1 and 10
> submodules on level 2. She would be surprised, then, when --jobs=10
> seemed to have little affect on performance.
Hmm, good point. However we implement that, it should at least be
properly documented in the man page (and in the use case you describe
a "git submodule foreach 'git submodule update -j 10'" could be the
solution if we choose to not propagate the jobs option).
> So maybe it is best to
> leave it as it is, excepting that the apparent attempt not to pass the
> switch down is probably misleading.
I didn't test it, but I think it should work (famous last words ;-).
^ permalink raw reply
* [PATCH] git p4: catch p4 describe errors
From: Pete Wyckoff @ 2012-11-03 23:07 UTC (permalink / raw)
To: git; +Cc: Arthur, Matt Arsenault
In-Reply-To: <20121103140946.GB4651@padd.com>
Group the two calls to "p4 describe" into a new helper function,
and try to validate the p4 results. The current behavior when p4
describe fails is to die with a python backtrace. The new behavior
will print the full response.
Based-on-patch-by: Matt Arsenault <arsenm2@gmail.com>
Signed-off-by: Pete Wyckoff <pw@padd.com>
---
Arthur and Matt, you've both had intermittent "p4 describe"
errors. I've not been able to repeat this or come up with
a possible root cause. But it is clear that the error handling
in this area is weak.
Can you continue using git-p4 with this patch applied? If
it fails again, at least we'll get some interesting output.
This is appropriate for upstream too, since it should do no harm
and might flush out a bug at some point. It includes "-s" on
both p4 describe calls now as Matt suggested.
-- Pete
git-p4.py | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/git-p4.py b/git-p4.py
index 882b1bb..e51a081 100755
--- a/git-p4.py
+++ b/git-p4.py
@@ -169,6 +169,29 @@ def p4_reopen(type, f):
def p4_move(src, dest):
p4_system(["move", "-k", wildcard_encode(src), wildcard_encode(dest)])
+def p4_describe(change):
+ """Make sure it returns a valid result by checking for
+ the presence of field "time". Return a dict of the
+ results."""
+
+ ds = p4CmdList(["describe", "-s", str(change)])
+ if len(ds) != 1:
+ die("p4 describe -s %d did not return 1 result: %s" % (change, str(ds)))
+
+ d = ds[0]
+
+ if "p4ExitCode" in d:
+ die("p4 describe -s %d exited with %d: %s" % (change, d["p4ExitCode"],
+ str(d)))
+ if "code" in d:
+ if d["code"] == "error":
+ die("p4 describe -s %d returned error code: %s" % (change, str(d)))
+
+ if "time" not in d:
+ die("p4 describe -s %d returned no \"time\": %s" % (change, str(d)))
+
+ return d
+
#
# Canonicalize the p4 type and return a tuple of the
# base type, plus any modifiers. See "p4 help filetypes"
@@ -2543,7 +2566,7 @@ class P4Sync(Command, P4UserMap):
def importChanges(self, changes):
cnt = 1
for change in changes:
- description = p4Cmd(["describe", str(change)])
+ description = p4_describe(change)
self.updateOptionDict(description)
if not self.silent:
@@ -2667,14 +2690,8 @@ class P4Sync(Command, P4UserMap):
# Use time from top-most change so that all git p4 clones of
# the same p4 repo have the same commit SHA1s.
- res = p4CmdList("describe -s %d" % newestRevision)
- newestTime = None
- for r in res:
- if r.has_key('time'):
- newestTime = int(r['time'])
- if newestTime is None:
- die("\"describe -s\" on newest change %d did not give a time")
- details["time"] = newestTime
+ res = p4_describe(newestRevision)
+ details["time"] = res["time"]
self.updateOptionDict(details)
try:
--
1.7.12.1.457.g468b3ef
^ permalink raw reply related
* Re: [PATCH] git p4: catch p4 describe errors
From: Matt Arsenault @ 2012-11-03 23:12 UTC (permalink / raw)
To: Pete Wyckoff; +Cc: git, Arthur
In-Reply-To: <20121103230701.GA11267@padd.com>
On Nov 3, 2012, at 16:07 , Pete Wyckoff <pw@padd.com> wrote:
>
> Arthur and Matt, you've both had intermittent "p4 describe"
> errors. I've not been able to repeat this or come up with
> a possible root cause. But it is clear that the error handling
> in this area is weak.
I tried this week to find the commit that caused the problem, but there were too many to sift through so I haven't managed to see it again either
^ permalink raw reply
* Re: git-p4 clone @all error
From: Pete Wyckoff @ 2012-11-03 23:13 UTC (permalink / raw)
To: Thomas Berg; +Cc: Arthur, git
In-Reply-To: <CABYiQp=1HEW=53U2Rck5vckhq0PB3C9iuanoXeVvNG6Xv5+oHg@mail.gmail.com>
merlin66b@gmail.com wrote on Wed, 31 Oct 2012 15:01 +0100:
> On Tue, Oct 30, 2012 at 11:44 AM, Arthur <a.foulon@amesys.fr> wrote:
> > The problem :
> >
> > Importing revision 7727 (100%)Traceback (most recent call last):
> > File "/usr/bin/git-p4", line 3183, in <module>
> > main()
> > File "/usr/bin/git-p4", line 3177, in main
> > if not cmd.run(args):
> > File "/usr/bin/git-p4", line 3048, in run
> > if not P4Sync.run(self, depotPaths):
> > File "/usr/bin/git-p4", line 2911, in run
> > self.importChanges(changes)
> > File "/usr/bin/git-p4", line 2618, in importChanges
> > self.initialParent)
> > File "/usr/bin/git-p4", line 2198, in commit
> > epoch = details["time"]
> > KeyError: 'time'
>
> Are you permanently converting a project, or are you planning to
> continue submitting to perforce with git-p4?
>
> I have seen similar bugs myself when using the --detect-branches
> option.
I hope --detect-branches is unrelated to any problems related to
p4 describe, because it is used identically both with and without
the option. But you never know.
> The branch detection in git-p4 is flaky anyway: it is limited
> what it can handle, and it used to require correct perforce branch
> specs at least, so I would recommend not using it unless you know what
> it is doing under the hood.
It relies on heuristics because the git idea of branches doesn't
have a direct analog in p4, even though p4 users will organize
their files and directories in ways that suggest branches. The
way it works is described in the BRANCH DETECTION part of the
git-p4.1 man page.
The man page also explains how you can use a config variable
to explicitly define the branch relationships. This might help:
git-p4.branchList::
List of branches to be imported when branch detection is
enabled. Each entry should be a pair of branch names separated
by a colon (:). This example declares that both branchA and
branchB were created from main:
git config git-p4.branchList main:branchA
git config --add git-p4.branchList main:branchB
It still only works for branches at the same "level" of the
depot path.
> Instead I would just clone a single branch at a time (drop the
> --detect-branches) and work on that.
>
> I do this even in the rare cases when I need more than one perforce
> branch in the same git repo - there are other ways to achieve the same
> thing.
Yep, that should alway works.
-- Pete
^ permalink raw reply
* [PATCH v6 00/16] New remote-hg helper:w
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
Hi,
Only a few updates, and has been moved to contrib/remote-helpers
(git-remote-bzr is on the way).
This remote-hg has advantages other tools don't have:
* Uses transport-helper (git clone hg::path)
* The code is small
* The code is simple
* No external dependencies (other than mercurial)
* It's easy to install (put into your path)
* Has extensive tests (for real)
* Active development
* Has compatibility with hg-git
* The required patches are available
* No changes necesary to git core
* Support for bookmarks
* Support for tags
One important alternative is the one written by Sverre Rabbelier that is
now maintained and distributed in msysgit. A list of issues with that
approach (not exhaustive):
* Doesn't work on newer versions of mercurial
* There are multiple versions, each with different issues
* Don't pass a single of this remote-hg's tests
To use it add it to your $PATH (e.g. ~/bin).
% git clone hd:///full/path/or/url/to/hg/repo
To run the tests:
% make -C contrib/remote-helpers test
The only caveat is that you need 'python' in your $PATH.
Changes since v5:
* Move to contrib/remote-helpers
* Reorganize tests
* Fix update of bookmarks
* Fix for older versions of python
* Performance improvements
* Improve default branch/bookmark handling
* Add fixes test-lib
* Cleanups
Changes since v4:
Felipe Contreras (16):
Add new remote-hg transport helper
remote-hg: add support for pushing
remote-hg: add support for remote pushing
remote-hg: add support to push URLs
remote-hg: make sure the encoding is correct
remote-hg: match hg merge behavior
remote-hg: add support for hg-git compat mode
remote-hg: add compat for hg-git author fixes
remote-hg: fake bookmark when there's none
remote-hg: add basic tests
test-lib: avoid full path to store test results
remote-hg: add bidirectional tests
remote-hg: add tests to compare with hg-git
remote-hg: add extra author test
remote-hg: add option to not track branches
remote-hg: the author email can be null
contrib/remote-helpers/Makefile | 13 +
contrib/remote-helpers/git-remote-hg | 785 +++++++++++++++++++++++++++++++
contrib/remote-helpers/test-hg-bidi.sh | 243 ++++++++++
contrib/remote-helpers/test-hg-hg-git.sh | 466 ++++++++++++++++++
contrib/remote-helpers/test-hg.sh | 112 +++++
t/test-lib.sh | 3 +-
6 files changed, 1621 insertions(+), 1 deletion(-)
create mode 100644 contrib/remote-helpers/Makefile
create mode 100755 contrib/remote-helpers/git-remote-hg
create mode 100755 contrib/remote-helpers/test-hg-bidi.sh
create mode 100755 contrib/remote-helpers/test-hg-hg-git.sh
create mode 100755 contrib/remote-helpers/test-hg.sh
--
1.8.0
^ permalink raw reply
* [PATCH v6 01/16] Add new remote-hg transport helper
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 391 +++++++++++++++++++++++++++++++++++
1 file changed, 391 insertions(+)
create mode 100755 contrib/remote-helpers/git-remote-hg
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
new file mode 100755
index 0000000..e37e278
--- /dev/null
+++ b/contrib/remote-helpers/git-remote-hg
@@ -0,0 +1,391 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+
+# Inspired by Rocco Rutte's hg-fast-export
+
+# Just copy to your ~/bin, or anywhere in your $PATH.
+# Then you can clone with:
+# git clone hg::/path/to/mercurial/repo/
+
+from mercurial import hg, ui, bookmarks
+
+import re
+import sys
+import os
+import json
+
+NAME_RE = re.compile('^([^<>]+)')
+AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]+)>$')
+
+def die(msg, *args):
+ sys.stderr.write('ERROR: %s\n' % (msg % args))
+ sys.exit(1)
+
+def warn(msg, *args):
+ sys.stderr.write('WARNING: %s\n' % (msg % args))
+
+def gitmode(flags):
+ return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644'
+
+def gittz(tz):
+ return '%+03d%02d' % (-tz / 3600, -tz % 3600 / 60)
+
+class Marks:
+
+ def __init__(self, path):
+ self.path = path
+ self.tips = {}
+ self.marks = {}
+ self.last_mark = 0
+
+ self.load()
+
+ def load(self):
+ if not os.path.exists(self.path):
+ return
+
+ tmp = json.load(open(self.path))
+
+ self.tips = tmp['tips']
+ self.marks = tmp['marks']
+ self.last_mark = tmp['last-mark']
+
+ def dict(self):
+ return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
+
+ def store(self):
+ json.dump(self.dict(), open(self.path, 'w'))
+
+ def __str__(self):
+ return str(self.dict())
+
+ def from_rev(self, rev):
+ return self.marks[str(rev)]
+
+ def get_mark(self, rev):
+ self.last_mark += 1
+ self.marks[str(rev)] = self.last_mark
+ return self.last_mark
+
+ def is_marked(self, rev):
+ return self.marks.has_key(str(rev))
+
+ def get_tip(self, branch):
+ return self.tips.get(branch, 0)
+
+ def set_tip(self, branch, tip):
+ self.tips[branch] = tip
+
+class Parser:
+
+ def __init__(self, repo):
+ self.repo = repo
+ self.line = self.get_line()
+
+ def get_line(self):
+ return sys.stdin.readline().strip()
+
+ def __getitem__(self, i):
+ return self.line.split()[i]
+
+ def check(self, word):
+ return self.line.startswith(word)
+
+ def each_block(self, separator):
+ while self.line != separator:
+ yield self.line
+ self.line = self.get_line()
+
+ def __iter__(self):
+ return self.each_block('')
+
+ def next(self):
+ self.line = self.get_line()
+ if self.line == 'done':
+ self.line = None
+
+def export_file(fc):
+ d = fc.data()
+ print "M %s inline %s" % (gitmode(fc.flags()), fc.path())
+ print "data %d" % len(d)
+ print d
+
+def get_filechanges(repo, ctx, parent):
+ modified = set()
+ added = set()
+ removed = set()
+
+ cur = ctx.manifest()
+ prev = repo[parent].manifest().copy()
+
+ for fn in cur:
+ if fn in prev:
+ if (cur.flags(fn) != prev.flags(fn) or cur[fn] != prev[fn]):
+ modified.add(fn)
+ del prev[fn]
+ else:
+ added.add(fn)
+ removed |= set(prev.keys())
+
+ return added | modified, removed
+
+def fixup_user(user):
+ user = user.replace('"', '')
+ name = mail = None
+ m = AUTHOR_RE.match(user)
+ if m:
+ name = m.group(1)
+ mail = m.group(2).strip()
+ else:
+ m = NAME_RE.match(user)
+ if m:
+ name = m.group(1).strip()
+
+ if not name:
+ name = 'Unknown'
+ if not mail:
+ mail = 'unknown'
+
+ return '%s <%s>' % (name, mail)
+
+def get_repo(url, alias):
+ global dirname
+
+ myui = ui.ui()
+ myui.setconfig('ui', 'interactive', 'off')
+
+ if hg.islocal(url):
+ repo = hg.repository(myui, url)
+ else:
+ local_path = os.path.join(dirname, 'clone')
+ if not os.path.exists(local_path):
+ peer, dstpeer = hg.clone(myui, {}, url, local_path, update=False, pull=True)
+ repo = dstpeer.local()
+ else:
+ repo = hg.repository(myui, local_path)
+ peer = hg.peer(myui, {}, url)
+ repo.pull(peer, heads=None, force=True)
+
+ return repo
+
+def rev_to_mark(rev):
+ global marks
+ return marks.from_rev(rev)
+
+def export_ref(repo, name, kind, head):
+ global prefix, marks
+
+ ename = '%s/%s' % (kind, name)
+ tip = marks.get_tip(ename)
+
+ # mercurial takes too much time checking this
+ if tip and tip == head.rev():
+ # nothing to do
+ return
+ revs = repo.revs('%u:%u' % (tip, head))
+ count = 0
+
+ revs = [rev for rev in revs if not marks.is_marked(rev)]
+
+ for rev in revs:
+
+ c = repo[rev]
+ (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(c.node())
+ rev_branch = extra['branch']
+
+ author = "%s %d %s" % (fixup_user(user), time, gittz(tz))
+ if 'committer' in extra:
+ user, time, tz = extra['committer'].rsplit(' ', 2)
+ committer = "%s %s %s" % (user, time, gittz(int(tz)))
+ else:
+ committer = author
+
+ parents = [p for p in repo.changelog.parentrevs(rev) if p >= 0]
+
+ if len(parents) == 0:
+ modified = c.manifest().keys()
+ removed = []
+ else:
+ modified, removed = get_filechanges(repo, c, parents[0])
+
+ if len(parents) == 0 and rev:
+ print 'reset %s/%s' % (prefix, ename)
+
+ print "commit %s/%s" % (prefix, ename)
+ print "mark :%d" % (marks.get_mark(rev))
+ print "author %s" % (author)
+ print "committer %s" % (committer)
+ print "data %d" % (len(desc))
+ print desc
+
+ if len(parents) > 0:
+ print "from :%s" % (rev_to_mark(parents[0]))
+ if len(parents) > 1:
+ print "merge :%s" % (rev_to_mark(parents[1]))
+
+ for f in modified:
+ export_file(c.filectx(f))
+ for f in removed:
+ print "D %s" % (f)
+ print
+
+ count += 1
+ if (count % 100 == 0):
+ print "progress revision %d '%s' (%d/%d)" % (rev, name, count, len(revs))
+ print "#############################################################"
+
+ # make sure the ref is updated
+ print "reset %s/%s" % (prefix, ename)
+ print "from :%u" % rev_to_mark(rev)
+ print
+
+ marks.set_tip(ename, rev)
+
+def export_tag(repo, tag):
+ export_ref(repo, tag, 'tags', repo[tag])
+
+def export_bookmark(repo, bmark):
+ head = bmarks[bmark]
+ export_ref(repo, bmark, 'bookmarks', head)
+
+def export_branch(repo, branch):
+ tip = get_branch_tip(repo, branch)
+ head = repo[tip]
+ export_ref(repo, branch, 'branches', head)
+
+def export_head(repo):
+ global g_head
+ export_ref(repo, g_head[0], 'bookmarks', g_head[1])
+
+def do_capabilities(parser):
+ global prefix, dirname
+
+ print "import"
+ print "refspec refs/heads/branches/*:%s/branches/*" % prefix
+ print "refspec refs/heads/*:%s/bookmarks/*" % prefix
+ print "refspec refs/tags/*:%s/tags/*" % prefix
+ print
+
+def get_branch_tip(repo, branch):
+ global branches
+
+ heads = branches.get(branch, None)
+ if not heads:
+ return None
+
+ # verify there's only one head
+ if (len(heads) > 1):
+ warn("Branch '%s' has more than one head, consider merging" % branch)
+ # older versions of mercurial don't have this
+ if hasattr(repo, "branchtip"):
+ return repo.branchtip(branch)
+
+ return heads[0]
+
+def list_head(repo, cur):
+ global g_head
+
+ head = bookmarks.readcurrent(repo)
+ if not head:
+ return
+ node = repo[head]
+ print "@refs/heads/%s HEAD" % head
+ g_head = (head, node)
+
+def do_list(parser):
+ global branches, bmarks
+
+ repo = parser.repo
+ for branch in repo.branchmap():
+ heads = repo.branchheads(branch)
+ if len(heads):
+ branches[branch] = heads
+
+ for bmark, node in bookmarks.listbookmarks(repo).iteritems():
+ bmarks[bmark] = repo[node]
+
+ cur = repo.dirstate.branch()
+
+ list_head(repo, cur)
+ for branch in branches:
+ print "? refs/heads/branches/%s" % branch
+ for bmark in bmarks:
+ print "? refs/heads/%s" % bmark
+
+ for tag, node in repo.tagslist():
+ if tag == 'tip':
+ continue
+ print "? refs/tags/%s" % tag
+
+ print
+
+def do_import(parser):
+ repo = parser.repo
+
+ path = os.path.join(dirname, 'marks-git')
+
+ print "feature done"
+ if os.path.exists(path):
+ print "feature import-marks=%s" % path
+ print "feature export-marks=%s" % path
+ sys.stdout.flush()
+
+ # lets get all the import lines
+ while parser.check('import'):
+ ref = parser[1]
+
+ if (ref == 'HEAD'):
+ export_head(repo)
+ elif ref.startswith('refs/heads/branches/'):
+ branch = ref[len('refs/heads/branches/'):]
+ export_branch(repo, branch)
+ elif ref.startswith('refs/heads/'):
+ bmark = ref[len('refs/heads/'):]
+ export_bookmark(repo, bmark)
+ elif ref.startswith('refs/tags/'):
+ tag = ref[len('refs/tags/'):]
+ export_tag(repo, tag)
+
+ parser.next()
+
+ print 'done'
+
+def main(args):
+ global prefix, dirname, marks, branches, bmarks
+
+ alias = args[1]
+ url = args[2]
+
+ gitdir = os.environ['GIT_DIR']
+ dirname = os.path.join(gitdir, 'hg', alias)
+ branches = {}
+ bmarks = {}
+
+ repo = get_repo(url, alias)
+ prefix = 'refs/hg/%s' % alias
+
+ if not os.path.exists(dirname):
+ os.makedirs(dirname)
+
+ marks_path = os.path.join(dirname, 'marks-hg')
+ marks = Marks(marks_path)
+
+ parser = Parser(repo)
+ for line in parser:
+ if parser.check('capabilities'):
+ do_capabilities(parser)
+ elif parser.check('list'):
+ do_list(parser)
+ elif parser.check('import'):
+ do_import(parser)
+ elif parser.check('export'):
+ do_export(parser)
+ else:
+ die('unhandled command: %s' % line)
+ sys.stdout.flush()
+
+ marks.store()
+
+sys.exit(main(sys.argv))
--
1.8.0
^ permalink raw reply related
* [PATCH v6 03/16] remote-hg: add support for remote pushing
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index fcceede..45629e0 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -197,7 +197,7 @@ def fixup_user(user):
return '%s <%s>' % (name, mail)
def get_repo(url, alias):
- global dirname
+ global dirname, peer
myui = ui.ui()
myui.setconfig('ui', 'interactive', 'off')
@@ -526,7 +526,7 @@ def parse_tag(parser):
# nothing to do
def do_export(parser):
- global parsed_refs, bmarks
+ global parsed_refs, bmarks, peer
parser.next()
@@ -562,12 +562,17 @@ def do_export(parser):
print
+ if peer:
+ parser.repo.push(peer, force=False)
+
def main(args):
global prefix, dirname, branches, bmarks
global marks, blob_marks, parsed_refs
+ global peer
alias = args[1]
url = args[2]
+ peer = None
gitdir = os.environ['GIT_DIR']
dirname = os.path.join(gitdir, 'hg', alias)
--
1.8.0
^ permalink raw reply related
* [PATCH v6 02/16] remote-hg: add support for pushing
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 217 ++++++++++++++++++++++++++++++++++-
1 file changed, 215 insertions(+), 2 deletions(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index e37e278..fcceede 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -9,7 +9,7 @@
# Then you can clone with:
# git clone hg::/path/to/mercurial/repo/
-from mercurial import hg, ui, bookmarks
+from mercurial import hg, ui, bookmarks, context
import re
import sys
@@ -18,6 +18,7 @@ import json
NAME_RE = re.compile('^([^<>]+)')
AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]+)>$')
+RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.+)> (\d+) ([+-]\d+)')
def die(msg, *args):
sys.stderr.write('ERROR: %s\n' % (msg % args))
@@ -32,12 +33,17 @@ def gitmode(flags):
def gittz(tz):
return '%+03d%02d' % (-tz / 3600, -tz % 3600 / 60)
+def hgmode(mode):
+ m = { '0100755': 'x', '0120000': 'l' }
+ return m.get(mode, '')
+
class Marks:
def __init__(self, path):
self.path = path
self.tips = {}
self.marks = {}
+ self.rev_marks = {}
self.last_mark = 0
self.load()
@@ -52,6 +58,9 @@ class Marks:
self.marks = tmp['marks']
self.last_mark = tmp['last-mark']
+ for rev, mark in self.marks.iteritems():
+ self.rev_marks[mark] = int(rev)
+
def dict(self):
return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark }
@@ -64,11 +73,19 @@ class Marks:
def from_rev(self, rev):
return self.marks[str(rev)]
+ def to_rev(self, mark):
+ return self.rev_marks[mark]
+
def get_mark(self, rev):
self.last_mark += 1
self.marks[str(rev)] = self.last_mark
return self.last_mark
+ def new_mark(self, rev, mark):
+ self.marks[str(rev)] = mark
+ self.rev_marks[mark] = rev
+ self.last_mark = mark
+
def is_marked(self, rev):
return self.marks.has_key(str(rev))
@@ -106,6 +123,35 @@ class Parser:
if self.line == 'done':
self.line = None
+ def get_mark(self):
+ i = self.line.index(':') + 1
+ return int(self.line[i:])
+
+ def get_data(self):
+ if not self.check('data'):
+ return None
+ i = self.line.index(' ') + 1
+ size = int(self.line[i:])
+ return sys.stdin.read(size)
+
+ def get_author(self):
+ m = RAW_AUTHOR_RE.match(self.line)
+ if not m:
+ return None
+ _, name, email, date, tz = m.groups()
+
+ if email != 'unknown':
+ if name:
+ user = '%s <%s>' % (name, email)
+ else:
+ user = '<%s>' % (email)
+ else:
+ user = name
+
+ tz = int(tz)
+ tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
+ return (user, int(date), -tz)
+
def export_file(fc):
d = fc.data()
print "M %s inline %s" % (gitmode(fc.flags()), fc.path())
@@ -174,6 +220,10 @@ def rev_to_mark(rev):
global marks
return marks.from_rev(rev)
+def mark_to_rev(mark):
+ global marks
+ return marks.to_rev(mark)
+
def export_ref(repo, name, kind, head):
global prefix, marks
@@ -263,9 +313,17 @@ def do_capabilities(parser):
global prefix, dirname
print "import"
+ print "export"
print "refspec refs/heads/branches/*:%s/branches/*" % prefix
print "refspec refs/heads/*:%s/bookmarks/*" % prefix
print "refspec refs/tags/*:%s/tags/*" % prefix
+
+ path = os.path.join(dirname, 'marks-git')
+
+ if os.path.exists(path):
+ print "*import-marks %s" % path
+ print "*export-marks %s" % path
+
print
def get_branch_tip(repo, branch):
@@ -352,8 +410,161 @@ def do_import(parser):
print 'done'
+def parse_blob(parser):
+ global blob_marks
+
+ parser.next()
+ mark = parser.get_mark()
+ parser.next()
+ data = parser.get_data()
+ blob_marks[mark] = data
+ parser.next()
+ return
+
+def parse_commit(parser):
+ global marks, blob_marks, bmarks, parsed_refs
+
+ from_mark = merge_mark = None
+
+ ref = parser[1]
+ parser.next()
+
+ commit_mark = parser.get_mark()
+ parser.next()
+ author = parser.get_author()
+ parser.next()
+ committer = parser.get_author()
+ parser.next()
+ data = parser.get_data()
+ parser.next()
+ if parser.check('from'):
+ from_mark = parser.get_mark()
+ parser.next()
+ if parser.check('merge'):
+ merge_mark = parser.get_mark()
+ parser.next()
+ if parser.check('merge'):
+ die('octopus merges are not supported yet')
+
+ files = {}
+
+ for line in parser:
+ if parser.check('M'):
+ t, m, mark_ref, path = line.split(' ')
+ mark = int(mark_ref[1:])
+ f = { 'mode' : hgmode(m), 'data' : blob_marks[mark] }
+ elif parser.check('D'):
+ t, path = line.split(' ')
+ f = { 'deleted' : True }
+ else:
+ die('Unknown file command: %s' % line)
+ files[path] = f
+
+ def getfilectx(repo, memctx, f):
+ of = files[f]
+ if 'deleted' in of:
+ raise IOError
+ is_exec = of['mode'] == 'x'
+ is_link = of['mode'] == 'l'
+ return context.memfilectx(f, of['data'], is_link, is_exec, None)
+
+ repo = parser.repo
+
+ user, date, tz = author
+ extra = {}
+
+ if committer != author:
+ extra['committer'] = "%s %u %u" % committer
+
+ if from_mark:
+ p1 = repo.changelog.node(mark_to_rev(from_mark))
+ else:
+ p1 = '\0' * 20
+
+ if merge_mark:
+ p2 = repo.changelog.node(mark_to_rev(merge_mark))
+ else:
+ p2 = '\0' * 20
+
+ ctx = context.memctx(repo, (p1, p2), data,
+ files.keys(), getfilectx,
+ user, (date, tz), extra)
+
+ node = repo.commitctx(ctx)
+
+ rev = repo[node].rev()
+
+ parsed_refs[ref] = node
+
+ marks.new_mark(rev, commit_mark)
+
+def parse_reset(parser):
+ ref = parser[1]
+ parser.next()
+ # ugh
+ if parser.check('commit'):
+ parse_commit(parser)
+ return
+ if not parser.check('from'):
+ return
+ from_mark = parser.get_mark()
+ parser.next()
+
+ node = parser.repo.changelog.node(mark_to_rev(from_mark))
+ parsed_refs[ref] = node
+
+def parse_tag(parser):
+ name = parser[1]
+ parser.next()
+ from_mark = parser.get_mark()
+ parser.next()
+ tagger = parser.get_author()
+ parser.next()
+ data = parser.get_data()
+ parser.next()
+
+ # nothing to do
+
+def do_export(parser):
+ global parsed_refs, bmarks
+
+ parser.next()
+
+ for line in parser.each_block('done'):
+ if parser.check('blob'):
+ parse_blob(parser)
+ elif parser.check('commit'):
+ parse_commit(parser)
+ elif parser.check('reset'):
+ parse_reset(parser)
+ elif parser.check('tag'):
+ parse_tag(parser)
+ elif parser.check('feature'):
+ pass
+ else:
+ die('unhandled export command: %s' % line)
+
+ for ref, node in parsed_refs.iteritems():
+ if ref.startswith('refs/heads/branches'):
+ pass
+ elif ref.startswith('refs/heads/'):
+ bmark = ref[len('refs/heads/'):]
+ if bmark in bmarks:
+ old = bmarks[bmark].hex()
+ else:
+ old = ''
+ if not bookmarks.pushbookmark(parser.repo, bmark, old, node):
+ continue
+ elif ref.startswith('refs/tags/'):
+ tag = ref[len('refs/tags/'):]
+ parser.repo.tag([tag], node, None, True, None, {})
+ print "ok %s" % ref
+
+ print
+
def main(args):
- global prefix, dirname, marks, branches, bmarks
+ global prefix, dirname, branches, bmarks
+ global marks, blob_marks, parsed_refs
alias = args[1]
url = args[2]
@@ -362,6 +573,8 @@ def main(args):
dirname = os.path.join(gitdir, 'hg', alias)
branches = {}
bmarks = {}
+ blob_marks = {}
+ parsed_refs = {}
repo = get_repo(url, alias)
prefix = 'refs/hg/%s' % alias
--
1.8.0
^ permalink raw reply related
* [PATCH v6 04/16] remote-hg: add support to push URLs
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index 45629e0..a5023c9 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -9,12 +9,13 @@
# Then you can clone with:
# git clone hg::/path/to/mercurial/repo/
-from mercurial import hg, ui, bookmarks, context
+from mercurial import hg, ui, bookmarks, context, util
import re
import sys
import os
import json
+import shutil
NAME_RE = re.compile('^([^<>]+)')
AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]+)>$')
@@ -574,6 +575,12 @@ def main(args):
url = args[2]
peer = None
+ if alias[4:] == url:
+ is_tmp = True
+ alias = util.sha1(alias).hexdigest()
+ else:
+ is_tmp = False
+
gitdir = os.environ['GIT_DIR']
dirname = os.path.join(gitdir, 'hg', alias)
branches = {}
@@ -604,6 +611,9 @@ def main(args):
die('unhandled command: %s' % line)
sys.stdout.flush()
- marks.store()
+ if not is_tmp:
+ marks.store()
+ else:
+ shutil.rmtree(dirname)
sys.exit(main(sys.argv))
--
1.8.0
^ permalink raw reply related
* [PATCH v6 05/16] remote-hg: make sure the encoding is correct
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Independently of the environment.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index a5023c9..503a9fc 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -9,7 +9,7 @@
# Then you can clone with:
# git clone hg::/path/to/mercurial/repo/
-from mercurial import hg, ui, bookmarks, context, util
+from mercurial import hg, ui, bookmarks, context, util, encoding
import re
import sys
@@ -391,6 +391,9 @@ def do_import(parser):
print "feature export-marks=%s" % path
sys.stdout.flush()
+ tmp = encoding.encoding
+ encoding.encoding = 'utf-8'
+
# lets get all the import lines
while parser.check('import'):
ref = parser[1]
@@ -409,6 +412,8 @@ def do_import(parser):
parser.next()
+ encoding.encoding = tmp
+
print 'done'
def parse_blob(parser):
@@ -491,8 +496,13 @@ def parse_commit(parser):
files.keys(), getfilectx,
user, (date, tz), extra)
+ tmp = encoding.encoding
+ encoding.encoding = 'utf-8'
+
node = repo.commitctx(ctx)
+ encoding.encoding = tmp
+
rev = repo[node].rev()
parsed_refs[ref] = node
--
1.8.0
^ permalink raw reply related
* [PATCH v6 07/16] remote-hg: add support for hg-git compat mode
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 89 +++++++++++++++++++++++++++++++++---
1 file changed, 83 insertions(+), 6 deletions(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index 247b7cb..d585756 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -16,6 +16,22 @@ import sys
import os
import json
import shutil
+import subprocess
+
+#
+# If you want to switch to hg-git compatibility mode:
+# git config --global remote-hg.hg-git-compat true
+#
+# git:
+# Sensible defaults for git.
+# hg bookmarks are exported as git branches, hg branches are prefixed
+# with 'branches/'.
+#
+# hg:
+# Emulate hg-git.
+# Only hg bookmarks are exported as git branches.
+# Commits are modified to preserve hg information and allow biridectionality.
+#
NAME_RE = re.compile('^([^<>]+)')
AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]+)>$')
@@ -226,7 +242,7 @@ def mark_to_rev(mark):
return marks.to_rev(mark)
def export_ref(repo, name, kind, head):
- global prefix, marks
+ global prefix, marks, mode
ename = '%s/%s' % (kind, name)
tip = marks.get_tip(ename)
@@ -261,6 +277,33 @@ def export_ref(repo, name, kind, head):
else:
modified, removed = get_filechanges(repo, c, parents[0])
+ if mode == 'hg':
+ extra_msg = ''
+
+ if rev_branch != 'default':
+ extra_msg += 'branch : %s\n' % rev_branch
+
+ renames = []
+ for f in c.files():
+ if f not in c.manifest():
+ continue
+ rename = c.filectx(f).renamed()
+ if rename:
+ renames.append((rename[0], f))
+
+ for e in renames:
+ extra_msg += "rename : %s => %s\n" % e
+
+ for key, value in extra.iteritems():
+ if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
+ continue
+ else:
+ extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value))
+
+ desc += '\n'
+ if extra_msg:
+ desc += '\n--HG--\n' + extra_msg
+
if len(parents) == 0 and rev:
print 'reset %s/%s' % (prefix, ename)
@@ -354,7 +397,7 @@ def list_head(repo, cur):
g_head = (head, node)
def do_list(parser):
- global branches, bmarks
+ global branches, bmarks, mode
repo = parser.repo
for branch in repo.branchmap():
@@ -368,8 +411,11 @@ def do_list(parser):
cur = repo.dirstate.branch()
list_head(repo, cur)
- for branch in branches:
- print "? refs/heads/branches/%s" % branch
+
+ if mode != 'hg':
+ for branch in branches:
+ print "? refs/heads/branches/%s" % branch
+
for bmark in bmarks:
print "? refs/heads/%s" % bmark
@@ -437,6 +483,7 @@ def get_merge_files(repo, p1, p2, files):
def parse_commit(parser):
global marks, blob_marks, bmarks, parsed_refs
+ global mode
from_mark = merge_mark = None
@@ -482,7 +529,9 @@ def parse_commit(parser):
return of['ctx']
is_exec = of['mode'] == 'x'
is_link = of['mode'] == 'l'
- return context.memfilectx(f, of['data'], is_link, is_exec, None)
+ rename = of.get('rename', None)
+ return context.memfilectx(f, of['data'],
+ is_link, is_exec, rename)
repo = parser.repo
@@ -509,6 +558,21 @@ def parse_commit(parser):
if merge_mark:
get_merge_files(repo, p1, p2, files)
+ if mode == 'hg':
+ i = data.find('\n--HG--\n')
+ if i >= 0:
+ tmp = data[i + len('\n--HG--\n'):].strip()
+ for k, v in [e.split(' : ') for e in tmp.split('\n')]:
+ if k == 'rename':
+ old, new = v.split(' => ', 1)
+ files[new]['rename'] = old
+ elif k == 'branch':
+ extra[k] = v
+ elif k == 'extra':
+ ek, ev = v.split(' : ', 1)
+ extra[ek] = urllib.unquote(ev)
+ data = data[:i]
+
ctx = context.memctx(repo, (p1, p2), data,
files.keys(), getfilectx,
user, (date, tz), extra)
@@ -596,12 +660,25 @@ def do_export(parser):
def main(args):
global prefix, dirname, branches, bmarks
global marks, blob_marks, parsed_refs
- global peer
+ global peer, mode
alias = args[1]
url = args[2]
peer = None
+ cmd = ['git', 'config', '--get', 'remote-hg.hg-git-compat']
+ hg_git_compat = False
+ try:
+ if subprocess.check_output(cmd) == 'true\n':
+ hg_git_compat = True
+ except subprocess.CalledProcessError:
+ pass
+
+ if hg_git_compat:
+ mode = 'hg'
+ else:
+ mode = 'git'
+
if alias[4:] == url:
is_tmp = True
alias = util.sha1(alias).hexdigest()
--
1.8.0
^ permalink raw reply related
* [PATCH v6 06/16] remote-hg: match hg merge behavior
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index 503a9fc..247b7cb 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -427,6 +427,14 @@ def parse_blob(parser):
parser.next()
return
+def get_merge_files(repo, p1, p2, files):
+ for e in repo[p1].files():
+ if e not in files:
+ if e not in repo[p1].manifest():
+ continue
+ f = { 'ctx' : repo[p1][e] }
+ files[e] = f
+
def parse_commit(parser):
global marks, blob_marks, bmarks, parsed_refs
@@ -470,6 +478,8 @@ def parse_commit(parser):
of = files[f]
if 'deleted' in of:
raise IOError
+ if 'ctx' in of:
+ return of['ctx']
is_exec = of['mode'] == 'x'
is_link = of['mode'] == 'l'
return context.memfilectx(f, of['data'], is_link, is_exec, None)
@@ -492,6 +502,13 @@ def parse_commit(parser):
else:
p2 = '\0' * 20
+ #
+ # If files changed from any of the parents, hg wants to know, but in git if
+ # nothing changed from the first parent, nothing changed.
+ #
+ if merge_mark:
+ get_merge_files(repo, p1, p2, files)
+
ctx = context.memctx(repo, (p1, p2), data,
files.keys(), getfilectx,
user, (date, tz), extra)
--
1.8.0
^ permalink raw reply related
* [PATCH v6 08/16] remote-hg: add compat for hg-git author fixes
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 59 ++++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 6 deletions(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index d585756..9db4b7e 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -17,6 +17,7 @@ import os
import json
import shutil
import subprocess
+import urllib
#
# If you want to switch to hg-git compatibility mode:
@@ -35,6 +36,7 @@ import subprocess
NAME_RE = re.compile('^([^<>]+)')
AUTHOR_RE = re.compile('^([^<>]+?)? ?<([^<>]+)>$')
+AUTHOR_HG_RE = re.compile('^(.*?) ?<(.+?)(?:>(.+)?)?$')
RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.+)> (\d+) ([+-]\d+)')
def die(msg, *args):
@@ -152,12 +154,20 @@ class Parser:
return sys.stdin.read(size)
def get_author(self):
+ global bad_mail
+
+ ex = None
m = RAW_AUTHOR_RE.match(self.line)
if not m:
return None
_, name, email, date, tz = m.groups()
+ if name and 'ext:' in name:
+ m = re.match('^(.+?) ext:\((.+)\)$', name)
+ if m:
+ name = m.group(1)
+ ex = urllib.unquote(m.group(2))
- if email != 'unknown':
+ if email != bad_mail:
if name:
user = '%s <%s>' % (name, email)
else:
@@ -165,6 +175,9 @@ class Parser:
else:
user = name
+ if ex:
+ user += ex
+
tz = int(tz)
tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
return (user, int(date), -tz)
@@ -194,9 +207,9 @@ def get_filechanges(repo, ctx, parent):
return added | modified, removed
-def fixup_user(user):
- user = user.replace('"', '')
+def fixup_user_git(user):
name = mail = None
+ user = user.replace('"', '')
m = AUTHOR_RE.match(user)
if m:
name = m.group(1)
@@ -205,11 +218,41 @@ def fixup_user(user):
m = NAME_RE.match(user)
if m:
name = m.group(1).strip()
+ return (name, mail)
+
+def fixup_user_hg(user):
+ def sanitize(name):
+ # stole this from hg-git
+ return re.sub('[<>\n]', '?', name.lstrip('< ').rstrip('> '))
+
+ m = AUTHOR_HG_RE.match(user)
+ if m:
+ name = sanitize(m.group(1))
+ mail = sanitize(m.group(2))
+ ex = m.group(3)
+ if ex:
+ name += ' ext:(' + urllib.quote(ex) + ')'
+ else:
+ name = sanitize(user)
+ if '@' in user:
+ mail = name
+ else:
+ mail = None
+
+ return (name, mail)
+
+def fixup_user(user):
+ global mode, bad_mail
+
+ if mode == 'git':
+ name, mail = fixup_user_git(user)
+ else:
+ name, mail = fixup_user_hg(user)
if not name:
- name = 'Unknown'
+ name = bad_name
if not mail:
- mail = 'unknown'
+ mail = bad_mail
return '%s <%s>' % (name, mail)
@@ -660,7 +703,7 @@ def do_export(parser):
def main(args):
global prefix, dirname, branches, bmarks
global marks, blob_marks, parsed_refs
- global peer, mode
+ global peer, mode, bad_mail, bad_name
alias = args[1]
url = args[2]
@@ -676,8 +719,12 @@ def main(args):
if hg_git_compat:
mode = 'hg'
+ bad_mail = 'none@none'
+ bad_name = ''
else:
mode = 'git'
+ bad_mail = 'unknown'
+ bad_name = 'Unknown'
if alias[4:] == url:
is_tmp = True
--
1.8.0
^ permalink raw reply related
* [PATCH v6 09/16] remote-hg: fake bookmark when there's none
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Or at least no current bookmark.
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/git-remote-hg | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/contrib/remote-helpers/git-remote-hg b/contrib/remote-helpers/git-remote-hg
index 9db4b7e..dbe309a 100755
--- a/contrib/remote-helpers/git-remote-hg
+++ b/contrib/remote-helpers/git-remote-hg
@@ -26,7 +26,7 @@ import urllib
# git:
# Sensible defaults for git.
# hg bookmarks are exported as git branches, hg branches are prefixed
-# with 'branches/'.
+# with 'branches/', HEAD is a special case.
#
# hg:
# Emulate hg-git.
@@ -430,12 +430,21 @@ def get_branch_tip(repo, branch):
return heads[0]
def list_head(repo, cur):
- global g_head
+ global g_head, bmarks
head = bookmarks.readcurrent(repo)
- if not head:
- return
- node = repo[head]
+ if head:
+ node = repo[head]
+ else:
+ # fake bookmark from current branch
+ head = cur
+ node = repo['.']
+ if not node:
+ return
+ if head == 'default':
+ head = 'master'
+ bmarks[head] = node
+
print "@refs/heads/%s HEAD" % head
g_head = (head, node)
--
1.8.0
^ permalink raw reply related
* [PATCH v6 10/16] remote-hg: add basic tests
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
contrib/remote-helpers/Makefile | 13 +++++
contrib/remote-helpers/test-hg.sh | 112 ++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+)
create mode 100644 contrib/remote-helpers/Makefile
create mode 100755 contrib/remote-helpers/test-hg.sh
diff --git a/contrib/remote-helpers/Makefile b/contrib/remote-helpers/Makefile
new file mode 100644
index 0000000..9a76575
--- /dev/null
+++ b/contrib/remote-helpers/Makefile
@@ -0,0 +1,13 @@
+TESTS := $(wildcard test*.sh)
+
+export T := $(addprefix $(CURDIR)/,$(TESTS))
+export MAKE := $(MAKE) -e
+export PATH := $(CURDIR):$(PATH)
+
+test:
+ $(MAKE) -C ../../t $@
+
+$(TESTS):
+ $(MAKE) -C ../../t $(CURDIR)/$@
+
+.PHONY: $(TESTS)
diff --git a/contrib/remote-helpers/test-hg.sh b/contrib/remote-helpers/test-hg.sh
new file mode 100755
index 0000000..40e6e3c
--- /dev/null
+++ b/contrib/remote-helpers/test-hg.sh
@@ -0,0 +1,112 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Felipe Contreras
+#
+# Base commands from hg-git tests:
+# https://bitbucket.org/durin42/hg-git/src
+#
+
+test_description='Test remote-hg'
+
+. ./test-lib.sh
+
+if ! test_have_prereq PYTHON; then
+ skip_all='skipping remote-hg tests; python not available'
+ test_done
+fi
+
+if ! "$PYTHON_PATH" -c 'import mercurial'; then
+ skip_all='skipping remote-hg tests; mercurial not available'
+ test_done
+fi
+
+check () {
+ (cd $1 &&
+ git log --format='%s' -1 &&
+ git symbolic-ref HEAD) > actual &&
+ (echo $2 &&
+ echo "refs/heads/$3") > expected &&
+ test_cmp expected actual
+}
+
+test_expect_success 'cloning' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ hg init hgrepo &&
+ cd hgrepo &&
+ echo zero > content &&
+ hg add content &&
+ hg commit -m zero
+ ) &&
+
+ git clone "hg::$PWD/hgrepo" gitrepo &&
+ check gitrepo zero master
+'
+
+test_expect_success 'cloning with branches' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ cd hgrepo &&
+ hg branch next &&
+ echo next > content &&
+ hg commit -m next
+ ) &&
+
+ git clone "hg::$PWD/hgrepo" gitrepo &&
+ check gitrepo next next &&
+
+ (cd hgrepo && hg checkout default) &&
+
+ git clone "hg::$PWD/hgrepo" gitrepo2 &&
+ check gitrepo2 zero master
+'
+
+test_expect_success 'cloning with bookmarks' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ cd hgrepo &&
+ hg bookmark feature-a &&
+ echo feature-a > content &&
+ hg commit -m feature-a
+ ) &&
+
+ git clone "hg::$PWD/hgrepo" gitrepo &&
+ check gitrepo feature-a feature-a
+'
+
+test_expect_success 'cloning with detached head' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ cd hgrepo &&
+ hg update -r 0
+ ) &&
+
+ git clone "hg::$PWD/hgrepo" gitrepo &&
+ check gitrepo zero master
+'
+
+test_expect_success 'update bookmark' '
+ test_when_finished "rm -rf gitrepo*" &&
+
+ (
+ cd hgrepo &&
+ hg bookmark devel
+ ) &&
+
+ (
+ git clone "hg::$PWD/hgrepo" gitrepo &&
+ cd gitrepo &&
+ git checkout devel &&
+ echo devel > content &&
+ git commit -a -m devel &&
+ git push
+ ) &&
+
+ hg -R hgrepo bookmarks | grep "devel\s\+3:"
+'
+
+test_done
--
1.8.0
^ permalink raw reply related
* [PATCH v6 11/16] test-lib: avoid full path to store test results
From: Felipe Contreras @ 2012-11-04 2:13 UTC (permalink / raw)
To: git
Cc: Junio C Hamano, Jeff King, Sverre Rabbelier, Johannes Schindelin,
Ilari Liusvaara, Daniel Barkalow, Michael J Gruber,
Felipe Contreras
In-Reply-To: <1351995218-19889-1-git-send-email-felipe.contreras@gmail.com>
No reason to use the full path in case this is used externally.
Otherwise we might get errors such as:
./test-lib.sh: line 394: /home/bob/dev/git/t/test-results//home/bob/dev/git/contrib/remote-hg/test-2894.counts: No such file or directory
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
t/test-lib.sh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 514282c..5a3d665 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -389,7 +389,8 @@ test_done () {
then
test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results"
mkdir -p "$test_results_dir"
- test_results_path="$test_results_dir/${0%.sh}-$$.counts"
+ base=${0##*/}
+ test_results_path="$test_results_dir/${base%.sh}-$$.counts"
cat >>"$test_results_path" <<-EOF
total $test_count
--
1.8.0
^ 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