* Re: General support for ! in git-config values
From: Junio C Hamano @ 2012-02-03 6:11 UTC (permalink / raw)
To: Kyle Moffett
Cc: demerphq, Jeff King, Ævar Arnfjörð,
Git Mailing List
In-Reply-To: <CAGZ=bq++R+X+2r2_zQ4UZ6JvDC9W9_4nF23MQ6+612_Qe2RS4Q@mail.gmail.com>
Kyle Moffett <kyle@moffetthome.net> writes:
> Alternatively, you could extend the recent proposal for GIT config
> "include" statements so that something like this works:
>
> [include]
> exec = echo "deploy.prefix = `cat /etc/SERVER_ROLE`"
> exec = /usr/local/bin/git-config-for-ldap-user
Erh...
Running known stuff from your own .git/config may be justifiable as "at
your own risk", but if we consider sources that are not under your direct
control, such as /etc/gitconfig and whatever your project encourages you
to include from your .git/config,... eek.
^ permalink raw reply
* Re: General support for ! in git-config values
From: Kyle Moffett @ 2012-02-03 7:35 UTC (permalink / raw)
To: Junio C Hamano
Cc: demerphq, Jeff King, Ævar Arnfjörð,
Git Mailing List
In-Reply-To: <7vmx90say8.fsf@alter.siamese.dyndns.org>
On Thu, Feb 2, 2012 at 22:11, Junio C Hamano <gitster@pobox.com> wrote:
> Kyle Moffett <kyle@moffetthome.net> writes:
>
>> Alternatively, you could extend the recent proposal for GIT config
>> "include" statements so that something like this works:
>>
>> [include]
>> exec = echo "deploy.prefix = `cat /etc/SERVER_ROLE`"
>> exec = /usr/local/bin/git-config-for-ldap-user
>
> Erh...
>
> Running known stuff from your own .git/config may be justifiable as "at
> your own risk", but if we consider sources that are not under your direct
> control, such as /etc/gitconfig and whatever your project encourages you
> to include from your .git/config,... eek.
Well yes, but running commands from .git/config is exactly what the OP
requested, and if it applies to .git/config it should also be
applicable to other trusted include sources too, no?
Perhaps allow config files to perform a "trusted" include, EG:
[include]
trusted_exec = /usr/local/bin/site-specific-config-program
blob = v1.0:src/gitconfig
By default, the only files which would be trusted are /etc/gitconfig,
~/.gitconfig, and .git/config (but ONLY if it has the same owner and
mode go-w), and they would only pass trust on to other files if they
use "trusted_*" include lines.
Also, since "include" is intended to introduce a
non-backwards-compatible change in behavior, perhaps a totally
different format should be used, EG:
$include exec_trusted /usr/local/bin/site-specific-config-program
$include blob v1.0:src/gitconfig
Something that would cause noticeable warnings in older versions of
git instead of silently ignoring the desired config includes.
Just a few thoughts.
Cheers,
Kyle Moffett
^ permalink raw reply
* Re: [PATCH/RFC (version B)] gitweb: Allow UTF-8 encoded CGI query parameters and path_info
From: Michal Kiedrowicz @ 2012-02-03 7:39 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <201202022357.29569.jnareb@gmail.com>
Jakub Narebski <jnareb@gmail.com> wrote:
> On Thu, 2 Feb 2012, Jakub Narebski wrote:
> > On Thu, 2 Feb 2012, Michał Kiedrowicz wrote:
> > > Jakub Narebski <jnareb@gmail.com> wrote:
> > >
> > > > Gitweb tries hard to properly process UTF-8 data, by marking
> > > > output from git commands and contents of files as UTF-8 with
> > > > to_utf8() subroutine. This ensures that gitweb would print
> > > > correctly UTF-8 e.g. in 'log' and 'commit' views.
> > > >
> > > > Unfortunately it misses another source of potentially Unicode
> > > > input, namely query parameters. The result is that one cannot
> > > > search for a string containing characters outside US-ASCII.
> > > > For example searching for "Michał Kiedrowicz" (containing
> > > > letter 'ł' - LATIN SMALL LETTER L WITH STROKE, with Unicode
> > > > codepoint U+0142, represented with 0xc5 0x82 bytes in UTF-8 and
> > > > percent-encoded as %C5%81) result in the following incorrect
> > > > data in search field
> > > >
> > > > MichaÅ Kiedrowicz
> > > >
> > > > This is caused by CGI by default treating '0xc5 0x82' bytes as
> > > > two characters in Perl legacy encoding latin-1 (iso-8859-1),
> > > > because 's' query parameter is not processed explicitly as
> > > > UTF-8 encoded string.
> > > >
> > > > The solution used here follows "Using Unicode in a Perl CGI
> > > > script" article on
> > > > http://www.lemoda.net/cgi/perl-unicode/index.html:
> > > >
> > > > use CGI;
> > > > use Encode 'decode_utf8;
> > > > my $value = params('input');
> > > > $value = decode_utf8($value);
> > > >
> > > > This is done when filling %input_params hash; this required to
> > > > move from explicit $cgi->param(<label>) to
> > > > $input_params{<name>} in a few places.
> > >
> > > I'm sorry but this doesn't work for me. I would be happy to help
> > > if you have some questions about it.
> >
> > Strange. http://www.lemoda.net/cgi/perl-unicode/index.html says
> > that those two approaches should be equivalent. The -utf8 pragma
> > version doesn't work for me at all, while this one works in that if
> > finds what it is supposed to, but shows garbage in search form.
>
> Is it what you mean by "this doesn't work for me", i.e. working
> search, garbage in search field?
I mean "garbage in search field". Search works even without the patch
(at least on Debian with git-1.7.7.3, perl-5.10.1 and CGI-3.43; I
don't have my notebook nearby at the moment to check).
>
> > Will investigate.
Thanks for your time spending on this. I wouldn't call this problem
"production critial" but it seems wrong to support UTF-8 everywhere
properly except for one place.
>
> Damn. If we use $cgi->textfield(-name => "s", -value => $searchtext)
> like in gitweb, CGI.pm would read $cgi->param("s") by itself -
> without decoding.
Makes sense. When I tried calling to_utf8() in the line that defines
textfield (this was my first approach to this problem), it haven't
changed anything.
> To skip this we need to pass -force=>1 or
> -override=>1 (i.e. further changes to gitweb).
>
> -utf8 pragma works with more modern CGI.pm, but does not with 3.10.
>
^ permalink raw reply
* [PATCH] Convert isatty() calls to git_isatty()
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 8:35 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
isatty() is used to check for interactive use cases. However if pager is
set up, standard file handles may be redirected and istty() calls later
on no longer reflect the original state.
Convert isatty() calls to git_isatty() and allow git_isatty() to cache
tty info before pager is set up.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
builtin/commit.c | 2 +-
builtin/fsck.c | 2 +-
builtin/merge.c | 4 ++--
builtin/pack-objects.c | 2 +-
builtin/pack-redundant.c | 2 +-
builtin/prune-packed.c | 2 +-
builtin/prune.c | 2 +-
builtin/revert.c | 2 +-
builtin/shortlog.c | 4 ++--
builtin/unpack-objects.c | 2 +-
cache.h | 1 +
color.c | 2 +-
| 17 +++++++++++++++++
transport.c | 4 ++--
14 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/builtin/commit.c b/builtin/commit.c
index eba1377..cc72f13 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -672,7 +672,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
strbuf_addbuf(&sb, &message);
hook_arg1 = "message";
} else if (logfile && !strcmp(logfile, "-")) {
- if (isatty(0))
+ if (git_isatty(0))
fprintf(stderr, _("(reading log message from standard input)\n"));
if (strbuf_read(&sb, 0, 0) < 0)
die_errno(_("could not read log from standard input"));
diff --git a/builtin/fsck.c b/builtin/fsck.c
index 8c479a7..0b4e8cf 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -637,7 +637,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
if (show_progress == -1)
- show_progress = isatty(2);
+ show_progress = git_isatty(2);
if (verbose)
show_progress = 0;
diff --git a/builtin/merge.c b/builtin/merge.c
index 62c7b68..49b9176 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -714,7 +714,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
o.renormalize = option_renormalize;
o.show_rename_progress =
- show_progress == -1 ? isatty(2) : show_progress;
+ show_progress == -1 ? git_isatty(2) : show_progress;
for (x = 0; x < xopts_nr; x++)
if (parse_merge_opt(&o, xopts[x]))
@@ -1129,7 +1129,7 @@ static int default_edit_option(void)
/* Use editor if stdin and stdout are the same and is a tty */
return (!fstat(0, &st_stdin) &&
!fstat(1, &st_stdout) &&
- isatty(0) &&
+ git_isatty(0) &&
st_stdin.st_dev == st_stdout.st_dev &&
st_stdin.st_ino == st_stdout.st_ino &&
st_stdin.st_mode == st_stdout.st_mode);
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0f2e7b8..4468c84 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2328,7 +2328,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!pack_compression_seen && core_compression_seen)
pack_compression_level = core_compression_level;
- progress = isatty(2);
+ progress = git_isatty(2);
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index f5c6afc..8197c9e 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -646,7 +646,7 @@ int cmd_pack_redundant(int argc, const char **argv, const char *prefix)
/* ignore objects given on stdin */
llist_init(&ignore);
- if (!isatty(0)) {
+ if (!git_isatty(0)) {
while (fgets(buf, sizeof(buf), stdin)) {
sha1 = xmalloc(20);
if (get_sha1_hex(buf, sha1))
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
index f9463de..498c6e9 100644
--- a/builtin/prune-packed.c
+++ b/builtin/prune-packed.c
@@ -71,7 +71,7 @@ void prune_packed_objects(int opts)
int cmd_prune_packed(int argc, const char **argv, const char *prefix)
{
- int opts = isatty(2) ? VERBOSE : 0;
+ int opts = git_isatty(2) ? VERBOSE : 0;
const struct option prune_packed_options[] = {
OPT_BIT('n', "dry-run", &opts, "dry run", DRY_RUN),
OPT_NEGBIT('q', "quiet", &opts, "be quiet", VERBOSE),
diff --git a/builtin/prune.c b/builtin/prune.c
index 58d7cb8..821772e 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -158,7 +158,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
}
if (show_progress == -1)
- show_progress = isatty(2);
+ show_progress = git_isatty(2);
if (show_progress)
progress = start_progress_delay("Checking connectivity", 0, 0, 2);
diff --git a/builtin/revert.c b/builtin/revert.c
index e6840f2..6f87c9b 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -199,7 +199,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
int res;
memset(&opts, 0, sizeof(opts));
- if (isatty(0))
+ if (git_isatty(0))
opts.edit = 1;
opts.action = REPLAY_REVERT;
git_config(git_default_config, NULL);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 37f3193..c77b472 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -289,10 +289,10 @@ parse_done:
log.abbrev = rev.abbrev;
/* assume HEAD if from a tty */
- if (!nongit && !rev.pending.nr && isatty(0))
+ if (!nongit && !rev.pending.nr && git_isatty(0))
add_head_to_pending(&rev);
if (rev.pending.nr == 0) {
- if (isatty(0))
+ if (git_isatty(0))
fprintf(stderr, _("(reading log message from standard input)\n"));
read_from_stdin(&log);
}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 14e04e6..4aaba69 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -501,7 +501,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
- quiet = !isatty(2);
+ quiet = !git_isatty(2);
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];
diff --git a/cache.h b/cache.h
index 9bd8c2d..4073fc9 100644
--- a/cache.h
+++ b/cache.h
@@ -1176,6 +1176,7 @@ extern void setup_pager(void);
extern const char *pager_program;
extern int pager_in_use(void);
extern int pager_use_color;
+extern int git_isatty(int);
extern const char *editor_program;
extern const char *askpass_program;
diff --git a/color.c b/color.c
index e8e2681..7151b48 100644
--- a/color.c
+++ b/color.c
@@ -183,7 +183,7 @@ int git_config_colorbool(const char *var, const char *value)
static int check_auto_color(void)
{
if (color_stdout_is_tty < 0)
- color_stdout_is_tty = isatty(1);
+ color_stdout_is_tty = git_isatty(1);
if (color_stdout_is_tty || (pager_in_use() && pager_use_color)) {
char *term = getenv("TERM");
if (term && strcmp(term, "dumb"))
--git a/pager.c b/pager.c
index 975955b..a9380ab 100644
--- a/pager.c
+++ b/pager.c
@@ -72,12 +72,17 @@ const char *git_pager(int stdout_is_tty)
void setup_pager(void)
{
const char *pager = git_pager(isatty(1));
+ int i;
if (!pager)
return;
setenv("GIT_PAGER_IN_USE", "true", 1);
+ /* cache tty info */
+ for (i = 0; i <= 2; i++)
+ git_isatty(i);
+
/* spawn the pager */
pager_argv[0] = pager;
pager_process.use_shell = 1;
@@ -110,3 +115,15 @@ int pager_in_use(void)
env = getenv("GIT_PAGER_IN_USE");
return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
}
+
+int git_isatty(int fd)
+{
+ static int tty[3] = { -1, -1, -1 };
+
+ if (fd < 0 || fd > 2)
+ return isatty(fd);
+
+ if (tty[fd] == -1)
+ tty[fd] = isatty(fd);
+ return tty[fd];
+}
diff --git a/transport.c b/transport.c
index cac0c06..af48f7c 100644
--- a/transport.c
+++ b/transport.c
@@ -880,7 +880,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
const char *helper;
struct transport *ret = xcalloc(1, sizeof(*ret));
- ret->progress = isatty(2);
+ ret->progress = git_isatty(2);
if (!remote)
die("No remote provided to transport_get()");
@@ -997,7 +997,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity,
* 2. Don't report progress, if verbosity < 0 (ie. -q/--quiet ).
* 3. Report progress if isatty(2) is 1.
**/
- transport->progress = force_progress || (verbosity >= 0 && isatty(2));
+ transport->progress = force_progress || (verbosity >= 0 && git_isatty(2));
}
int transport_push(struct transport *transport,
--
1.7.8.36.g69ee2
^ permalink raw reply related
* Re: [RFC/PATCH git-remote-bzr] Adapt to new semantics of remote-helper "import" command
From: Gabriel Filion @ 2012-02-03 9:43 UTC (permalink / raw)
To: Jonathan Nieder
Cc: git, Simon Poirier, Sverre Rabbelier, Jeff King, David Barr,
Dmitry Ivankov, Jelmer Vernooij
In-Reply-To: <20120122054657.GA25103@burratino>
Hello,
On 12-01-22 12:46 AM, Jonathan Nieder wrote:
> Hi Simon and Gabriel,
>
> Here's a rough patch against git://github.com/lelutin/git-remote-bzr.git
> master.
great! thanks for your help.
I must admit that this project never got to completion and is now
getting quite the low priority for my part. I'm no longer working for
the company that was using mainly Bazaar as their VCS, and I've been a
happy git-only user for some time now.
So, I don't have the same incentive to complete the project as I had before.
But I'd be happy to see this get to a point where it's working fine.
> Without this patch, whenever I try to use "git clone bzr::<something>",
> after doing all the work it removes the resulting repo and exits with
> status 141 (SIGPIPE). Maybe the transport-helper should mask SIGPIPE
> when writing the final newline to avoid that.
>
> I'd have prefered to write a patch for remote-bzr that works with
> older versions of git fast-import, too, but it wasn't obvious how.
> Hints welcome.
hmm.. I can wait some time to see if some ideas come out around this,
and commit your patch as-is if there are no comments/reworks.
> BTW, would you mind if I sent a patch to include git-remote-bzr in
> git.git under contrib/?
absolutely not, that'd be great actually :)
I didn't do that up to now, though, since I bumped into so much bugs
that I couldn't work out -- some very bad performance issues, and
problems with handling mark files with bzr-fastimport.
> Thanks for git remote-bzr! I'd be happy for any thoughts you have.
The idea behind git-remote-bzr was to be able to interact with Bazaar
from within your git repository, i.e. to expose remote branches that you
can pull from and push to using the default git commands, without having
to learn to use yet another tool since the remote-helper would be
interfacing with the tool for you.
I have dived for a short period of time into bzrlib, the python library
behind Bazaar, to see how much work it would take to put together a
simplified fast-import client.. and .... wechrk!
It was a huge maze of version-dependant code (the API undergoes big
changes frequently, and backwards compatibility is maintained pretty
far) mixed with a 40-foot-deep class hierarchy. So I quickly gave up on
that idea..
IIRC, at the time I started work on this, Simon and I used
bzr-fastimport[1] because we were able to get farther with this tool. I
haven't used bzr-git[2] that much, though, so I can't comment too
extensively on it. But I would guess that it is maintained more
frequently than bzr-fastimport is, so it could be a better choice for
the backend fast-import client.
I would guess that Jelmer would be happy to help out with interfacing
with bzr-git.
--
Gabriel Filion
^ permalink raw reply
* Re: [PATCH] Convert isatty() calls to git_isatty()
From: Johannes Sixt @ 2012-02-03 9:48 UTC (permalink / raw)
To: Nguyễn Thái Ngọc Duy; +Cc: git
In-Reply-To: <1328258101-10636-1-git-send-email-pclouds@gmail.com>
Am 2/3/2012 9:35, schrieb Nguyễn Thái Ngọc Duy:
> isatty() is used to check for interactive use cases. However if pager is
> set up, standard file handles may be redirected and istty() calls later
> on no longer reflect the original state.
So what? What's wrong with this behavior?
You converted many cases involving progress indicators. Wouldn't the new
code pipe progress output to the pager where earlier it was not shown if a
pager was present? That is plainly wrong: Progress output is destined only
for the terminal, not for the pager.
-- Hannes
^ permalink raw reply
* Re: [PATCH] Convert isatty() calls to git_isatty()
From: Nguyen Thai Ngoc Duy @ 2012-02-03 9:59 UTC (permalink / raw)
To: Johannes Sixt; +Cc: git
In-Reply-To: <4F2BAD8B.1080403@viscovery.net>
2012/2/3 Johannes Sixt <j.sixt@viscovery.net>:
> Am 2/3/2012 9:35, schrieb Nguyễn Thái Ngọc Duy:
>> isatty() is used to check for interactive use cases. However if pager is
>> set up, standard file handles may be redirected and istty() calls later
>> on no longer reflect the original state.
>
> So what? What's wrong with this behavior?
>
> You converted many cases involving progress indicators. Wouldn't the new
> code pipe progress output to the pager where earlier it was not shown if a
> pager was present? That is plainly wrong: Progress output is destined only
> for the terminal, not for the pager.
Yeah right. My mistake.
--
Duy
^ permalink raw reply
* Re: [PATCH v3 1/4] completion: be nicer with zsh
From: Felipe Contreras @ 2012-02-03 10:38 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Jonathan Nieder, git, SZEDER Gábor
In-Reply-To: <7vhaz8vkhd.fsf@alter.siamese.dyndns.org>
On Fri, Feb 3, 2012 at 2:17 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Felipe Contreras <felipe.contreras@gmail.com> writes:
>
>> On Thu, Feb 2, 2012 at 9:27 PM, Junio C Hamano <gitster@pobox.com> wrote:
>>> Jonathan Nieder <jrnieder@gmail.com> writes:
>>>> However, clearly I did not say it clearly enough. :) I guess it's
>>>> better to take a cue from storytellers and show rather than tell.
>>>
>>> Very big thanks for this ;-)
>>
>> Not a single comment regarding what I said?
>
> What entitles you to force me to refraining from commenting at all until I
> read everything in my mailbox and after waiting for a while to make sure
> there is no more to come to the thread?
Fair enough. Just wondering.
> In any case, "be nicer with zsh" conveys no more meaningful information
> than "this is some patch about zsh".
And that already tells you a lot more than other alternatives.
> Let's try to avoid warm and fuzzy
> words that imply "goodness", e.g. "improve" and "be nicer with" because
> nobody sends a patch to purposefully make Git worse and expects it to be
> applied.
True. Which why I listened to the suggestion from Thomas Rast and
didn't use that, but "completion: work around zsh option propagation
bug" instead.
> I found Jonathan's alternative "avoid default value assignment on : true
> command" at least a bit better for the purpose of jogging the short-term
> memory in the "'git shortlog v1.7.9.. contrib/completion/' tells us that
> we have applied several patches, and I remember that : ${var=word} one!"
> sense. It is not super-useful for the longer term, though.
>
> Here is what I ended up in preparation for queuing the series. I still
> haven't seen any version of 4/4, but please check $gmane/189683 and see if
> that matches what you intended. Also I am assuming $gmane/189606 relayed
> by Jonathan is a squash between your 2 and 3 (which didn't reach me), so
> please advise if that does not match what you want to have.
This is getting ridiculous, now I sent the patches directly to you, is
your pobox.com server also silently dropping them for no reason? I
think this is totally counter-productive. I haven't received any reply
from the vger postmaster, but I guess you should be able to find out
why your host is dropping mails. Am I the only one that has such
issues?
Anyway. I have uploaded all the mails to here:
http://people.freedesktop.org/~felipec/git-patches/
As for $gmane/189683, the changes seem to be correct, but I still
prefer my commit message[1]--which I have written and rewritten many
times now to improve it.
Regarding $gmane/189606, I still prefer my commit message[2], because
it starts with the *purpose* of the patch. As for the changes, they
are correct, and I don't mind squashing them, but they are *two*
logically independent changes; imagine in the future somebody
wants/need to re-enable __git_shopt, well, all they have to do is
revert the second patch. But that's up to you.
Cheers.
[1] http://people.freedesktop.org/~felipec/git-patches/4
[2] http://people.freedesktop.org/~felipec/git-patches/2
--
Felipe Contreras
^ permalink raw reply
* Re: [RFC/PATCH 0/2] Commits with ancient timestamps
From: Thomas Rast @ 2012-02-03 10:44 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <1328218903-5681-1-git-send-email-gitster@pobox.com>
Junio C Hamano <gitster@pobox.com> writes:
> avoid misinterpreting human-written timestamp in other formats, and
> timestamps before 1975 do not have enough number of digits in them.
>
> Here is a two-patch series that may improve the situation.
Doing this just makes me wonder how important exactly the 1970-1975
range is. Is there a notable software history from that era that can be
recovered?
(Your [1/2] does not seem to parse negative offsets from the unix epoch,
so anything before 1970 is still out.)
--
Thomas Rast
trast@{inf,student}.ethz.ch
^ permalink raw reply
* Re: Alternates corruption issue
From: Jeff King @ 2012-02-03 12:02 UTC (permalink / raw)
To: Junio C Hamano
Cc: Jonathan Nieder, Richard Purdie, GIT Mailing-list, Hart, Darren,
Ashfield, Bruce
In-Reply-To: <7vzkd0u4ik.fsf@alter.siamese.dyndns.org>
On Thu, Feb 02, 2012 at 04:47:31PM -0800, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
>
> > @@ -324,8 +324,11 @@ const char *enter_repo(const char *path, int strict)
> > return NULL;
> > len = strlen(used_path);
> > for (i = 0; suffix[i]; i++) {
> > + struct stat st;
> > strcpy(used_path + len, suffix[i]);
> > - if (!access(used_path, F_OK)) {
> > + if (!stat(used_path, &st) &&
> > + (S_ISREG(st.st_mode) ||
> > + (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
>
> Hmm, how would this change interact with
>
> > strcat(validated_path, suffix[i]);
> > break;
> > }
>
> gitfile = read_gitfile(used_path);
>
> that appear after the context in the patch?
It assumes that any file named ".git" is worth reading and selecting.
And then later we actually read_gitfile to find out if it's worth-while.
There is no change of behavior from before the patch, as we would
similarly notice the file (without checking if it's a real gitfile) and
then later read it and possibly fail.
However, with the ordering change, there is a technically a regression
in one case: a random file "foo" next to a repo "foo.git". Saying "git
ls-remote foo" used to prefer "foo.git", and will now select the file
"foo" only to fail.
The code-path in clone's get_repo_path handles this properly (it checks
that the path is really a valid gitfile before finishing the loop). The
gitfile-reading from later in enter_repo could be hoisted into the loop.
If was trying to make a less-invasive change; if we're going to do that
much rewriting, it probably makes sense to factor out the logic from
get_repo_path and have them share the code.
Thanks for noticing. I saw this issue when I was writing the original
version of the patch, and meant to revisit it and at least document it
in the commit message, but I ended up forgetting.
-Peff
^ permalink raw reply
* Re: [PATCH] t0300-credentials: Word around a solaris /bin/sh bug
From: Jeff King @ 2012-02-03 12:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Ben Walton, git
In-Reply-To: <7vr4ycu3ty.fsf@alter.siamese.dyndns.org>
On Thu, Feb 02, 2012 at 05:02:17PM -0800, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
>
> > I wonder if a better solution is to use a known-good shell instead of
> > trying to work around problems in a bogus shell.
>
> Yeah, I think that is a better approach.
>
> What prevents us from doing 's|^#! */bin/sh|$#$SHELL_PATH|' on everything
> in t/ directory (I am not suggesting to do this. I just want to know if
> there is a reason we want hardcoded "#!/bin/sh" for some instances).
The quoting is more annoying, because you usually don't want
interpolation on the rest of the lines of your embedded script. So:
cat >foo.sh <<\EOF
#!/bin/sh
echo my arguments are "$@"
EOF
cannot have the mechanical replace you mentioned above. It would need:
cat >foo.sh <<EOF
#!$SHELL_PATH
echo my arguments are "\$@"
EOF
or:
{
echo "#!$SHELL_PATH" &&
cat <<EOF
echo my arguments are "$@"
EOF
} >foo.sh
When I have hard-coded "#!/bin/sh", my thinking is usually "this is less
cumbersome to type and to read, and this script-let is so small that
even Solaris will get it right".
-Peff
^ permalink raw reply
* Re: General support for ! in git-config values
From: Jeff King @ 2012-02-03 12:09 UTC (permalink / raw)
To: Kyle Moffett
Cc: demerphq, Junio C Hamano, Ævar Arnfjörð,
Git Mailing List
In-Reply-To: <CAGZ=bq++R+X+2r2_zQ4UZ6JvDC9W9_4nF23MQ6+612_Qe2RS4Q@mail.gmail.com>
On Thu, Feb 02, 2012 at 09:08:46PM -0800, Kyle Moffett wrote:
> > I understand. I think we will probably use backtick quoting in git-deploy. So
> >
> > deploy.prefix=`cat /etc/SERVER_ROLE`
> >
> > will execute cat /etc/SERVER_ROLE and use the results as the value of
> > the config option.
>
> Alternatively, you could extend the recent proposal for GIT config
> "include" statements so that something like this works:
>
> [include]
> exec = echo "deploy.prefix = `cat /etc/SERVER_ROLE`"
> exec = /usr/local/bin/git-config-for-ldap-user
>
> Thoughts?
I am still undecided on whether the utility of the idea is worth the
potential hassle, but syntactically I like that better. It does put a
little more burden on the called program to handle things like quoting,
though.
-Peff
^ permalink raw reply
* Re: General support for ! in git-config values
From: Jeff King @ 2012-02-03 12:13 UTC (permalink / raw)
To: Junio C Hamano
Cc: Kyle Moffett, demerphq, Ævar Arnfjörð,
Git Mailing List
In-Reply-To: <7vmx90say8.fsf@alter.siamese.dyndns.org>
On Thu, Feb 02, 2012 at 10:11:27PM -0800, Junio C Hamano wrote:
> Kyle Moffett <kyle@moffetthome.net> writes:
>
> > Alternatively, you could extend the recent proposal for GIT config
> > "include" statements so that something like this works:
> >
> > [include]
> > exec = echo "deploy.prefix = `cat /etc/SERVER_ROLE`"
> > exec = /usr/local/bin/git-config-for-ldap-user
>
> Erh...
>
> Running known stuff from your own .git/config may be justifiable as "at
> your own risk", but if we consider sources that are not under your direct
> control, such as /etc/gitconfig and whatever your project encourages you
> to include from your .git/config,... eek.
For normal use, I don't see this as a big deal. They could also be
specifying diff.external, which would run arbitrary code (and who
doesn't run "git diff" once in a while?).
I see it as a bigger issue for sites which serve repositories on behalf
of their users, and already take care never to use porcelain commands
which will run arbitrary code from the config by default (e.g., gitweb
carefully uses diff plumbing for this reason). Introducing such an
option provides a mechanism for users who control the config of the
served repositories to execute code as the user running git-daemon or
gitweb.
-Peff
^ permalink raw reply
* Re: [PATCH v2] Use correct grammar in diffstat summary line
From: Jeff King @ 2012-02-03 12:24 UTC (permalink / raw)
To: Nguyen Thai Ngoc Duy
Cc: Junio C Hamano, git, Jonathan Nieder,
Ævar Arnfjörð, Frederik Schwarzer, Brandon Casey
In-Reply-To: <CACsJy8CcBB9OF=8a1hQEpDFzqsrkbpFKnVAcU65h_5Cnym90SQ@mail.gmail.com>
On Fri, Feb 03, 2012 at 08:11:23AM +0700, Nguyen Thai Ngoc Duy wrote:
> >> I take it --summary is un-i18n-able,...
> >
> > ... because?
>
> .. of scripts? We have --numstat for scripts, but I see no alternative
> to --summary. Does anybody parse --summary output?
I would think it is spelled "--raw".
-Peff
^ permalink raw reply
* Re: Breakage in master?
From: Erik Faye-Lund @ 2012-02-03 12:28 UTC (permalink / raw)
To: Jeff King; +Cc: Git Mailing List, msysGit, Ævar Arnfjörð
In-Reply-To: <20120202174601.GB30857@sigill.intra.peff.net>
On Thu, Feb 2, 2012 at 6:46 PM, Jeff King <peff@peff.net> wrote:
> On Thu, Feb 02, 2012 at 01:14:19PM +0100, Erik Faye-Lund wrote:
>
>> But here's the REALLY puzzling part: If I add a simple, unused
>> function to diff-lib.c, like this:
>> [...]
>> "git status" starts to error out with that same vsnprintf complaint!
>>
>> ---8<---
>> $ git status
>> # On branch master
>> # Changes not staged for commit:
>> # (use "git add <file>..." to update what will be committed)
>> fatal: BUG: your vsnprintf is broken (returned -1)
>> ---8<---
>
> OK, that's definitely odd.
>
> At the moment of the die() in strbuf_vaddf, what does errno say?
If I apply this patch:
---8<---
diff --git a/strbuf.c b/strbuf.c
index ff0b96b..52dfdd6 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -218,7 +218,7 @@ void strbuf_vaddf(struct strbuf *sb, const char
*fmt, va_list ap)
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
va_end(cp);
if (len < 0)
- die("BUG: your vsnprintf is broken (returned %d)", len);
+ die_errno("BUG: your vsnprintf is broken (returned %d)", len);
if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
---8<---
Then I get "fatal: BUG: your vsnprintf is broken (returned -1): Result
too large". This goes both for both failure cases I described. I
assume this means errno=ERANGE.
> vsnprintf should generally never be returning -1 (it should return the
> number of characters that would have been written). Since you're on
> Windows, I assume you're using the replacement version in
> compat/snprintf.c.
No. SNPRINTF_RETURNS_BOGUS is only set for the MSVC target, not for
the MinGW target. I'm assuming that means MinGW-runtime has a sane
vsnprintf implementation. But even if I enable SNPRINTF_RETURNS_BOGUS,
the problem occurs. And it's still "Result too large".
So I decided to do a bit of stepping, and it seems libintl takes over
vsnprintf, directing us to libintl_vsnprintf instead. I guess this is
so it can ensure we support reordering the parameters with $1 etc...
And aparently this vsnprintf implementation calls the system vnsprintf
if the format string does not contain '$', and it's using _vsnprintf
rather than vsnprintf on Windows. _vsnprintf is the MSVCRT-version,
and not the MinGW-runtime, which needs SNPRINTF_RETURNS_BOGUS.
So I guess I can patch libintl to call vsnprintf from MinGW-runtime instead.
> All of that would make sense to me, _except_ for your weird "if I add a
> random function, the problem is more reproducible" bit. Which does seem
> like something is invoking undefined behavior (of course, it could be
> that undefined behavior or stack-smashing that is causing vsnprintf to
> report an error). Lacking any better leads, it might be worth pursuing.
Well, now at least I have some better leads, but I'm still not able to
explain the "if I add a random function, the problem is more
reproducible" bit. :(
>> I've bisected the issues down to 5e9637c (i18n: add infrastructure for
>> translating Git with gettext). Trying to apply my unused-function
>> patch on top of this commit starts giving the same "fatal: BUG: your
>> vsnprintf is broken (returned -1)" error. It's ancestor, bc1bbe0(Git
>> 1.7.8-rc2), does not yield any of the issues.
>
> I've looked at 5e9637c, and it really doesn't do anything that looks
> bad. I wonder if your gettext library is buggy. Does compiling with
> NO_GETTEXT help?
Compiling with NO_GETTEXT does make the symptoms go away, but that's
not curing the problem ;)
But, I have a lead now. I'll see if I can find out *why* libintl calls
_vsnprintf on MinGW. I expect it's so the MSVC and the MinGW versions
behave similarly, MSVC doesn't have a sane vsnprintf. Perhaps I should
back-port SNPRINTF_RETURNS_BOGUS-workaround to libintl, so our MSVC
builds doesn't break also?
^ permalink raw reply related
* [PATCH/RFCv2 (version B)] gitweb: Allow UTF-8 encoded CGI query parameters and path_info
From: Jakub Narebski @ 2012-02-03 12:44 UTC (permalink / raw)
To: Michal Kiedrowicz; +Cc: git
In-Reply-To: <20120203083935.5d9d4b18@mkiedrowicz.ivo.pl>
Gitweb tries hard to properly process UTF-8 data, by marking output
from git commands and contents of files as UTF-8 with to_utf8()
subroutine. This ensures that gitweb would print correctly UTF-8
e.g. in 'log' and 'commit' views.
Unfortunately it misses another source of potentially Unicode input,
namely query parameters. The result is that one cannot search for a
string containing characters outside US-ASCII. For example searching
for "Michał Kiedrowicz" (containing letter 'ł' - LATIN SMALL LETTER L
WITH STROKE, with Unicode codepoint U+0142, represented with 0xc5 0x82
bytes in UTF-8 and percent-encoded as %C5%81) result in the following
incorrect data in search field
MichaÅ Kiedrowicz
This is caused by CGI by default treating '0xc5 0x82' bytes as two
characters in Perl legacy encoding latin-1 (iso-8859-1), because 's'
query parameter is not processed explicitly as UTF-8 encoded string.
The solution used here follows "Using Unicode in a Perl CGI script"
article on http://www.lemoda.net/cgi/perl-unicode/index.html:
use CGI;
use Encode 'decode_utf8;
my $value = params('input');
$value = decode_utf8($value);
Decoding UTF-8 is done when filling %input_params hash and $path_info
variable; the former required to move from explicit $cgi->param(<label>)
to $input_params{<name>} in a few places, which is a good idea anyway.
Another required change was to add -override=>1 parameter to
$cgi->textfield() invocation (in search form). Otherwise CGI would
use values from query string if it is present, filling value from
$cgi->param... without decode_utf8(). As we are using value of
appropriate parameter anyway, -override=>1 doesn't change the
situation but makes gitweb fill search field correctly.
Alternate solution would be to simply use the '-utf8' pragma (via
"use CGI '-utf8';"), but according to CGI.pm documentation it may
cause problems with POST requests containing binary files... and
it requires CGI 3.31 (I think), released with perl v5.8.9.
Noticed-by: Michał Kiedrowicz <michal.kiedrowicz@gmail.com>
Signed-off-by: Jakub Narębski <jnareb@gmail.com>
---
On Fri, 3 Feb 2012, Michal Kiedrowicz wrote:
> Jakub Narebski <jnareb@gmail.com> wrote:
> > Is it what you mean by "this doesn't work for me", i.e. working
> > search, garbage in search field?
>
> I mean "garbage in search field". Search works even without the patch
> (at least on Debian with git-1.7.7.3, perl-5.10.1 and CGI-3.43; I
> don't have my notebook nearby at the moment to check).
[...]
> > Damn. If we use $cgi->textfield(-name => "s", -value => $searchtext)
> > like in gitweb, CGI.pm would read $cgi->param("s") by itself -
> > without decoding.
>
> Makes sense. When I tried calling to_utf8() in the line that defines
> textfield (this was my first approach to this problem), it haven't
> changed anything.
Yes, and it doesn't makes sense in gitweb case - we use value of
$cgi->param("s") as default value of text field anyway, but in
Unicode-aware way.
> > To skip this we need to pass -force=>1 or
> > -override=>1 (i.e. further changes to gitweb).
This patch does this.
Does it make work for you?
> > -utf8 pragma works with more modern CGI.pm, but does not with 3.10.
-utf8 pragma was added in CVS revision 1.238 of CGI.pm, which I think
is present in CGI 3.31, released with perl v5.8.9. Theoretically gitweb
maintains backward compatibility with perl v5.8.3 or something
("use 5.008;" but IIRC 5.8.3 is needed for correct Unicde handling anyway).
gitweb/gitweb.perl | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 9cf7e71..bd5fff9 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -52,7 +52,7 @@ sub evaluate_uri {
# as base URL.
# Therefore, if we needed to strip PATH_INFO, then we know that we have
# to build the base URL ourselves:
- our $path_info = $ENV{"PATH_INFO"};
+ our $path_info = decode_utf8($ENV{"PATH_INFO"});
if ($path_info) {
if ($my_url =~ s,\Q$path_info\E$,, &&
$my_uri =~ s,\Q$path_info\E$,, &&
@@ -816,9 +816,9 @@ sub evaluate_query_params {
while (my ($name, $symbol) = each %cgi_param_mapping) {
if ($symbol eq 'opt') {
- $input_params{$name} = [ $cgi->param($symbol) ];
+ $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ];
} else {
- $input_params{$name} = $cgi->param($symbol);
+ $input_params{$name} = decode_utf8($cgi->param($symbol));
}
}
}
@@ -2767,7 +2767,7 @@ sub git_populate_project_tagcloud {
}
my $cloud;
- my $matched = $cgi->param('by_tag');
+ my $matched = $input_params{'ctag'};
if (eval { require HTML::TagCloud; 1; }) {
$cloud = HTML::TagCloud->new;
foreach my $ctag (sort keys %ctags_lc) {
@@ -3873,7 +3873,7 @@ sub print_search_form {
-values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
$cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
" search:\n",
- $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+ $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
"<span title=\"Extended regular expression\">" .
$cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
-checked => $search_use_regexp) .
@@ -5282,7 +5282,7 @@ sub git_project_list_body {
my $check_forks = gitweb_check_feature('forks');
my $show_ctags = gitweb_check_feature('ctags');
- my $tagfilter = $show_ctags ? $cgi->param('by_tag') : undef;
+ my $tagfilter = $show_ctags ? $input_params{'ctag'} : undef;
$check_forks = undef
if ($tagfilter || $searchtext);
@@ -5994,7 +5994,7 @@ sub git_project_list {
}
print $cgi->startform(-method => "get") .
"<p class=\"projsearch\">Search:\n" .
- $cgi->textfield(-name => "s", -value => $searchtext) . "\n" .
+ $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
"</p>" .
$cgi->end_form() . "\n";
git_project_list_body(\@list, $order);
@@ -6197,7 +6197,7 @@ sub git_tag {
sub git_blame_common {
my $format = shift || 'porcelain';
- if ($format eq 'porcelain' && $cgi->param('js')) {
+ if ($format eq 'porcelain' && $input_params{'javascript'}) {
$format = 'incremental';
$action = 'blame_incremental'; # for page title etc
}
--
1.7.6
^ permalink raw reply related
* Re: [ANNOUNCE] Git 1.7.9
From: Jakub Narebski @ 2012-02-03 12:52 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <CAPc5daVhXQ3-TCqZi8di=j5LdpwXZUt3bO8KkvA2UmL6axCRqQ@mail.gmail.com>
On Fri, 3 Feb 2012, Junio C Hamano wrote:
> On Thu, Feb 2, 2012 at 12:50 PM, Jakub Narebski <jnareb@gmail.com> wrote:
>
> > When trying to rebuild RPM out of tarball with
> >
> > $ rpmbuild -tb git-1.7.9.tar.gz
> >
> > I get the following error at the end of build phase:
> >
> > RPM build errors:
> > Installed (but unpackaged) file(s) found:
> > /usr/share/locale/is/LC_MESSAGES/git.mo
> >
>
> I think it should be simply ignored at least for now. I stopped touching
> the rpm spec since August last year (the only reason I was running rpmbuild
> was to install them on k.org), so I didn't notice.
So for the time being something like that would be an acceptable fix?
diff --git a/git.spec b/git.spec
index 8ceb42b..5461b0b 100644
--- a/git.spec
+++ b/git.spec
@@ -134,6 +134,7 @@ find $RPM_BUILD_ROOT -type f -name perllocal.pod -exec rm -f {} ';'
%else
rm -rf $RPM_BUILD_ROOT%{_mandir}
%endif
+rm -rf $RPM_BUILD_ROOT%{_datadir}/locale
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
install -m 644 -T contrib/completion/git-completion.bash $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d/git
--
Jakub Narebski
Poland
^ permalink raw reply related
* filter-branch ignoring gitattributes?
From: norbert.nemec @ 2012-02-03 12:55 UTC (permalink / raw)
To: git
Hi there,
it seems that 'git filter-branch' ignores the setting in
.git/info/attributes - is that correct?
Does .gitattributes work reliably?
Specifically, I tried
git filter-branch \
--tree-filter 'echo "* text=auto" > .gitattributes' \
--tag-name-filter cat
--prune-empty -- --all
It seems to work, but I am not sure whether I missed anything.
Greetings,
Norbert
^ permalink raw reply
* [PATCH v4 00/13] Column display again
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
Reroll of v3 [1]. This series adds support for column display like
"ls". "git branch", "git tag -l" and "git status"'s untracked files
can now be displayed in columns. There's also "git-column" to help
do the layout for commands that are not aware of column display. In
fact git-tag uses it this way.
I've been thinking of supporting the layout where a cell's content can
occupy more than one cell. It'll make better use of space when there
are a few long entries. Something like this:
abc def ghk
longlonglong short
again here now
"git status" may benefit when you have untracked files in some deep
directories.
"ls -R" layout is also an option ("branch -r" and ls-files will
benefit due to dense tree output). But these ideas will have to wait
until later.
Compared to v3, it has "git status" support, the return of git-column,
and column.* conf vars.
[1] http://mid.gmane.org/1300625873-18435-1-git-send-email-pclouds@gmail.com
Nguyễn Thái Ngọc Duy (13):
Save terminal width before setting up pager
column: add API to print items in columns
parseopt: make OPT_INTEGER support hexadecimal as well
Add git-column and column mode parsing
Stop starting pager recursively
column: add columnar layout
column: support columns with different widths
column: add column.ui for default column output settings
help: reuse print_columns() for help -a
branch: add --column
status: add --column
column: support piping stdout to external git-column process
tag: add --column
.gitignore | 1 +
Documentation/config.txt | 38 ++++
Documentation/git-branch.txt | 9 +
Documentation/git-column.txt | 53 +++++
Documentation/git-status.txt | 7 +
Documentation/git-tag.txt | 11 +-
Makefile | 3 +
builtin.h | 1 +
builtin/branch.c | 26 ++-
builtin/column.c | 64 ++++++
builtin/commit.c | 13 +-
builtin/tag.c | 25 ++-
column.c | 493 ++++++++++++++++++++++++++++++++++++++++++
column.h | 41 ++++
command-list.txt | 1 +
git.c | 1 +
help.c | 70 ++-----
pager.c | 37 +++-
parse-options.c | 5 +-
parse-options.h | 2 +
t/t9002-column.sh | 135 ++++++++++++
wt-status.c | 38 +++-
wt-status.h | 2 +-
23 files changed, 1002 insertions(+), 74 deletions(-)
create mode 100644 Documentation/git-column.txt
create mode 100644 builtin/column.c
create mode 100644 column.c
create mode 100644 column.h
create mode 100755 t/t9002-column.sh
--
1.7.8.36.g69ee2
^ permalink raw reply
* [PATCH v4 01/13] Save terminal width before setting up pager
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1328276078-27955-1-git-send-email-pclouds@gmail.com>
term_columns() checks for terminal width via ioctl(2). After
redirecting, stdin is no longer terminal to get terminal width.
Check terminal width and save it before redirect stdin in
setup_pager() and let term_columns() reuse the value.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Makefile | 1 +
column.h | 6 ++++++
help.c | 23 +----------------------
| 35 +++++++++++++++++++++++++++++++++++
4 files changed, 43 insertions(+), 22 deletions(-)
create mode 100644 column.h
diff --git a/Makefile b/Makefile
index c457c34..cbbc699 100644
--- a/Makefile
+++ b/Makefile
@@ -2114,6 +2114,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
builtin/tar-tree.o archive-tar.o: tar.h
connect.o transport.o url.o http-backend.o: url.h
+help.o pager.o: column.h
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
diff --git a/column.h b/column.h
new file mode 100644
index 0000000..55d8067
--- /dev/null
+++ b/column.h
@@ -0,0 +1,6 @@
+#ifndef COLUMN_H
+#define COLUMN_H
+
+extern int term_columns(void);
+
+#endif
diff --git a/help.c b/help.c
index cbbe966..672561b 100644
--- a/help.c
+++ b/help.c
@@ -4,28 +4,7 @@
#include "levenshtein.h"
#include "help.h"
#include "common-cmds.h"
-
-/* most GUI terminals set COLUMNS (although some don't export it) */
-static int term_columns(void)
-{
- char *col_string = getenv("COLUMNS");
- int n_cols;
-
- if (col_string && (n_cols = atoi(col_string)) > 0)
- return n_cols;
-
-#ifdef TIOCGWINSZ
- {
- struct winsize ws;
- if (!ioctl(1, TIOCGWINSZ, &ws)) {
- if (ws.ws_col)
- return ws.ws_col;
- }
- }
-#endif
-
- return 80;
-}
+#include "column.h"
void add_cmdname(struct cmdnames *cmds, const char *name, int len)
{
--git a/pager.c b/pager.c
index 975955b..772a5a6 100644
--- a/pager.c
+++ b/pager.c
@@ -6,6 +6,21 @@
#define DEFAULT_PAGER "less"
#endif
+static int spawned_pager;
+static int max_columns;
+
+static int retrieve_terminal_width(void)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ if (ioctl(1, TIOCGWINSZ, &ws)) /* e.g., ENOSYS */
+ return 0;
+ return ws.ws_col;
+#else
+ return 0;
+#endif
+}
+
/*
* This is split up from the rest of git so that we can do
* something different on Windows.
@@ -72,12 +87,17 @@ const char *git_pager(int stdout_is_tty)
void setup_pager(void)
{
const char *pager = git_pager(isatty(1));
+ int width;
if (!pager)
return;
setenv("GIT_PAGER_IN_USE", "true", 1);
+ width = retrieve_terminal_width();
+ if (width)
+ max_columns = width;
+
/* spawn the pager */
pager_argv[0] = pager;
pager_process.use_shell = 1;
@@ -110,3 +130,18 @@ int pager_in_use(void)
env = getenv("GIT_PAGER_IN_USE");
return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
}
+
+int term_columns()
+{
+ char *col_string = getenv("COLUMNS");
+ int n_cols;
+
+ if (col_string && (n_cols = atoi(col_string)) > 0)
+ return n_cols;
+
+ if (spawned_pager && max_columns)
+ return max_columns;
+
+ n_cols = retrieve_terminal_width();
+ return n_cols ? n_cols : 80;
+}
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v4 02/13] column: add API to print items in columns
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1328276078-27955-1-git-send-email-pclouds@gmail.com>
Simple code that print line-by-line and wants to columnize can do
this:
print_cell(...);
print_cell(...);
...
print_columns(...);
if column layout is disabled, print_cell() prints directly and
print_columns() becomes no-op. Otherwise print_cell() saves all items
in a string list for print_columns() to process later.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Makefile | 3 ++-
column.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
column.h | 17 +++++++++++++++++
3 files changed, 73 insertions(+), 1 deletions(-)
create mode 100644 column.c
diff --git a/Makefile b/Makefile
index cbbc699..5f0531b 100644
--- a/Makefile
+++ b/Makefile
@@ -637,6 +637,7 @@ LIB_OBJS += bulk-checkin.o
LIB_OBJS += bundle.o
LIB_OBJS += cache-tree.o
LIB_OBJS += color.o
+LIB_OBJS += column.o
LIB_OBJS += combine-diff.o
LIB_OBJS += commit.o
LIB_OBJS += compat/obstack.o
@@ -2114,7 +2115,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
builtin/tar-tree.o archive-tar.o: tar.h
connect.o transport.o url.o http-backend.o: url.h
-help.o pager.o: column.h
+column.o help.o pager.o: column.h
http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
diff --git a/column.c b/column.c
new file mode 100644
index 0000000..4ae98f3
--- /dev/null
+++ b/column.c
@@ -0,0 +1,54 @@
+#include "cache.h"
+#include "column.h"
+#include "string-list.h"
+
+#define MODE(mode) ((mode) & COL_MODE)
+
+struct string_list_item *add_cell_to_list(struct string_list *list,
+ int mode,
+ const char *string)
+{
+ if (mode & COL_ENABLED)
+ return string_list_append(list, string);
+ return NULL;
+}
+
+void print_cell(struct string_list *list, int mode, const char *string)
+{
+ if (!add_cell_to_list(list, mode, string))
+ printf("%s\n", string);
+}
+
+/* Display without layout when COL_ENABLED is not set */
+static void display_plain(const struct string_list *list,
+ const char *indent, const char *nl)
+{
+ int i;
+
+ for (i = 0; i < list->nr; i++)
+ printf("%s%s%s", indent, list->items[i].string, nl);
+}
+
+void print_columns(const struct string_list *list, int mode,
+ struct column_options *opts)
+{
+ const char *indent = "", *nl = "\n";
+ int padding = 1, width = term_columns();
+
+ if (!list->nr)
+ return;
+ if (opts) {
+ if (opts->indent)
+ indent = opts->indent;
+ if (opts->nl)
+ nl = opts->nl;
+ if (opts->width)
+ width = opts->width;
+ padding = opts->padding;
+ }
+ if (width <= 1 || !(mode & COL_ENABLED)) {
+ display_plain(list, indent, nl);
+ return;
+ }
+ die("BUG: invalid mode %d", MODE(mode));
+}
diff --git a/column.h b/column.h
index 55d8067..e0f8c26 100644
--- a/column.h
+++ b/column.h
@@ -1,6 +1,23 @@
#ifndef COLUMN_H
#define COLUMN_H
+#define COL_MODE 0x000F
+#define COL_ENABLED (1 << 4)
+
+struct column_options {
+ int width;
+ int padding;
+ const char *indent;
+ const char *nl;
+};
+
extern int term_columns(void);
+extern struct string_list_item *add_cell_to_list(struct string_list *list,
+ int mode,
+ const char *string);
+/* add cell to list, or print it out if column mode is disabled */
+extern void print_cell(struct string_list *list, int mode, const char *string);
+extern void print_columns(const struct string_list *list,
+ int mode, struct column_options *opts);
#endif
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1328276078-27955-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
parse-options.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/parse-options.c b/parse-options.c
index f0098eb..7c9109d 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -139,7 +139,10 @@ static int get_value(struct parse_opt_ctx_t *p,
}
if (get_arg(p, opt, flags, &arg))
return -1;
- *(int *)opt->value = strtol(arg, (char **)&s, 10);
+ if (!prefixcmp(arg, "0x") || !prefixcmp(arg, "0X"))
+ *(int *)opt->value = strtol(arg + 2, (char **)&s, 16);
+ else
+ *(int *)opt->value = strtol(arg, (char **)&s, 10);
if (*s)
return opterror(opt, "expects a numerical value", flags);
return 0;
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v4 04/13] Add git-column and column mode parsing
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1328276078-27955-1-git-send-email-pclouds@gmail.com>
A column option string consists of many token separated by either
space of commas. A token belongs to one of three groups:
- enabling: always, never and auto
- layout mode: to be implemented
- other tuning, which could be negated be prefix 'no'
A command line option without argument (e.g. --column) will enable
column output and reuse existing settings (layout mode and options..).
--no-column disables columnar output.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
.gitignore | 1 +
Documentation/git-column.txt | 49 ++++++++++++++++
Makefile | 1 +
builtin.h | 1 +
builtin/column.c | 41 ++++++++++++++
column.c | 125 ++++++++++++++++++++++++++++++++++++++++++
column.h | 6 ++
command-list.txt | 1 +
git.c | 1 +
parse-options.h | 2 +
t/t9002-column.sh | 27 +++++++++
11 files changed, 255 insertions(+), 0 deletions(-)
create mode 100644 Documentation/git-column.txt
create mode 100644 builtin/column.c
create mode 100755 t/t9002-column.sh
diff --git a/.gitignore b/.gitignore
index 3b7680e..039e5ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@
/git-cherry-pick
/git-clean
/git-clone
+/git-column
/git-commit
/git-commit-tree
/git-config
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
new file mode 100644
index 0000000..508b85f
--- /dev/null
+++ b/Documentation/git-column.txt
@@ -0,0 +1,49 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Display data in columns
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+ [--indent=<string>] [--nl=<string>] [--pading=<n>]
+
+DESCRIPTION
+-----------
+This command formats its input into multiple columns.
+
+OPTIONS
+-------
+--mode=<mode>::
+ Specify layout mode. See configuration variable column.ui for option
+ syntax.
+
+--rawmode=<n>::
+ Same as --mode but take mode encoded as a number. This is mainly used
+ by other commands that have already parsed layout mode.
+
+--width=<width>::
+ Specify the terminal width. By default 'git column' will detect the
+ terminal width, or fall back to 80 if it is unable to do so.
+
+--indent=<string>::
+ String to be printed at the beginning of each line.
+
+--nl=<N>::
+ String to be printed at the end of each line,
+ including newline character.
+
+--padding=<N>::
+ The number of spaces between columns. One space by default.
+
+
+Author
+------
+Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 5f0531b..92700ca 100644
--- a/Makefile
+++ b/Makefile
@@ -766,6 +766,7 @@ BUILTIN_OBJS += builtin/checkout-index.o
BUILTIN_OBJS += builtin/checkout.o
BUILTIN_OBJS += builtin/clean.o
BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/column.o
BUILTIN_OBJS += builtin/commit-tree.o
BUILTIN_OBJS += builtin/commit.o
BUILTIN_OBJS += builtin/config.o
diff --git a/builtin.h b/builtin.h
index 857b9c8..338f540 100644
--- a/builtin.h
+++ b/builtin.h
@@ -61,6 +61,7 @@ extern int cmd_cherry(int argc, const char **argv, const char *prefix);
extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
extern int cmd_clone(int argc, const char **argv, const char *prefix);
extern int cmd_clean(int argc, const char **argv, const char *prefix);
+extern int cmd_column(int argc, const char **argv, const char *prefix);
extern int cmd_commit(int argc, const char **argv, const char *prefix);
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
extern int cmd_config(int argc, const char **argv, const char *prefix);
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000..c4a0431
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,41 @@
+#include "builtin.h"
+#include "cache.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+ "git column [options]",
+ NULL
+};
+static int colopts;
+
+int cmd_column(int argc, const char **argv, const char *prefix)
+{
+ struct string_list list = STRING_LIST_INIT_DUP;
+ struct strbuf sb = STRBUF_INIT;
+ struct column_options copts;
+ struct option options[] = {
+ OPT_COLUMN(0, "mode", &colopts, "layout to use"),
+ OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
+ OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
+ OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
+ OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
+ OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+ OPT_END()
+ };
+
+ memset(&copts, 0, sizeof(copts));
+ copts.width = term_columns();
+ copts.padding = 1;
+ argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
+ if (argc)
+ usage_with_options(builtin_column_usage, options);
+
+ while (!strbuf_getline(&sb, stdin, '\n'))
+ string_list_append(&list, sb.buf);
+
+ print_columns(&list, colopts, &copts);
+ return 0;
+}
diff --git a/column.c b/column.c
index 4ae98f3..bd15bea 100644
--- a/column.c
+++ b/column.c
@@ -1,6 +1,7 @@
#include "cache.h"
#include "column.h"
#include "string-list.h"
+#include "parse-options.h"
#define MODE(mode) ((mode) & COL_MODE)
@@ -52,3 +53,127 @@ void print_columns(const struct string_list *list, int mode,
}
die("BUG: invalid mode %d", MODE(mode));
}
+
+struct colopt {
+ enum {
+ ENABLE,
+ MODE,
+ OPTION
+ } type;
+ const char *name;
+ int value;
+};
+
+/*
+ * Set COL_ENABLED and COL_ENABLED_SET. If 'set' is -1, check if
+ * stdout is tty.
+ */
+static int set_enable_bit(int *mode, int set, int stdout_is_tty)
+{
+ if (set < 0) { /* auto */
+ if (stdout_is_tty < 0)
+ stdout_is_tty = isatty(1);
+ set = stdout_is_tty || (pager_in_use() && pager_use_color);
+ }
+ if (set)
+ *mode = *mode | COL_ENABLED | COL_ENABLED_SET;
+ else
+ *mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+ return 0;
+}
+
+/*
+ * Set COL_MODE_*. mode is intially copied from column.ui. If
+ * COL_ENABLED_SET is not set, then neither 'always', 'never' nor
+ * 'auto' has been used. Default to 'always'.
+ */
+static int set_mode(int *mode, int value)
+{
+ *mode = (*mode & ~COL_MODE) | value;
+ if (!(*mode & COL_ENABLED_SET))
+ *mode |= COL_ENABLED | COL_ENABLED_SET;
+
+ return 0;
+}
+
+/* Set or unset other COL_* */
+static int set_option(int *mode, int opt, int set)
+{
+ if (set)
+ *mode |= opt;
+ else
+ *mode &= ~opt;
+ return 0;
+}
+
+static int parse_option(const char *arg, int len,
+ int *mode, int stdout_is_tty)
+{
+ struct colopt opts[] = {
+ { ENABLE, "always", 1 },
+ { ENABLE, "never", 0 },
+ { ENABLE, "auto", -1 },
+ };
+ int i, set, name_len;
+
+ for (i = 0; i < ARRAY_SIZE(opts); i++) {
+ if (opts[i].type == OPTION) {
+ if (len > 2 && !strncmp(arg, "no", 2)) {
+ arg += 2;
+ len -= 2;
+ set = 0;
+ }
+ else
+ set = 1;
+ }
+
+ name_len = strlen(opts[i].name);
+ if (len != name_len ||
+ strncmp(arg, opts[i].name, name_len))
+ continue;
+
+ switch (opts[i].type) {
+ case ENABLE: return set_enable_bit(mode, opts[i].value,
+ stdout_is_tty);
+ case MODE: return set_mode(mode, opts[i].value);
+ case OPTION: return set_option(mode, opts[i].value, set);
+ default: die("BUG: Unknown option type %d", opts[i].type);
+ }
+ }
+
+ return error("unsupported style '%s'", arg);
+}
+
+int git_config_column(int *mode, const char *value,
+ int stdout_is_tty)
+{
+ const char *sep = " ,";
+
+ while (*value) {
+ int len = strcspn(value, sep);
+ if (len) {
+ if (parse_option(value, len, mode, stdout_is_tty))
+ return -1;
+
+ value += len;
+ }
+ value += strspn(value, sep);
+ }
+ return 0;
+}
+
+int parseopt_column_callback(const struct option *opt,
+ const char *arg, int unset)
+{
+ int *mode = opt->value;
+ if (unset) {
+ *mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+ return 0;
+ }
+ if (arg)
+ return git_config_column(mode, arg, -1);
+
+ /* no arg, turn it on */
+ *mode |= COL_ENABLED | COL_ENABLED_SET;
+ return 0;
+}
diff --git a/column.h b/column.h
index e0f8c26..59f26dc 100644
--- a/column.h
+++ b/column.h
@@ -3,6 +3,7 @@
#define COL_MODE 0x000F
#define COL_ENABLED (1 << 4)
+#define COL_ENABLED_SET (1 << 5) /* Has COL_ENABLED been set by config? */
struct column_options {
int width;
@@ -19,5 +20,10 @@ extern struct string_list_item *add_cell_to_list(struct string_list *list,
extern void print_cell(struct string_list *list, int mode, const char *string);
extern void print_columns(const struct string_list *list,
int mode, struct column_options *opts);
+extern int git_config_column(int *mode, const char *value, int stdout_is_tty);
+
+struct option;
+extern int parseopt_column_callback(const struct option *opt,
+ const char *arg, int unset);
#endif
diff --git a/command-list.txt b/command-list.txt
index a36ee9b..fe06f15 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -20,6 +20,7 @@ git-cherry-pick mainporcelain
git-citool mainporcelain
git-clean mainporcelain
git-clone mainporcelain common
+git-column purehelpers
git-commit mainporcelain common
git-commit-tree plumbingmanipulators
git-config ancillarymanipulators
diff --git a/git.c b/git.c
index 3805616..419e3cc 100644
--- a/git.c
+++ b/git.c
@@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
{ "clone", cmd_clone },
+ { "column", cmd_column },
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
{ "config", cmd_config, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index 2e811dc..56fcafd 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -238,5 +238,7 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
#define OPT__COLOR(var, h) \
OPT_COLOR_FLAG(0, "color", (var), (h))
+#define OPT_COLUMN(s, l, v, h) \
+ { OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
#endif
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
new file mode 100755
index 0000000..b0b6d62
--- /dev/null
+++ b/t/t9002-column.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='git column'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ cat >lista <<\EOF
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+'
+
+test_expect_success 'never' '
+ git column --mode=never <lista >actual &&
+ test_cmp lista actual
+'
+
+test_done
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v4 05/13] Stop starting pager recursively
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1328276078-27955-1-git-send-email-pclouds@gmail.com>
git-column can be used as a pager for other git commands, something
like this:
GIT_PAGER="git -p column --mode='dense color'" git -p branch
The problem with this is that "git -p column" also has $GIT_PAGER
set so the pager runs itself again as a pager, then again and again.
Stop this.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
| 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--git a/pager.c b/pager.c
index 772a5a6..e4353dc 100644
--- a/pager.c
+++ b/pager.c
@@ -89,7 +89,7 @@ void setup_pager(void)
const char *pager = git_pager(isatty(1));
int width;
- if (!pager)
+ if (!pager || pager_in_use())
return;
setenv("GIT_PAGER_IN_USE", "true", 1);
--
1.7.8.36.g69ee2
^ permalink raw reply related
* [PATCH v4 06/13] column: add columnar layout
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw)
To: git; +Cc: Nguyễn Thái Ngọc Duy
In-Reply-To: <1328276078-27955-1-git-send-email-pclouds@gmail.com>
COL_MODE_COLUMN and COL_MODE_ROW fill column by column (or row by row
respectively), given the terminal width and how many space between
columns.
Strings are supposed to be in UTF-8. If strings contain ANSI escape
strings, COL_ANSI must be specified for correct length calculation.
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
column.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
column.h | 3 +
t/t9002-column.sh | 86 +++++++++++++++++++++++++++++++++++
3 files changed, 219 insertions(+), 1 deletions(-)
diff --git a/column.c b/column.c
index bd15bea..4681106 100644
--- a/column.c
+++ b/column.c
@@ -2,8 +2,66 @@
#include "column.h"
#include "string-list.h"
#include "parse-options.h"
+#include "utf8.h"
#define MODE(mode) ((mode) & COL_MODE)
+#define XY2LINEAR(d,x,y) (MODE((d)->mode) == COL_MODE_COLUMN ? \
+ (x) * (d)->rows + (y) : \
+ (y) * (d)->cols + (x))
+
+struct column_data {
+ const struct string_list *list; /* list of all cells */
+ int mode; /* COL_MODE */
+ int total_width; /* terminal width */
+ int padding; /* cell padding */
+ const char *indent; /* left most column indentation */
+ const char *nl;
+
+ int rows, cols;
+ int *len; /* cell length */
+};
+
+/* return length of 's' in letters, ANSI escapes stripped */
+static int item_length(int mode, const char *s)
+{
+ int len, i = 0;
+ struct strbuf str = STRBUF_INIT;
+
+ if (!(mode & COL_ANSI))
+ return utf8_strwidth(s);
+
+ strbuf_addstr(&str, s);
+ while ((s = strstr(str.buf + i, "\033[")) != NULL) {
+ int len = strspn(s + 2, "0123456789;");
+ i = s - str.buf;
+ strbuf_remove(&str, i, len + 3); /* \033[<len><func char> */
+ }
+ len = utf8_strwidth(str.buf);
+ strbuf_release(&str);
+ return len;
+}
+
+/*
+ * Calculate cell width, rows and cols for a table of equal cells, given
+ * table width and how many spaces between cells.
+ */
+static void layout(struct column_data *data, int *width)
+{
+ int i;
+
+ *width = 0;
+ for (i = 0; i < data->list->nr; i++)
+ if (*width < data->len[i])
+ *width = data->len[i];
+
+ *width += data->padding;
+
+ data->cols = (data->total_width - strlen(data->indent)) / *width;
+ if (data->cols == 0)
+ data->cols = 1;
+
+ data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
+}
struct string_list_item *add_cell_to_list(struct string_list *list,
int mode,
@@ -30,6 +88,65 @@ static void display_plain(const struct string_list *list,
printf("%s%s%s", indent, list->items[i].string, nl);
}
+/* Print a cell to stdout with all necessary leading/traling space */
+static int display_cell(struct column_data *data, int initial_width,
+ const char *empty_cell, int x, int y)
+{
+ int i, len, newline;
+
+ i = XY2LINEAR(data, x, y);
+ if (i >= data->list->nr)
+ return -1;
+ len = data->len[i];
+ if (MODE(data->mode) == COL_MODE_COLUMN)
+ newline = i + data->rows >= data->list->nr;
+ else
+ newline = x == data->cols - 1 || i == data->list->nr - 1;
+
+ printf("%s%s%s",
+ x == 0 ? data->indent : "",
+ data->list->items[i].string,
+ newline ? data->nl : empty_cell + len);
+ return 0;
+}
+
+/* Display COL_MODE_COLUMN or COL_MODE_ROW */
+static void display_table(const struct string_list *list,
+ int mode, int total_width,
+ int padding, const char *indent,
+ const char *nl)
+{
+ struct column_data data;
+ int x, y, i, initial_width;
+ char *empty_cell;
+
+ memset(&data, 0, sizeof(data));
+ data.list = list;
+ data.mode = mode;
+ data.total_width = total_width;
+ data.padding = padding;
+ data.indent = indent;
+ data.nl = nl;
+
+ data.len = xmalloc(sizeof(*data.len) * list->nr);
+ for (i = 0; i < list->nr; i++)
+ data.len[i] = item_length(mode, list->items[i].string);
+
+ layout(&data, &initial_width);
+
+ empty_cell = xmalloc(initial_width + 1);
+ memset(empty_cell, ' ', initial_width);
+ empty_cell[initial_width] = '\0';
+ for (y = 0; y < data.rows; y++) {
+ for (x = 0; x < data.cols; x++)
+ if (display_cell(&data, initial_width, empty_cell, x, y))
+ break;
+ }
+
+ free(data.len);
+ free(empty_cell);
+}
+
void print_columns(const struct string_list *list, int mode,
struct column_options *opts)
{
@@ -51,7 +168,16 @@ void print_columns(const struct string_list *list, int mode,
display_plain(list, indent, nl);
return;
}
- die("BUG: invalid mode %d", MODE(mode));
+
+ switch (MODE(mode)) {
+ case COL_MODE_ROW:
+ case COL_MODE_COLUMN:
+ display_table(list, mode, width, padding, indent, nl);
+ break;
+
+ default:
+ die("BUG: invalid mode %d", MODE(mode));
+ }
}
struct colopt {
@@ -113,6 +239,9 @@ static int parse_option(const char *arg, int len,
{ ENABLE, "always", 1 },
{ ENABLE, "never", 0 },
{ ENABLE, "auto", -1 },
+ { MODE, "column", COL_MODE_COLUMN },
+ { MODE, "row", COL_MODE_ROW },
+ { OPTION, "color", COL_ANSI },
};
int i, set, name_len;
diff --git a/column.h b/column.h
index 59f26dc..38976ea 100644
--- a/column.h
+++ b/column.h
@@ -2,8 +2,11 @@
#define COLUMN_H
#define COL_MODE 0x000F
+#define COL_MODE_COLUMN 0 /* Fill columns before rows */
+#define COL_MODE_ROW 1 /* Fill rows before columns */
#define COL_ENABLED (1 << 4)
#define COL_ENABLED_SET (1 << 5) /* Has COL_ENABLED been set by config? */
+#define COL_ANSI (1 << 6) /* Remove ANSI escapes from string length */
struct column_options {
int width;
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index b0b6d62..cffb029 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -24,4 +24,90 @@ test_expect_success 'never' '
test_cmp lista actual
'
+test_expect_success '80 columns' '
+ cat >expected <<\EOF &&
+one two three four five six seven eight nine ten eleven
+EOF
+ COLUMNS=80 git column --mode=column <lista >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'COLUMNS = 1' '
+ cat >expected <<\EOF &&
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+ COLUMNS=1 git column --mode=column <lista >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'width = 1' '
+ git column --mode=column --width=1 <lista >actual &&
+ test_cmp expected actual
+'
+
+COLUMNS=20
+export COLUMNS
+
+test_expect_success '20 columns' '
+ cat >expected <<\EOF &&
+one seven
+two eight
+three nine
+four ten
+five eleven
+six
+EOF
+ git column --mode=column <lista >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '20 columns, padding 2' '
+ cat >expected <<\EOF &&
+one seven
+two eight
+three nine
+four ten
+five eleven
+six
+EOF
+ git column --mode=column --padding 2 <lista >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '20 columns, indented' '
+ cat >expected <<\EOF &&
+ one seven
+ two eight
+ three nine
+ four ten
+ five eleven
+ six
+EOF
+ git column --mode=column --indent=" " <lista >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success '20 columns, row first' '
+ cat >expected <<\EOF &&
+one two
+three four
+five six
+seven eight
+nine ten
+eleven
+EOF
+ git column --mode=row <lista >actual &&
+ test_cmp expected actual
+'
+
test_done
--
1.7.8.36.g69ee2
^ 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