git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] git --trace: trace command execution
@ 2006-06-25 10:57 Matthias Lederhofer
  2006-06-25 11:50 ` Junio C Hamano
  0 siblings, 1 reply; 10+ messages in thread
From: Matthias Lederhofer @ 2006-06-25 10:57 UTC (permalink / raw)
  To: git

Show parameters to execve/builtin-cmds before executing them. This
version does not yet have a parameter --trace to git to enable this I
just want to get feedback first :)

I think this is quite useful to debug what is going on since a command
may be another program (shell/python/perl/.. script etc) or just an
alias for a internal command. Before that many commands became
built-ins this was quite easy to do with strace.

Example:
% git repo-config alias.showtag
trace: exec: /home/matled/local/stow/git/bin/git-repo-config
alias.showtag
% git showtag v1.4.1-rc1 > /dev/null
trace: exec: /home/matled/local/stow/git/bin/git-showtag v1.4.1-rc1
trace: exec failed: No such file or directory
trace: built-in command: git cat-file tag v1.4.1-rc1
% git showtag 'a b "c" `d` $e \f'
trace: exec: /home/matled/local/stow/git/bin/git-showtag "a b \"c\" \`d\` \$e \\f"
trace: exec failed: No such file or directory
trace: built-in command: git cat-file tag "a b \"c\" \`d\` \$e \\f"
fatal: Not a valid object name a b "c" `d` $e \f
% git cat-file tag "a b \"c\" \`d\` \$e \\f"
trace: built-in command: git cat-file tag "a b \"c\" \`d\` \$e \\f"
fatal: Not a valid object name a b "c" `d` $e \f

print_shell_escape will escape the arguments to be used as strings in
the shell to prevent ambiguity with spaces and other special
characters and make them copy-and-pastable.

---
 exec_cmd.c |   42 ++++++++++++++++++++++++++++++++++++++++++
 exec_cmd.h |    1 +
 git.c      |   10 ++++++++++
 3 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/exec_cmd.c b/exec_cmd.c
index c1539d1..85afbf3 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -87,6 +87,16 @@ int execv_git_cmd(const char **argv)
 			break;
 		}
 
+		fprintf(stderr, "trace: exec: ");
+		print_shell_escape(stderr, git_command);
+		const char **p = argv;
+		while (*(++p)) {
+			putc(' ', stderr);
+			print_shell_escape(stderr, *p);
+		}
+		putc('\n', stderr);
+		fflush(stderr);
+
 		/* argv[0] must be the git command, but the argv array
 		 * belongs to the caller, and my be reused in
 		 * subsequent loop iterations. Save argv[0] and
@@ -98,6 +108,8 @@ int execv_git_cmd(const char **argv)
 
 		/* execve() can only ever return if it fails */
 		execve(git_command, (char **)argv, environ);
+		fprintf(stderr, "trace: exec failed: %s\n", strerror(errno));
+		fflush(stderr);
 
 		argv[0] = tmp;
 	}
@@ -128,3 +140,33 @@ int execl_git_cmd(const char *cmd,...)
 	argv[argc] = NULL;
 	return execv_git_cmd(argv);
 }
+
+void print_shell_escape(FILE *stream, const char *s)
+{
+	const char *c = s;
+	short int quote = 0;
+	while (*c) {
+		if (*c == '"' || *c == '`' || *c == '$' || *c == '\\' ||
+			isspace(*c))
+		{
+			quote = 1;
+			break;
+		}
+		++c;
+	}
+
+	if (!quote) {
+		fputs(s, stream);
+		return;
+	}
+
+	putc('"', stream);
+	c = s;
+	while (*c) {
+		if (*c == '"' || *c == '`' || *c == '$' || *c == '\\')
+			putc('\\', stream);
+		putc(*c, stream);
+		++c;
+	}
+	putc('"', stream);
+}
diff --git a/exec_cmd.h b/exec_cmd.h
index 989621f..8b237fa 100644
--- a/exec_cmd.h
+++ b/exec_cmd.h
@@ -5,6 +5,7 @@ extern void git_set_exec_path(const char
 extern const char* git_exec_path(void);
 extern int execv_git_cmd(const char **argv); /* NULL terminated */
 extern int execl_git_cmd(const char *cmd, ...);
+extern void print_shell_escape(FILE *stream, const char *s);
 
 
 #endif /* __GIT_EXEC_CMD_H_ */
diff --git a/git.c b/git.c
index 94e9a4a..361fb25 100644
--- a/git.c
+++ b/git.c
@@ -198,6 +198,16 @@ static void handle_internal_command(int 
 		struct cmd_struct *p = commands+i;
 		if (strcmp(p->cmd, cmd))
 			continue;
+
+		fprintf(stderr, "trace: built-in command: git");
+		int i;
+		for (i = 0; i < argc; ++i) {
+			putc(' ', stderr);
+			print_shell_escape(stderr, argv[i]);
+		}
+		putc('\n', stderr);
+		fflush(stderr);
+
 		exit(p->fn(argc, argv, envp));
 	}
 }
-- 
1.4.GIT

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC] git --trace: trace command execution
  2006-06-25 10:57 [RFC] git --trace: trace command execution Matthias Lederhofer
@ 2006-06-25 11:50 ` Junio C Hamano
  2006-06-25 12:51   ` Matthias Lederhofer
                     ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Junio C Hamano @ 2006-06-25 11:50 UTC (permalink / raw)
  To: Matthias Lederhofer; +Cc: git

Matthias Lederhofer <matled@gmx.net> writes:

> Show parameters to execve/builtin-cmds before executing them. This
> version does not yet have a parameter --trace to git to enable this I
> just want to get feedback first :)
>
> I think this is quite useful to debug what is going on since a command
> may be another program (shell/python/perl/.. script etc) or just an
> alias for a internal command. Before that many commands became
> built-ins this was quite easy to do with strace.

Interesting.  Debugging one's alias entries would be helped with
this I would imagine, and for that you would want something like
this:

> Example:
> % git showtag v1.4.1-rc1 > /dev/null
> trace: exec: /home/matled/local/stow/git/bin/git-showtag v1.4.1-rc1
> trace: exec failed: No such file or directory
* trace: expanded alias "showtag" => "cat-file tag"
> trace: built-in command: git cat-file tag v1.4.1-rc1

By the way "git cat-file -p" or "git verify-tag -v" might be
more pleasant to view a tag since they make the tagger timestamp
human readable.

> print_shell_escape will escape the arguments to be used as strings in
> the shell to prevent ambiguity with spaces and other special
> characters and make them copy-and-pastable.

Might be worth reusing quote.c::sq_quote(), perhaps?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] git --trace: trace command execution
  2006-06-25 11:50 ` Junio C Hamano
@ 2006-06-25 12:51   ` Matthias Lederhofer
  2006-06-25 13:56   ` [PATCH] GIT_TRACE: show which built-in/external commands are executed Matthias Lederhofer
  2006-06-29 18:06   ` [RFC] git --trace: trace command execution Jakub Narebski
  2 siblings, 0 replies; 10+ messages in thread
From: Matthias Lederhofer @ 2006-06-25 12:51 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

> Interesting.  Debugging one's alias entries would be helped with
> this I would imagine, and for that you would want something like
> this:
> 
> > Example:
> > % git showtag v1.4.1-rc1 > /dev/null
> > trace: exec: /home/matled/local/stow/git/bin/git-showtag v1.4.1-rc1
> > trace: exec failed: No such file or directory
> * trace: expanded alias "showtag" => "cat-file tag"
That's a good idea, I'll integrate that.

> By the way "git cat-file -p" or "git verify-tag -v" might be
> more pleasant to view a tag since they make the tagger timestamp
> human readable.
Ok, yesterday I was searching for something to see the annotation of a
tag. verify-tag -v looks quite much like that, is there any other way
to read this? Or in general: how do I work with tags? I want to build
a version tagged as v1.2 so currently I'll do
> git checkout -b 1.2 v1.2
and built it. But then I've to type the version number twice (typing
it once is annoying enough :)) and I've to type it once more to get
the tag annotation.

> Might be worth reusing quote.c::sq_quote(), perhaps?
Oh, sure, did not know about this. This would result in a loop of
malloc'ing memory for the buffer. Is this ok? Or should I add a
function like sq_quote which takes a stream and writes to it?

So for the --trace part I think an environment variable GIT_TRACE is
more suitable for this because children inherit this. So running git
status will show what internal commands the shell script uses.
Otherwise I see no way to pass the --trace option down because an
extern program like git-status, git-annotate etc will not accept
parameters which can be passed to `git'.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] GIT_TRACE: show which built-in/external commands are executed
  2006-06-25 11:50 ` Junio C Hamano
  2006-06-25 12:51   ` Matthias Lederhofer
@ 2006-06-25 13:56   ` Matthias Lederhofer
  2006-06-25 14:11     ` Johannes Schindelin
  2006-06-29 18:06   ` [RFC] git --trace: trace command execution Jakub Narebski
  2 siblings, 1 reply; 10+ messages in thread
From: Matthias Lederhofer @ 2006-06-25 13:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

With the environment variable GIT_TRACE set git will show
 - alias expansion
 - built-in command execution
 - external command execution
on stderr.

Signed-off-by: Matthias Lederhofer <matled@gmx.net>
---
Examples:
% GIT_TRACE=1 git status > /dev/null
trace: exec: '/home/matled/local/stow/git/bin/git-status'
trace: built-in: git 'rev-parse' '--git-dir'
trace: built-in: git 'rev-parse' '--show-cdup'
trace: built-in: git 'update-index' '-q' '--unmerged' '--refresh'
trace: built-in: git 'diff-index' '-M' '--cached' '--name-status' \
    '--diff-filter=MDTCRA' 'HEAD'
trace: built-in: git 'diff-files' '--name-status'
trace: built-in: git 'ls-files' '-z' '--others' '--directory' \
    '--no-empty-directory' '--exclude-from=.git/info/exclude' \
    '--exclude-per-directory=.gitignore'

This seems to be quite useful to find out how tools do things and for
debugging.

% GIT_TRACE=1 git showtag v1.4.0 > /dev/null
trace: exec: '/home/matled/local/stow/git/bin/git-showtag' 'v1.4.0'
trace: exec failed: No such file or directory
trace: alias expansion: showtag => 'cat-file' 'tag'
trace: built-in: git 'cat-file' 'tag' 'v1.4.0'

% GIT_TRACE=1 git l > /dev/null
trace: exec: '/home/matled/local/stow/git/bin/git-l'
trace: exec failed: No such file or directory
trace: alias expansion: l => 'log' '-p'
trace: built-in: git 'log' '-p'

 Documentation/git.txt |    7 +++++++
 exec_cmd.c            |   19 +++++++++++++++++++
 git.c                 |   25 +++++++++++++++++++++++++
 quote.c               |   17 +++++++++++++++++
 quote.h               |    1 +
 5 files changed, 69 insertions(+), 0 deletions(-)

diff --git a/Documentation/git.txt b/Documentation/git.txt
index 51f20c6..603c474 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -615,6 +615,13 @@ git Diffs
 	gitlink:git-diff-files[1];
 	gitlink:git-diff-tree[1]
 
+other
+~~~~~
+'GIT_TRACE'::
+	If this variable is set git will print `trace:` messages on
+	stderr telling about alias expansion, built-in command
+	execution and external command execution.
+
 Discussion[[Discussion]]
 ------------------------
 include::README[]
diff --git a/exec_cmd.c b/exec_cmd.c
index c1539d1..f2133ec 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "exec_cmd.h"
+#include "quote.h"
 #define MAX_ARGS	32
 
 extern char **environ;
@@ -96,9 +97,27 @@ int execv_git_cmd(const char **argv)
 		tmp = argv[0];
 		argv[0] = git_command;
 
+		if (getenv("GIT_TRACE")) {
+			fputs("trace: exec:", stderr);
+			const char **p = argv;
+			while (*p) {
+				fputc(' ', stderr);
+				sq_quote_print(stderr, *p);
+				++p;
+			}
+			putc('\n', stderr);
+			fflush(stderr);
+		}
+
 		/* execve() can only ever return if it fails */
 		execve(git_command, (char **)argv, environ);
 
+		if (getenv("GIT_TRACE")) {
+			fprintf(stderr, "trace: exec failed: %s\n",
+				strerror(errno));
+			fflush(stderr);
+		}
+
 		argv[0] = tmp;
 	}
 	return -1;
diff --git a/git.c b/git.c
index 94e9a4a..8b060e8 100644
--- a/git.c
+++ b/git.c
@@ -11,6 +11,7 @@ #include <stdarg.h>
 #include "git-compat-util.h"
 #include "exec_cmd.h"
 #include "cache.h"
+#include "quote.h"
 
 #include "builtin.h"
 
@@ -119,6 +120,18 @@ static int handle_alias(int *argcp, cons
 			if (!strcmp(alias_command, new_argv[0]))
 				die("recursive alias: %s", alias_command);
 
+			if (getenv("GIT_TRACE")) {
+				int i;
+				fprintf(stderr, "trace: alias expansion: %s =>",
+					alias_command);
+				for (i = 0; i < count; ++i) {
+					fputc(' ', stderr);
+					sq_quote_print(stderr, new_argv[i]);
+				}
+				fputc('\n', stderr);
+				fflush(stderr);
+			}
+
 			/* insert after command name */
 			if (*argcp > 1) {
 				new_argv = realloc(new_argv, sizeof(char*) *
@@ -198,6 +211,18 @@ static void handle_internal_command(int 
 		struct cmd_struct *p = commands+i;
 		if (strcmp(p->cmd, cmd))
 			continue;
+
+		if (getenv("GIT_TRACE")) {
+			int i;
+			fprintf(stderr, "trace: built-in: git");
+			for (i = 0; i < argc; ++i) {
+				fputc(' ', stderr);
+				sq_quote_print(stderr, argv[i]);
+			}
+			putc('\n', stderr);
+			fflush(stderr);
+		}
+
 		exit(p->fn(argc, argv, envp));
 	}
 }
diff --git a/quote.c b/quote.c
index dcc2326..2ca18e8 100644
--- a/quote.c
+++ b/quote.c
@@ -45,6 +45,23 @@ size_t sq_quote_buf(char *dst, size_t n,
 	return len;
 }
 
+void sq_quote_print(FILE *stream, const char *src)
+{
+	char c;
+
+	fputc('\'', stream);
+	while ((c = *src++)) {
+		if (need_bs_quote(c)) {
+			fputs("'\\", stream);
+			fputc(c, stream);
+			fputc('\'', stream);
+		} else {
+			fputc(c, stream);
+		}
+	}
+	fputc('\'', stream);
+}
+
 char *sq_quote(const char *src)
 {
 	char *buf;
diff --git a/quote.h b/quote.h
index c1ab378..fc5481e 100644
--- a/quote.h
+++ b/quote.h
@@ -29,6 +29,7 @@ #include <stdio.h>
  */
 
 extern char *sq_quote(const char *src);
+extern void sq_quote_print(FILE *stream, const char *src);
 extern size_t sq_quote_buf(char *dst, size_t n, const char *src);
 
 /* This unwraps what sq_quote() produces in place, but returns
-- 
1.4.1.rc1.gfa6c9-dirty

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] GIT_TRACE: show which built-in/external commands are executed
  2006-06-25 13:56   ` [PATCH] GIT_TRACE: show which built-in/external commands are executed Matthias Lederhofer
@ 2006-06-25 14:11     ` Johannes Schindelin
  2006-06-25 14:22       ` Petr Baudis
  2006-06-25 16:10       ` Matthias Lederhofer
  0 siblings, 2 replies; 10+ messages in thread
From: Johannes Schindelin @ 2006-06-25 14:11 UTC (permalink / raw)
  To: Matthias Lederhofer; +Cc: Junio C Hamano, git

Hi,

On Sun, 25 Jun 2006, Matthias Lederhofer wrote:

> With the environment variable GIT_TRACE set git will show
>  - alias expansion
>  - built-in command execution
>  - external command execution
> on stderr.

Nice.

Ciao,
Dscho

P.S.: Now we only have to convert all "git-" invocations in the scripts to
"git " invocations so we can benefit from it. But that would mean two 
forks instead of one for the non-builtins. Hmm.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] GIT_TRACE: show which built-in/external commands are executed
  2006-06-25 14:11     ` Johannes Schindelin
@ 2006-06-25 14:22       ` Petr Baudis
  2006-06-25 16:10       ` Matthias Lederhofer
  1 sibling, 0 replies; 10+ messages in thread
From: Petr Baudis @ 2006-06-25 14:22 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Matthias Lederhofer, Junio C Hamano, git

  Hi,

Dear diary, on Sun, Jun 25, 2006 at 04:11:48PM CEST, I got a letter
where Johannes Schindelin <Johannes.Schindelin@gmx.de> said that...
> P.S.: Now we only have to convert all "git-" invocations in the scripts to
> "git " invocations so we can benefit from it. But that would mean two 
> forks instead of one for the non-builtins. Hmm.

  actually this is a myth - not two fork()s since 'git' has no reason to
fork; only two execve()s in line after a single fork().

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
A person is just about as big as the things that make them angry.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] GIT_TRACE: show which built-in/external commands are executed
  2006-06-25 14:11     ` Johannes Schindelin
  2006-06-25 14:22       ` Petr Baudis
@ 2006-06-25 16:10       ` Matthias Lederhofer
  2006-06-25 23:30         ` Johannes Schindelin
  1 sibling, 1 reply; 10+ messages in thread
From: Matthias Lederhofer @ 2006-06-25 16:10 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

> Hi,
> 
> On Sun, 25 Jun 2006, Matthias Lederhofer wrote:
> 
> > With the environment variable GIT_TRACE set git will show
> >  - alias expansion
> >  - built-in command execution
> >  - external command execution
> > on stderr.
> 
> Nice.
Thanks :)

> P.S.: Now we only have to convert all "git-" invocations in the scripts to
> "git " invocations so we can benefit from it. But that would mean two 
> forks instead of one for the non-builtins. Hmm.

Why do we not use this policy:

git-* is guaranteed to be the normal command without any strange alias
expansion, default parameters or something else a script does not like
to be changed in the commands. So all scripts use git-*, this will
prevent a double exec. The path to git-* should be obtained using git
--exec-path in the beginnig.

git <command> is to be used by the user if he wants aliases, default
parameters and other fancy stuff.

Using this policy the user can always get the normal behaviour and it
is possible to shadown built-in commands etc.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] GIT_TRACE: show which built-in/external commands are executed
  2006-06-25 16:10       ` Matthias Lederhofer
@ 2006-06-25 23:30         ` Johannes Schindelin
  2006-06-28 18:22           ` Matthias Lederhofer
  0 siblings, 1 reply; 10+ messages in thread
From: Johannes Schindelin @ 2006-06-25 23:30 UTC (permalink / raw)
  To: Matthias Lederhofer; +Cc: git

Hi,

On Sun, 25 Jun 2006, Matthias Lederhofer wrote:

> > P.S.: Now we only have to convert all "git-" invocations in the scripts to
> > "git " invocations so we can benefit from it. But that would mean two 
> > forks instead of one for the non-builtins. Hmm.
> 
> Why do we not use this policy:
> 
> git-* is guaranteed to be the normal command without any strange alias
> expansion, default parameters or something else a script does not like
> to be changed in the commands. So all scripts use git-*, this will
> prevent a double exec. The path to git-* should be obtained using git
> --exec-path in the beginnig.

That still leaves my problem: GIT_TRACE=1 on scripts is incomplete.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] GIT_TRACE: show which built-in/external commands are executed
  2006-06-25 23:30         ` Johannes Schindelin
@ 2006-06-28 18:22           ` Matthias Lederhofer
  0 siblings, 0 replies; 10+ messages in thread
From: Matthias Lederhofer @ 2006-06-28 18:22 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

> That still leaves my problem: GIT_TRACE=1 on scripts is incomplete.
Ok, I see what you mean.

This actually affects all scripts which are called as git-foo instead
of git foo (but built-in commands show up anyway). So I'd add a
warning to the documentation in which cases GIT_TRACE will not show
that a command is executed.
In the git repository I found 47 shell scripts (git-* without the
header file) which would be affected. Searching for all occurences of
git-(one of those shell-scripts) I found 50 lines of code which use
it. If there is any interest in changing this I can try to change
this.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] git --trace: trace command execution
  2006-06-25 11:50 ` Junio C Hamano
  2006-06-25 12:51   ` Matthias Lederhofer
  2006-06-25 13:56   ` [PATCH] GIT_TRACE: show which built-in/external commands are executed Matthias Lederhofer
@ 2006-06-29 18:06   ` Jakub Narebski
  2 siblings, 0 replies; 10+ messages in thread
From: Jakub Narebski @ 2006-06-29 18:06 UTC (permalink / raw)
  To: git

Junio C Hamano wrote:

> By the way "git cat-file -p" or "git verify-tag -v" might be
> more pleasant to view a tag since they make the tagger timestamp
> human readable.

Interesting, -p makes tagger timestamp human readable, but not author or
commiter:

$ git cat-file -p `cat .git/refs/tags/v1.4.0`
tagger Junio C Hamano <junkio@cox.net> Sat Jun 10 12:43:37 2006 -0700

$ git cat-file -p `cat .git/refs/heads/origin`
author Johannes Schindelin <Johannes.Schindelin@gmx.de> 1151491527 +0200
committer Junio C Hamano <junkio@cox.net> 1151492136 -0700

Is it intended, or a bug/missing feature (git 1.4.0)?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2006-06-29 18:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-06-25 10:57 [RFC] git --trace: trace command execution Matthias Lederhofer
2006-06-25 11:50 ` Junio C Hamano
2006-06-25 12:51   ` Matthias Lederhofer
2006-06-25 13:56   ` [PATCH] GIT_TRACE: show which built-in/external commands are executed Matthias Lederhofer
2006-06-25 14:11     ` Johannes Schindelin
2006-06-25 14:22       ` Petr Baudis
2006-06-25 16:10       ` Matthias Lederhofer
2006-06-25 23:30         ` Johannes Schindelin
2006-06-28 18:22           ` Matthias Lederhofer
2006-06-29 18:06   ` [RFC] git --trace: trace command execution Jakub Narebski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).