{"thread":{"id":"4625","subject":"[PATCH] Introduce Git.pm (v3)","startedAt":"2006-06-22T22:02:01Z","lastAt":"2006-06-26T23:20:41Z","messageCount":20,"participants":["Petr Baudis","Junio C Hamano","Jakub Narebski","Nguyễn Thái Ngọc Duy","Eric W. Biederman","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"22312","messageId":"20060622220201.19132.67536.stgit@machine.or.cz","threadId":"4625","inReplyTo":null,"subject":"[PATCH] Introduce Git.pm (v3)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-06-22T22:02:01Z","receivedAt":"2006-06-22T22:02:01Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"This patch introduces a very basic and barebone Git.pm module\nwith a sketch of how the generic interface would look like;\nmost functions are missing, but this should give some good base.\nI will continue expanding it.\n\nMost desirable now is more careful error reporting, generic_in() for feeding\ninput to Git commands and the repository() constructor doing some poking\nwith git-rev-parse to get the git directory and subdirectory prefix.\nThose three are basically the prerequisities for converting git-mv.\n\nCurrently Git.pm just wraps up exec()s of Git commands, but even that\nis not trivial to get right and various Git perl scripts do it in\nvarious inconsistent ways. In addition to Git.pm, there is now also\nGit.xs which provides barebone Git.xs for directly interfacing with\nlibgit.a, and as an example providing the hash_object() function using\nlibgit.\n\nThis adds the Git module, integrates it to the build system and as\nan example converts the git-fmt-merge-msg.perl script to it (the result\nis not very impressive since its advantage is not quite apparent in this\none, but I just picked up the simplest Git user around).\n\nThe changes since v1 are:\n\n\t* s/generic/command/ in the API, added command_pipe() and\n\t  changed behaviour of command() in the scalar context\n\t* Added hash_object() and Git.xs providing the fast implementation\n\t* Better error reporting\n\t* Plenty of random minor stuff\n\nIt's a good thing v2 didn't make it to the list since it contained a huge\nfile which turns out that can be autogenerated at the build time, so v3\njust changes that (and adds .gitignore file and makes some other minor\nchanges).\n\nI consider this patch \"stable\" now. Further enhancements will be posted\nas patches on top of this.\n\nMy current working state is available all the time at\n\n\thttp://pasky.or.cz/~xpasky/git-perl/Git.pm\n\nand an irregularily updated API documentation is at\n\n\thttp://pasky.or.cz/~xpasky/git-perl/Git.html\n\nMany thanks to Jakub Narebski, Junio and others for their feedback.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n---\n\n Makefile               |   12 +\n git-fmt-merge-msg.perl |   10 +\n perl/.gitignore        |    7 +\n perl/Git.pm            |  401 ++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Git.xs            |   60 +++++++\n perl/Makefile.PL       |   21 +++\n 6 files changed, 504 insertions(+), 7 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex a5b6784..4d20b22 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -476,7 +476,8 @@ ### Build rules\n \n all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk\n \n-all:\n+all: perl/Makefile\n+\t$(MAKE) -C perl\n \t$(MAKE) -C templates\n \n strip: $(PROGRAMS) git$X\n@@ -508,7 +509,7 @@ common-cmds.h: Documentation/git-*.txt\n \n $(patsubst %.perl,%,$(SCRIPT_PERL)) : % : %.perl\n \trm -f $@ $@+\n-\tsed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \\\n+\tsed -e '1s|#!.*perl\\(.*\\)|#!$(PERL_PATH_SQ)\\1 -I'\"$$(make -s -C perl instlibdir)\"'|' \\\n \t    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n \t    $@.perl >$@+\n \tchmod +x $@+\n@@ -594,6 +595,9 @@ XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare\n \trm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS)\n \n \n+perl/Makefile:\tperl/Git.pm perl/Makefile.PL\n+\t(cd perl && $(PERL_PATH) Makefile.PL PREFIX=\"$(prefix)\" DEFINE=\"$(ALL_CFLAGS)\" LIBS=\"$(LIBS)\")\n+\n doc:\n \t$(MAKE) -C Documentation all\n \n@@ -649,6 +653,7 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'\n \t$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'\n \t$(MAKE) -C templates install\n+\t$(MAKE) -C perl install\n \t$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'\n \t$(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'\n \tif test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \\\n@@ -716,7 +721,8 @@ clean:\n \trm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \trm -f $(htmldocs).tar.gz $(manpages).tar.gz\n \t$(MAKE) -C Documentation/ clean\n-\t$(MAKE) -C templates clean\n+\t[ ! -e perl/Makefile ] || $(MAKE) -C perl/ clean\n+\t$(MAKE) -C templates/ clean\n \t$(MAKE) -C t/ clean\n \trm -f GIT-VERSION-FILE GIT-CFLAGS\n \ndiff --git a/git-fmt-merge-msg.perl b/git-fmt-merge-msg.perl\nindex 5986e54..c32cafb 100755\n--- a/git-fmt-merge-msg.perl\n+++ b/git-fmt-merge-msg.perl\n@@ -6,6 +6,9 @@ # Read .git/FETCH_HEAD and make a human \n # by grouping branches and tags together to form a single line.\n \n use strict;\n+use Git;\n+\n+my $repo = Git->repository();\n \n my @src;\n my %src;\n@@ -28,13 +31,12 @@ sub andjoin {\n }\n \n sub repoconfig {\n-\tmy ($val) = qx{git-repo-config --get merge.summary};\n+\tmy ($val) = $repo->command_oneline('repo-config', '--get', 'merge.summary');\n \treturn $val;\n }\n \n sub current_branch {\n-\tmy ($bra) = qx{git-symbolic-ref HEAD};\n-\tchomp($bra);\n+\tmy ($bra) = $repo->command_oneline('symbolic-ref', 'HEAD');\n \t$bra =~ s|^refs/heads/||;\n \tif ($bra ne 'master') {\n \t\t$bra = \" into $bra\";\n@@ -47,7 +49,7 @@ sub current_branch {\n sub shortlog {\n \tmy ($tip) = @_;\n \tmy @result;\n-\tforeach ( qx{git-log --no-merges --topo-order --pretty=oneline $tip ^HEAD} ) {\n+\tforeach ($repo->command('log', '--no-merges', '--topo-order', '--pretty=oneline', $tip, '^HEAD')) {\n \t\ts/^[0-9a-f]{40}\\s+//;\n \t\tpush @result, $_;\n \t}\ndiff --git a/perl/.gitignore b/perl/.gitignore\nnew file mode 100644\nindex 0000000..6d778f3\n--- /dev/null\n+++ b/perl/.gitignore\n@@ -0,0 +1,7 @@\n+Git.bs\n+Git.c\n+Makefile\n+blib\n+blibdirs\n+pm_to_blib\n+ppport.h\ndiff --git a/perl/Git.pm b/perl/Git.pm\nnew file mode 100644\nindex 0000000..4bb7c50\n--- /dev/null\n+++ b/perl/Git.pm\n@@ -0,0 +1,401 @@\n+=head1 NAME\n+\n+Git - Perl interface to the Git version control system\n+\n+=cut\n+\n+\n+package Git;\n+\n+use strict;\n+\n+\n+BEGIN {\n+\n+our ($VERSION, @ISA, @EXPORT, @EXPORT_OK);\n+\n+# Totally unstable API.\n+$VERSION = '0.01';\n+\n+\n+=head1 SYNOPSIS\n+\n+  use Git;\n+\n+  my $version = Git::command_oneline('version');\n+\n+  Git::command_noisy('update-server-info');\n+\n+  my $repo = Git->repository (Directory => '/srv/git/cogito.git');\n+\n+\n+  my @revs = $repo->command('rev-list', '--since=last monday', '--all');\n+\n+  my $fh = $repo->command_pipe('rev-list', '--since=last monday', '--all');\n+  my $lastrev = <$fh>; chomp $lastrev;\n+  close $fh; # You may want to test rev-list exit status here\n+\n+  my $lastrev = $repo->command_oneline('rev-list', '--all');\n+\n+=cut\n+\n+\n+require Exporter;\n+\n+@ISA = qw(Exporter);\n+\n+@EXPORT = qw();\n+\n+# Methods which can be called as standalone functions as well:\n+@EXPORT_OK = qw(command command_oneline command_pipe command_noisy);\n+\n+\n+=head1 DESCRIPTION\n+\n+This module provides Perl scripts easy way to interface the Git version control\n+system. The modules have an easy and well-tested way to call arbitrary Git\n+commands; in the future, the interface will also provide specialized methods\n+for doing easily operations which are not totally trivial to do over\n+the generic command interface.\n+\n+While some commands can be executed outside of any context (e.g. 'version'\n+or 'init-db'), most operations require a repository context, which in practice\n+means getting an instance of the Git object using the repository() constructor.\n+(In the future, we will also get a new_repository() constructor.) All commands\n+called as methods of the object are then executed in the context of the\n+repository.\n+\n+TODO: In the future, we might also do\n+\n+\tmy $subdir = $repo->subdir('Documentation');\n+\t# Gets called in the subdirectory context:\n+\t$subdir->command('status');\n+\n+\tmy $remoterepo = $repo->remote_repository (name => 'cogito', branch => 'master');\n+\t$remoterepo ||= Git->remote_repository ('http://git.or.cz/cogito.git/');\n+\tmy @refs = $remoterepo->refs();\n+\n+So far, all functions just die if anything goes wrong. If you don't want that,\n+make appropriate provisions to catch the possible deaths. Better error recovery\n+mechanisms will be provided in the future.\n+\n+Currently, the module merely wraps calls to external Git tools. In the future,\n+it will provide a much faster way to interact with Git by linking directly\n+to libgit. This should be completely opaque to the user, though (performance\n+increate nonwithstanding).\n+\n+=cut\n+\n+\n+use Carp qw(carp croak);\n+\n+require XSLoader;\n+XSLoader::load('Git', $VERSION);\n+\n+}\n+\n+\n+=head1 CONSTRUCTORS\n+\n+=over 4\n+\n+=item repository ( OPTIONS )\n+\n+=item repository ( DIRECTORY )\n+\n+=item repository ()\n+\n+Construct a new repository object.\n+C<OPTIONS> are passed in a hash like fashion, using key and value pairs.\n+Possible options are:\n+\n+B<Repository> - Path to the Git repository.\n+\n+B<WorkingCopy> - Path to the associated working copy; not strictly required\n+as many commands will happily crunch on a bare repository.\n+\n+B<Directory> - Path to the Git working directory in its usual setup. This\n+is just for convenient setting of both C<Repository> and C<WorkingCopy>\n+at once: If the directory as a C<.git> subdirectory, C<Repository> is pointed\n+to the subdirectory and the directory is assumed to be the working copy.\n+If the directory does not have the subdirectory, C<WorkingCopy> is left\n+undefined and C<Repository> is pointed to the directory itself.\n+\n+B<GitPath> - Path to the C<git> binary executable. By default the C<$PATH>\n+is searched for it.\n+\n+You should not use both C<Directory> and either of C<Repository> and\n+C<WorkingCopy> - the results of that are undefined.\n+\n+Alternatively, a directory path may be passed as a single scalar argument\n+to the constructor; it is equivalent to setting only the C<Directory> option\n+field.\n+\n+Calling the constructor with no options whatsoever is equivalent to\n+calling it with C<< Directory => '.' >>.\n+\n+=cut\n+\n+sub repository {\n+\tmy $class = shift;\n+\tmy @args = @_;\n+\tmy %opts = ();\n+\tmy $self;\n+\n+\tif (defined $args[0]) {\n+\t\tif ($#args % 2 != 1) {\n+\t\t\t# Not a hash.\n+\t\t\t$#args == 0 or croak \"bad usage\";\n+\t\t\t%opts = (Directory => $args[0]);\n+\t\t} else {\n+\t\t\t%opts = @args;\n+\t\t}\n+\n+\t\tif ($opts{Directory}) {\n+\t\t\t-d $opts{Directory} or croak \"Directory not found: $!\";\n+\t\t\tif (-d $opts{Directory}.\"/.git\") {\n+\t\t\t\t# TODO: Might make this more clever\n+\t\t\t\t$opts{WorkingCopy} = $opts{Directory};\n+\t\t\t\t$opts{Repository} = $opts{Directory}.\"/.git\";\n+\t\t\t} else {\n+\t\t\t\t$opts{Repository} = $opts{Directory};\n+\t\t\t}\n+\t\t\tdelete $opts{Directory};\n+\t\t}\n+\t}\n+\n+\t$self = { opts => \\%opts };\n+\tbless $self, $class;\n+}\n+\n+\n+=back\n+\n+=head1 METHODS\n+\n+=over 4\n+\n+=item command ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given Git C<COMMAND> (specify it without the 'git-'\n+prefix), optionally with the specified extra C<ARGUMENTS>.\n+\n+The method can be called without any instance or on a specified Git repository\n+(in that case the command will be run in the repository context).\n+\n+In scalar context, it returns all the command output in a single string\n+(verbatim).\n+\n+In array context, it returns an array containing lines printed to the\n+command's stdout (without trailing newlines).\n+\n+In both cases, the command's stdin and stderr are the same as the caller's.\n+\n+=cut\n+\n+sub command {\n+\tmy $fh = command_pipe(@_);\n+\n+\tif (not defined wantarray) {\n+\t\t_cmd_close($fh);\n+\n+\t} elsif (not wantarray) {\n+\t\tlocal $/;\n+\t\tmy $text = <$fh>;\n+\t\t_cmd_close($fh);\n+\t\treturn $text;\n+\n+\t} else {\n+\t\tmy @lines = <$fh>;\n+\t\t_cmd_close($fh);\n+\t\tchomp @lines;\n+\t\treturn @lines;\n+\t}\n+}\n+\n+=item command_oneline ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command()\n+does but always return a scalar string containing the first line\n+of the command's standard output.\n+\n+=cut\n+\n+sub command_oneline {\n+\tmy $fh = command_pipe(@_);\n+\n+\tmy $line = <$fh>;\n+\t_cmd_close($fh);\n+\n+\tchomp $line;\n+\treturn $line;\n+}\n+\n+=item command_pipe ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command()\n+does but return a pipe filehandle from which the command output can be\n+read.\n+\n+=cut\n+\n+sub command_pipe {\n+\tmy ($self, $cmd, @args) = _maybe_self(@_);\n+\n+\t$cmd =~ /^[a-z0-9A-Z_-]+$/ or croak \"bad command: $cmd\";\n+\n+\tmy $pid = open(my $fh, \"-|\");\n+\tif (not defined $pid) {\n+\t\tcroak \"open failed: $!\";\n+\t} elsif ($pid == 0) {\n+\t\t_cmd_exec($self, $cmd, @args);\n+\t}\n+\treturn $fh;\n+}\n+\n+=item command_noisy ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command() does but do not\n+capture the command output - the standard output is not redirected and goes\n+to the standard output of the caller application.\n+\n+While the method is called command_noisy(), you might want to as well use\n+it for the most silent Git commands which you know will never pollute your\n+stdout but you want to avoid the overhead of the pipe setup when calling them.\n+\n+The function returns only after the command has finished running.\n+\n+=cut\n+\n+sub command_noisy {\n+\tmy ($self, $cmd, @args) = _maybe_self(@_);\n+\n+\t$cmd =~ /^[a-z0-9A-Z_-]+$/ or croak \"bad command: $cmd\";\n+\n+\tmy $pid = fork;\n+\tif (not defined $pid) {\n+\t\tcroak \"fork failed: $!\";\n+\t} elsif ($pid == 0) {\n+\t\t_cmd_exec($self, $cmd, @args);\n+\t}\n+\tif (waitpid($pid, 0) > 0 and $? != 0) {\n+\t\tcroak \"exit status: $?\";\n+\t}\n+}\n+\n+=item hash_object ( FILENAME [, TYPE ] )\n+\n+=item hash_object ( FILEHANDLE [, TYPE ] )\n+\n+Compute the SHA1 object id of the given C<FILENAME> (or data waiting in\n+C<FILEHANDLE>) considering it is of the C<TYPE> object type (C<blob>\n+(default), C<commit>, C<tree>).\n+\n+In case of C<FILEHANDLE> passed instead of file name, all the data\n+available are read and hashed, and the filehandle is automatically\n+closed. The file handle should be freshly opened - if you have already\n+read anything from the file handle, the results are undefined (since\n+this function works directly with the file descriptor and internal\n+PerlIO buffering might have messed things up).\n+\n+The method can be called without any instance or on a specified Git repository,\n+it makes zero difference.\n+\n+The function returns the SHA1 hash.\n+\n+Implementation of this function is very fast; no external command calls\n+are involved.\n+\n+=cut\n+\n+# Implemented in Git.xs.\n+\n+\n+=back\n+\n+=head1 TODO\n+\n+This is still fairly crude.\n+We need some good way to report errors back except just dying.\n+\n+=head1 COPYRIGHT\n+\n+Copyright 2006 by Petr Baudis E<lt>pasky@suse.czE<gt>.\n+\n+This module is free software; it may be used, copied, modified\n+and distributed under the terms of the GNU General Public Licence,\n+either version 2, or (at your option) any later version.\n+\n+=cut\n+\n+\n+# Take raw method argument list and return ($obj, @args) in case\n+# the method was called upon an instance and (undef, @args) if\n+# it was called directly.\n+sub _maybe_self {\n+\t# This breaks inheritance. Oh well.\n+\tref $_[0] eq 'Git' ? @_ : (undef, @_);\n+}\n+\n+# When already in the subprocess, set up the appropriate state\n+# for the given repository and execute the git command.\n+sub _cmd_exec {\n+\tmy ($self, @args) = @_;\n+\tif ($self) {\n+\t\t$self->{opts}->{Repository} and $ENV{'GIT_DIR'} = $self->{opts}->{Repository};\n+\t\t$self->{opts}->{WorkingCopy} and chdir($self->{opts}->{WorkingCopy});\n+\t}\n+\tmy $git = $self->{opts}->{GitPath};\n+\t$git ||= 'git';\n+\texec ($git, @args) or croak \"exec failed: $!\";\n+}\n+\n+# Close pipe to a subprocess.\n+sub _cmd_close {\n+\tmy ($fh) = @_;\n+\tif (not close $fh) {\n+\t\tif ($!) {\n+\t\t\t# It's just close, no point in fatalities\n+\t\t\tcarp \"error closing pipe: $!\";\n+\t\t} else {\n+\t\t\tcroak \"exit status: $?\";\n+\t\t}\n+\t}\n+}\n+\n+\n+# Trickery for .xs routines: In order to avoid having some horrid\n+# C code trying to do stuff with undefs and hashes, we gate all\n+# xs calls through the following and in case we are being ran upon\n+# an instance call a C part of the gate which will set up the\n+# environment properly.\n+sub _call_gate {\n+\tmy $xsfunc = shift;\n+\tmy ($self, @args) = _maybe_self(@_);\n+\n+\tif (defined $self) {\n+\t\t# XXX: We ignore the WorkingCopy! To properly support\n+\t\t# that will require heavy changes in libgit.\n+\n+\t\t# XXX: And we ignore everything else as well. libgit\n+\t\t# at least needs to be extended to let us specify\n+\t\t# the $GIT_DIR instead of looking it up in environment.\n+\t\t#xs_call_gate($self->{opts}->{Repository});\n+\t}\n+\n+\t&$xsfunc(@args);\n+}\n+\n+sub AUTOLOAD {\n+\tmy $xsname;\n+\tour $AUTOLOAD;\n+\t($xsname = $AUTOLOAD) =~ s/.*:://;\n+\tcroak \"&Git::$xsname not defined\" if $xsname =~ /^xs_/;\n+\t$xsname = 'xs_'.$xsname;\n+\t_call_gate(\\&$xsname, @_);\n+}\n+\n+sub DESTROY { }\n+\n+\n+1; # Famous last words\ndiff --git a/perl/Git.xs b/perl/Git.xs\nnew file mode 100644\nindex 0000000..33bb3ca\n--- /dev/null\n+++ b/perl/Git.xs\n@@ -0,0 +1,60 @@\n+/* By carefully stacking #includes here (even if WE don't really need them)\n+ * we strive to make the thing actually compile. Git header files aren't very\n+ * nice. Perl headers are one of the signs of the coming apocalypse. */\n+#include <ctype.h>\n+/* Ok, it hasn't been so bad so far. */\n+\n+/* libgit interface */\n+#include \"../cache.h\"\n+\n+/* XS and Perl interface */\n+#include \"EXTERN.h\"\n+#include \"perl.h\"\n+#include \"XSUB.h\"\n+\n+#include \"ppport.h\"\n+\n+\n+MODULE = Git\t\tPACKAGE = Git\t\t\n+\n+# /* TODO: xs_call_gate(). See Git.pm. */\n+\n+char *\n+xs_hash_object(file, type = \"blob\")\n+\tSV *file;\n+\tchar *type;\n+CODE:\n+\tunsigned char sha1[20];\n+\n+\tif (SvTYPE(file) == SVt_RV)\n+\t\tfile = SvRV(file);\n+\n+\tif (SvTYPE(file) == SVt_PVGV) {\n+\t\t/* Filehandle */\n+\t\tPerlIO *pio;\n+\n+\t\tpio = IoIFP(sv_2io(file));\n+\t\tif (!pio)\n+\t\t\tcroak(\"You passed me something weird - a dir glob?\");\n+\t\t/* XXX: I just hope PerlIO didn't read anything from it yet.\n+\t\t * --pasky */\n+\t\tif (index_pipe(sha1, PerlIO_fileno(pio), type, 0))\n+\t\t\tcroak(\"Unable to hash given filehandle\");\n+\t\t/* Avoid any nasty surprises. */\n+\t\tPerl_io_close(sv_2io(file), 1);\n+\n+\t} else {\n+\t\t/* String */\n+\t\tchar *path = SvPV_nolen(file);\n+\t\tint fd = open(path, O_RDONLY);\n+\t\tstruct stat st;\n+\n+\t\tif (fd < 0 ||\n+\t\t    fstat(fd, &st) < 0 ||\n+\t\t    index_fd(sha1, fd, &st, 0, type))\n+\t\t\tcroak(\"Unable to hash %s\", path);\n+\t\tclose(fd);\n+\t}\n+\tRETVAL = sha1_to_hex(sha1);\n+OUTPUT:\n+\tRETVAL\ndiff --git a/perl/Makefile.PL b/perl/Makefile.PL\nnew file mode 100644\nindex 0000000..dd61056\n--- /dev/null\n+++ b/perl/Makefile.PL\n@@ -0,0 +1,21 @@\n+use ExtUtils::MakeMaker;\n+\n+sub MY::postamble {\n+\treturn <<'MAKE_FRAG';\n+instlibdir:\n+\t@echo $(INSTALLSITELIB)\n+\n+MAKE_FRAG\n+}\n+\n+WriteMakefile(\n+\tNAME            => 'Git',\n+\tVERSION_FROM    => 'Git.pm',\n+\tMYEXTLIB        => '../libgit.a',\n+\tINC             => '-I. -I..',\n+);\n+\n+\n+use Devel::PPPort;\n+\n+-s 'ppport.h' or Devel::PPPort::WriteFile();\n"},{"id":"22318","messageId":"7vlkrohj9p.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060622220201.19132.67536.stgit@machine.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-22T23:18:10Z","receivedAt":"2006-06-22T23:18:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> \t* Added hash_object() and Git.xs providing the fast implementation\n> \t* Better error reporting\n> \t* Plenty of random minor stuff\n>\n> It's a good thing v2 didn't make it to the list since it contained a huge\n> file which turns out that can be autogenerated at the build time, so v3\n> just changes that (and adds .gitignore file and makes some other minor\n> changes).\n>\n> I consider this patch \"stable\" now. Further enhancements will be posted\n> as patches on top of this.\n\nEek.  It does not compile for me -- maybe there is more\ndependencies that need to be listed in INSTALL file?\n\nmake -C perl\nmake[1]: Entering directory `/opt/git/git.git/perl'\ncc -c  -I. -I.. -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2   -DVERSION=\\\"0.01\\\" -DXS_VERSION=\\\"0.01\\\" -fPIC \"-I/usr/lib/perl/5.8/CORE\"  -O2 -Wall -Wdeclaration-after-statement -g -DSHA1_HEADER='<openssl/sha.h>'  Git.c\nGit.xs: In function 'XS_Git_xs_hash_object':\nGit.xs:27: warning: ISO C90 forbids mixed declarations and code\nGit.xs:44: warning: passing argument 1 of 'Perl_io_close' from incompatible pointer type\nGit.xs:44: warning: passing argument 2 of 'Perl_io_close' makes pointer from integer without a cast\nGit.xs:44: error: too few arguments to function 'Perl_io_close'\nmake[1]: *** [Git.o] Error 1\nmake[1]: Leaving directory `/opt/git/git.git/perl'\nmake: *** [all] Error 2\n"},{"id":"22320","messageId":"20060622235017.GH21864@pasky.or.cz","threadId":"4625","inReplyTo":"7vlkrohj9p.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-06-22T23:50:17Z","receivedAt":"2006-06-22T23:50:17Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Fri, Jun 23, 2006 at 01:18:10AM CEST, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> > \t* Added hash_object() and Git.xs providing the fast implementation\n> > \t* Better error reporting\n> > \t* Plenty of random minor stuff\n> >\n> > It's a good thing v2 didn't make it to the list since it contained a huge\n> > file which turns out that can be autogenerated at the build time, so v3\n> > just changes that (and adds .gitignore file and makes some other minor\n> > changes).\n> >\n> > I consider this patch \"stable\" now. Further enhancements will be posted\n> > as patches on top of this.\n> \n> Eek.  It does not compile for me -- maybe there is more\n> dependencies that need to be listed in INSTALL file?\n> \n> make -C perl\n> make[1]: Entering directory `/opt/git/git.git/perl'\n> cc -c  -I. -I.. -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2   -DVERSION=\\\"0.01\\\" -DXS_VERSION=\\\"0.01\\\" -fPIC \"-I/usr/lib/perl/5.8/CORE\"  -O2 -Wall -Wdeclaration-after-statement -g -DSHA1_HEADER='<openssl/sha.h>'  Git.c\n> Git.xs: In function 'XS_Git_xs_hash_object':\n> Git.xs:27: warning: ISO C90 forbids mixed declarations and code\n> Git.xs:44: warning: passing argument 1 of 'Perl_io_close' from incompatible pointer type\n> Git.xs:44: warning: passing argument 2 of 'Perl_io_close' makes pointer from integer without a cast\n> Git.xs:44: error: too few arguments to function 'Perl_io_close'\n\nOops, sorry. Apparently, I've digged too deep and unleashed a monster of\nunstable API. Now I've finally discovered perlapio(1) and know I\nshould've just called PerlIO_close(). Below comes a fixed patch, I\ndidn't bother to bump the version number.\n\n---\n\n[PATCH] Introduce Git.pm (v3)\n\nThis patch introduces a very basic and barebone Git.pm module\nwith a sketch of how the generic interface would look like;\nmost functions are missing, but this should give some good base.\nI will continue expanding it.\n\nMost desirable now is more careful error reporting, generic_in() for feeding\ninput to Git commands and the repository() constructor doing some poking\nwith git-rev-parse to get the git directory and subdirectory prefix.\nThose three are basically the prerequisities for converting git-mv.\n\nCurrently Git.pm just wraps up exec()s of Git commands, but even that\nis not trivial to get right and various Git perl scripts do it in\nvarious inconsistent ways. In addition to Git.pm, there is now also\nGit.xs which provides barebone Git.xs for directly interfacing with\nlibgit.a, and as an example providing the hash_object() function using\nlibgit.\n\nThis adds the Git module, integrates it to the build system and as\nan example converts the git-fmt-merge-msg.perl script to it (the result\nis not very impressive since its advantage is not quite apparent in this\none, but I just picked up the simplest Git user around).\n\nThe changes since v1 are:\n\n\t* s/generic/command/ in the API, added command_pipe() and\n\t  changed behaviour of command() in the scalar context\n\t* Added hash_object() and Git.xs providing the fast implementation\n\t* Better error reporting\n\t* Plenty of random minor stuff\n\nIt's a good thing v2 didn't make it to the list since it contained a huge\nfile which turns out that can be autogenerated at the build time, so v3\njust changes that (and adds .gitignore file and makes some other minor\nchanges).\n\nI consider this patch \"stable\" now. Further enhancements will be posted\nas patches on top of this.\n\nMy current working state is available all the time at\n\n\thttp://pasky.or.cz/~xpasky/git-perl/Git.pm\n\nand an irregularily updated API documentation is at\n\n\thttp://pasky.or.cz/~xpasky/git-perl/Git.html\n\nMany thanks to Jakub Narebski, Junio and others for their feedback.\n\nSigned-off-by: Petr Baudis <pasky@suse.cz>\n---\n\n Makefile               |   12 +\n git-fmt-merge-msg.perl |   10 +\n perl/.gitignore        |    7 +\n perl/Git.pm            |  401 ++++++++++++++++++++++++++++++++++++++++++++++++\n perl/Git.xs            |   60 +++++++\n perl/Makefile.PL       |   21 +++\n 6 files changed, 504 insertions(+), 7 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex a5b6784..4d20b22 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -476,7 +476,8 @@ ### Build rules\n \n all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk\n \n-all:\n+all: perl/Makefile\n+\t$(MAKE) -C perl\n \t$(MAKE) -C templates\n \n strip: $(PROGRAMS) git$X\n@@ -508,7 +509,7 @@ common-cmds.h: Documentation/git-*.txt\n \n $(patsubst %.perl,%,$(SCRIPT_PERL)) : % : %.perl\n \trm -f $@ $@+\n-\tsed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \\\n+\tsed -e '1s|#!.*perl\\(.*\\)|#!$(PERL_PATH_SQ)\\1 -I'\"$$(make -s -C perl instlibdir)\"'|' \\\n \t    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n \t    $@.perl >$@+\n \tchmod +x $@+\n@@ -594,6 +595,9 @@ XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare\n \trm -f $@ && $(AR) rcs $@ $(XDIFF_OBJS)\n \n \n+perl/Makefile:\tperl/Git.pm perl/Makefile.PL\n+\t(cd perl && $(PERL_PATH) Makefile.PL PREFIX=\"$(prefix)\" DEFINE=\"$(ALL_CFLAGS)\" LIBS=\"$(LIBS)\")\n+\n doc:\n \t$(MAKE) -C Documentation all\n \n@@ -649,6 +653,7 @@ install: all\n \t$(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)'\n \t$(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)'\n \t$(MAKE) -C templates install\n+\t$(MAKE) -C perl install\n \t$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'\n \t$(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'\n \tif test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \\\n@@ -716,7 +721,8 @@ clean:\n \trm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz\n \trm -f $(htmldocs).tar.gz $(manpages).tar.gz\n \t$(MAKE) -C Documentation/ clean\n-\t$(MAKE) -C templates clean\n+\t[ ! -e perl/Makefile ] || $(MAKE) -C perl/ clean\n+\t$(MAKE) -C templates/ clean\n \t$(MAKE) -C t/ clean\n \trm -f GIT-VERSION-FILE GIT-CFLAGS\n \ndiff --git a/git-fmt-merge-msg.perl b/git-fmt-merge-msg.perl\nindex 5986e54..c32cafb 100755\n--- a/git-fmt-merge-msg.perl\n+++ b/git-fmt-merge-msg.perl\n@@ -6,6 +6,9 @@ # Read .git/FETCH_HEAD and make a human \n # by grouping branches and tags together to form a single line.\n \n use strict;\n+use Git;\n+\n+my $repo = Git->repository();\n \n my @src;\n my %src;\n@@ -28,13 +31,12 @@ sub andjoin {\n }\n \n sub repoconfig {\n-\tmy ($val) = qx{git-repo-config --get merge.summary};\n+\tmy ($val) = $repo->command_oneline('repo-config', '--get', 'merge.summary');\n \treturn $val;\n }\n \n sub current_branch {\n-\tmy ($bra) = qx{git-symbolic-ref HEAD};\n-\tchomp($bra);\n+\tmy ($bra) = $repo->command_oneline('symbolic-ref', 'HEAD');\n \t$bra =~ s|^refs/heads/||;\n \tif ($bra ne 'master') {\n \t\t$bra = \" into $bra\";\n@@ -47,7 +49,7 @@ sub current_branch {\n sub shortlog {\n \tmy ($tip) = @_;\n \tmy @result;\n-\tforeach ( qx{git-log --no-merges --topo-order --pretty=oneline $tip ^HEAD} ) {\n+\tforeach ($repo->command('log', '--no-merges', '--topo-order', '--pretty=oneline', $tip, '^HEAD')) {\n \t\ts/^[0-9a-f]{40}\\s+//;\n \t\tpush @result, $_;\n \t}\ndiff --git a/perl/.gitignore b/perl/.gitignore\nnew file mode 100644\nindex 0000000..6d778f3\n--- /dev/null\n+++ b/perl/.gitignore\n@@ -0,0 +1,7 @@\n+Git.bs\n+Git.c\n+Makefile\n+blib\n+blibdirs\n+pm_to_blib\n+ppport.h\ndiff --git a/perl/Git.pm b/perl/Git.pm\nnew file mode 100644\nindex 0000000..4bb7c50\n--- /dev/null\n+++ b/perl/Git.pm\n@@ -0,0 +1,401 @@\n+=head1 NAME\n+\n+Git - Perl interface to the Git version control system\n+\n+=cut\n+\n+\n+package Git;\n+\n+use strict;\n+\n+\n+BEGIN {\n+\n+our ($VERSION, @ISA, @EXPORT, @EXPORT_OK);\n+\n+# Totally unstable API.\n+$VERSION = '0.01';\n+\n+\n+=head1 SYNOPSIS\n+\n+  use Git;\n+\n+  my $version = Git::command_oneline('version');\n+\n+  Git::command_noisy('update-server-info');\n+\n+  my $repo = Git->repository (Directory => '/srv/git/cogito.git');\n+\n+\n+  my @revs = $repo->command('rev-list', '--since=last monday', '--all');\n+\n+  my $fh = $repo->command_pipe('rev-list', '--since=last monday', '--all');\n+  my $lastrev = <$fh>; chomp $lastrev;\n+  close $fh; # You may want to test rev-list exit status here\n+\n+  my $lastrev = $repo->command_oneline('rev-list', '--all');\n+\n+=cut\n+\n+\n+require Exporter;\n+\n+@ISA = qw(Exporter);\n+\n+@EXPORT = qw();\n+\n+# Methods which can be called as standalone functions as well:\n+@EXPORT_OK = qw(command command_oneline command_pipe command_noisy);\n+\n+\n+=head1 DESCRIPTION\n+\n+This module provides Perl scripts easy way to interface the Git version control\n+system. The modules have an easy and well-tested way to call arbitrary Git\n+commands; in the future, the interface will also provide specialized methods\n+for doing easily operations which are not totally trivial to do over\n+the generic command interface.\n+\n+While some commands can be executed outside of any context (e.g. 'version'\n+or 'init-db'), most operations require a repository context, which in practice\n+means getting an instance of the Git object using the repository() constructor.\n+(In the future, we will also get a new_repository() constructor.) All commands\n+called as methods of the object are then executed in the context of the\n+repository.\n+\n+TODO: In the future, we might also do\n+\n+\tmy $subdir = $repo->subdir('Documentation');\n+\t# Gets called in the subdirectory context:\n+\t$subdir->command('status');\n+\n+\tmy $remoterepo = $repo->remote_repository (name => 'cogito', branch => 'master');\n+\t$remoterepo ||= Git->remote_repository ('http://git.or.cz/cogito.git/');\n+\tmy @refs = $remoterepo->refs();\n+\n+So far, all functions just die if anything goes wrong. If you don't want that,\n+make appropriate provisions to catch the possible deaths. Better error recovery\n+mechanisms will be provided in the future.\n+\n+Currently, the module merely wraps calls to external Git tools. In the future,\n+it will provide a much faster way to interact with Git by linking directly\n+to libgit. This should be completely opaque to the user, though (performance\n+increate nonwithstanding).\n+\n+=cut\n+\n+\n+use Carp qw(carp croak);\n+\n+require XSLoader;\n+XSLoader::load('Git', $VERSION);\n+\n+}\n+\n+\n+=head1 CONSTRUCTORS\n+\n+=over 4\n+\n+=item repository ( OPTIONS )\n+\n+=item repository ( DIRECTORY )\n+\n+=item repository ()\n+\n+Construct a new repository object.\n+C<OPTIONS> are passed in a hash like fashion, using key and value pairs.\n+Possible options are:\n+\n+B<Repository> - Path to the Git repository.\n+\n+B<WorkingCopy> - Path to the associated working copy; not strictly required\n+as many commands will happily crunch on a bare repository.\n+\n+B<Directory> - Path to the Git working directory in its usual setup. This\n+is just for convenient setting of both C<Repository> and C<WorkingCopy>\n+at once: If the directory as a C<.git> subdirectory, C<Repository> is pointed\n+to the subdirectory and the directory is assumed to be the working copy.\n+If the directory does not have the subdirectory, C<WorkingCopy> is left\n+undefined and C<Repository> is pointed to the directory itself.\n+\n+B<GitPath> - Path to the C<git> binary executable. By default the C<$PATH>\n+is searched for it.\n+\n+You should not use both C<Directory> and either of C<Repository> and\n+C<WorkingCopy> - the results of that are undefined.\n+\n+Alternatively, a directory path may be passed as a single scalar argument\n+to the constructor; it is equivalent to setting only the C<Directory> option\n+field.\n+\n+Calling the constructor with no options whatsoever is equivalent to\n+calling it with C<< Directory => '.' >>.\n+\n+=cut\n+\n+sub repository {\n+\tmy $class = shift;\n+\tmy @args = @_;\n+\tmy %opts = ();\n+\tmy $self;\n+\n+\tif (defined $args[0]) {\n+\t\tif ($#args % 2 != 1) {\n+\t\t\t# Not a hash.\n+\t\t\t$#args == 0 or croak \"bad usage\";\n+\t\t\t%opts = (Directory => $args[0]);\n+\t\t} else {\n+\t\t\t%opts = @args;\n+\t\t}\n+\n+\t\tif ($opts{Directory}) {\n+\t\t\t-d $opts{Directory} or croak \"Directory not found: $!\";\n+\t\t\tif (-d $opts{Directory}.\"/.git\") {\n+\t\t\t\t# TODO: Might make this more clever\n+\t\t\t\t$opts{WorkingCopy} = $opts{Directory};\n+\t\t\t\t$opts{Repository} = $opts{Directory}.\"/.git\";\n+\t\t\t} else {\n+\t\t\t\t$opts{Repository} = $opts{Directory};\n+\t\t\t}\n+\t\t\tdelete $opts{Directory};\n+\t\t}\n+\t}\n+\n+\t$self = { opts => \\%opts };\n+\tbless $self, $class;\n+}\n+\n+\n+=back\n+\n+=head1 METHODS\n+\n+=over 4\n+\n+=item command ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given Git C<COMMAND> (specify it without the 'git-'\n+prefix), optionally with the specified extra C<ARGUMENTS>.\n+\n+The method can be called without any instance or on a specified Git repository\n+(in that case the command will be run in the repository context).\n+\n+In scalar context, it returns all the command output in a single string\n+(verbatim).\n+\n+In array context, it returns an array containing lines printed to the\n+command's stdout (without trailing newlines).\n+\n+In both cases, the command's stdin and stderr are the same as the caller's.\n+\n+=cut\n+\n+sub command {\n+\tmy $fh = command_pipe(@_);\n+\n+\tif (not defined wantarray) {\n+\t\t_cmd_close($fh);\n+\n+\t} elsif (not wantarray) {\n+\t\tlocal $/;\n+\t\tmy $text = <$fh>;\n+\t\t_cmd_close($fh);\n+\t\treturn $text;\n+\n+\t} else {\n+\t\tmy @lines = <$fh>;\n+\t\t_cmd_close($fh);\n+\t\tchomp @lines;\n+\t\treturn @lines;\n+\t}\n+}\n+\n+=item command_oneline ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command()\n+does but always return a scalar string containing the first line\n+of the command's standard output.\n+\n+=cut\n+\n+sub command_oneline {\n+\tmy $fh = command_pipe(@_);\n+\n+\tmy $line = <$fh>;\n+\t_cmd_close($fh);\n+\n+\tchomp $line;\n+\treturn $line;\n+}\n+\n+=item command_pipe ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command()\n+does but return a pipe filehandle from which the command output can be\n+read.\n+\n+=cut\n+\n+sub command_pipe {\n+\tmy ($self, $cmd, @args) = _maybe_self(@_);\n+\n+\t$cmd =~ /^[a-z0-9A-Z_-]+$/ or croak \"bad command: $cmd\";\n+\n+\tmy $pid = open(my $fh, \"-|\");\n+\tif (not defined $pid) {\n+\t\tcroak \"open failed: $!\";\n+\t} elsif ($pid == 0) {\n+\t\t_cmd_exec($self, $cmd, @args);\n+\t}\n+\treturn $fh;\n+}\n+\n+=item command_noisy ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command() does but do not\n+capture the command output - the standard output is not redirected and goes\n+to the standard output of the caller application.\n+\n+While the method is called command_noisy(), you might want to as well use\n+it for the most silent Git commands which you know will never pollute your\n+stdout but you want to avoid the overhead of the pipe setup when calling them.\n+\n+The function returns only after the command has finished running.\n+\n+=cut\n+\n+sub command_noisy {\n+\tmy ($self, $cmd, @args) = _maybe_self(@_);\n+\n+\t$cmd =~ /^[a-z0-9A-Z_-]+$/ or croak \"bad command: $cmd\";\n+\n+\tmy $pid = fork;\n+\tif (not defined $pid) {\n+\t\tcroak \"fork failed: $!\";\n+\t} elsif ($pid == 0) {\n+\t\t_cmd_exec($self, $cmd, @args);\n+\t}\n+\tif (waitpid($pid, 0) > 0 and $? != 0) {\n+\t\tcroak \"exit status: $?\";\n+\t}\n+}\n+\n+=item hash_object ( FILENAME [, TYPE ] )\n+\n+=item hash_object ( FILEHANDLE [, TYPE ] )\n+\n+Compute the SHA1 object id of the given C<FILENAME> (or data waiting in\n+C<FILEHANDLE>) considering it is of the C<TYPE> object type (C<blob>\n+(default), C<commit>, C<tree>).\n+\n+In case of C<FILEHANDLE> passed instead of file name, all the data\n+available are read and hashed, and the filehandle is automatically\n+closed. The file handle should be freshly opened - if you have already\n+read anything from the file handle, the results are undefined (since\n+this function works directly with the file descriptor and internal\n+PerlIO buffering might have messed things up).\n+\n+The method can be called without any instance or on a specified Git repository,\n+it makes zero difference.\n+\n+The function returns the SHA1 hash.\n+\n+Implementation of this function is very fast; no external command calls\n+are involved.\n+\n+=cut\n+\n+# Implemented in Git.xs.\n+\n+\n+=back\n+\n+=head1 TODO\n+\n+This is still fairly crude.\n+We need some good way to report errors back except just dying.\n+\n+=head1 COPYRIGHT\n+\n+Copyright 2006 by Petr Baudis E<lt>pasky@suse.czE<gt>.\n+\n+This module is free software; it may be used, copied, modified\n+and distributed under the terms of the GNU General Public Licence,\n+either version 2, or (at your option) any later version.\n+\n+=cut\n+\n+\n+# Take raw method argument list and return ($obj, @args) in case\n+# the method was called upon an instance and (undef, @args) if\n+# it was called directly.\n+sub _maybe_self {\n+\t# This breaks inheritance. Oh well.\n+\tref $_[0] eq 'Git' ? @_ : (undef, @_);\n+}\n+\n+# When already in the subprocess, set up the appropriate state\n+# for the given repository and execute the git command.\n+sub _cmd_exec {\n+\tmy ($self, @args) = @_;\n+\tif ($self) {\n+\t\t$self->{opts}->{Repository} and $ENV{'GIT_DIR'} = $self->{opts}->{Repository};\n+\t\t$self->{opts}->{WorkingCopy} and chdir($self->{opts}->{WorkingCopy});\n+\t}\n+\tmy $git = $self->{opts}->{GitPath};\n+\t$git ||= 'git';\n+\texec ($git, @args) or croak \"exec failed: $!\";\n+}\n+\n+# Close pipe to a subprocess.\n+sub _cmd_close {\n+\tmy ($fh) = @_;\n+\tif (not close $fh) {\n+\t\tif ($!) {\n+\t\t\t# It's just close, no point in fatalities\n+\t\t\tcarp \"error closing pipe: $!\";\n+\t\t} else {\n+\t\t\tcroak \"exit status: $?\";\n+\t\t}\n+\t}\n+}\n+\n+\n+# Trickery for .xs routines: In order to avoid having some horrid\n+# C code trying to do stuff with undefs and hashes, we gate all\n+# xs calls through the following and in case we are being ran upon\n+# an instance call a C part of the gate which will set up the\n+# environment properly.\n+sub _call_gate {\n+\tmy $xsfunc = shift;\n+\tmy ($self, @args) = _maybe_self(@_);\n+\n+\tif (defined $self) {\n+\t\t# XXX: We ignore the WorkingCopy! To properly support\n+\t\t# that will require heavy changes in libgit.\n+\n+\t\t# XXX: And we ignore everything else as well. libgit\n+\t\t# at least needs to be extended to let us specify\n+\t\t# the $GIT_DIR instead of looking it up in environment.\n+\t\t#xs_call_gate($self->{opts}->{Repository});\n+\t}\n+\n+\t&$xsfunc(@args);\n+}\n+\n+sub AUTOLOAD {\n+\tmy $xsname;\n+\tour $AUTOLOAD;\n+\t($xsname = $AUTOLOAD) =~ s/.*:://;\n+\tcroak \"&Git::$xsname not defined\" if $xsname =~ /^xs_/;\n+\t$xsname = 'xs_'.$xsname;\n+\t_call_gate(\\&$xsname, @_);\n+}\n+\n+sub DESTROY { }\n+\n+\n+1; # Famous last words\ndiff --git a/perl/Git.xs b/perl/Git.xs\nnew file mode 100644\nindex 0000000..3799ee9\n--- /dev/null\n+++ b/perl/Git.xs\n@@ -0,0 +1,60 @@\n+/* By carefully stacking #includes here (even if WE don't really need them)\n+ * we strive to make the thing actually compile. Git header files aren't very\n+ * nice. Perl headers are one of the signs of the coming apocalypse. */\n+#include <ctype.h>\n+/* Ok, it hasn't been so bad so far. */\n+\n+/* libgit interface */\n+#include \"../cache.h\"\n+\n+/* XS and Perl interface */\n+#include \"EXTERN.h\"\n+#include \"perl.h\"\n+#include \"XSUB.h\"\n+\n+#include \"ppport.h\"\n+\n+\n+MODULE = Git\t\tPACKAGE = Git\t\t\n+\n+# /* TODO: xs_call_gate(). See Git.pm. */\n+\n+char *\n+xs_hash_object(file, type = \"blob\")\n+\tSV *file;\n+\tchar *type;\n+CODE:\n+\tunsigned char sha1[20];\n+\n+\tif (SvTYPE(file) == SVt_RV)\n+\t\tfile = SvRV(file);\n+\n+\tif (SvTYPE(file) == SVt_PVGV) {\n+\t\t/* Filehandle */\n+\t\tPerlIO *pio;\n+\n+\t\tpio = IoIFP(sv_2io(file));\n+\t\tif (!pio)\n+\t\t\tcroak(\"You passed me something weird - a dir glob?\");\n+\t\t/* XXX: I just hope PerlIO didn't read anything from it yet.\n+\t\t * --pasky */\n+\t\tif (index_pipe(sha1, PerlIO_fileno(pio), type, 0))\n+\t\t\tcroak(\"Unable to hash given filehandle\");\n+\t\t/* Avoid any nasty surprises. */\n+\t\tPerlIO_close(pio);\n+\n+\t} else {\n+\t\t/* String */\n+\t\tchar *path = SvPV_nolen(file);\n+\t\tint fd = open(path, O_RDONLY);\n+\t\tstruct stat st;\n+\n+\t\tif (fd < 0 ||\n+\t\t    fstat(fd, &st) < 0 ||\n+\t\t    index_fd(sha1, fd, &st, 0, type))\n+\t\t\tcroak(\"Unable to hash %s\", path);\n+\t\tclose(fd);\n+\t}\n+\tRETVAL = sha1_to_hex(sha1);\n+OUTPUT:\n+\tRETVAL\ndiff --git a/perl/Makefile.PL b/perl/Makefile.PL\nnew file mode 100644\nindex 0000000..dd61056\n--- /dev/null\n+++ b/perl/Makefile.PL\n@@ -0,0 +1,21 @@\n+use ExtUtils::MakeMaker;\n+\n+sub MY::postamble {\n+\treturn <<'MAKE_FRAG';\n+instlibdir:\n+\t@echo $(INSTALLSITELIB)\n+\n+MAKE_FRAG\n+}\n+\n+WriteMakefile(\n+\tNAME            => 'Git',\n+\tVERSION_FROM    => 'Git.pm',\n+\tMYEXTLIB        => '../libgit.a',\n+\tINC             => '-I. -I..',\n+);\n+\n+\n+use Devel::PPPort;\n+\n+-s 'ppport.h' or Devel::PPPort::WriteFile();\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nA person is just about as big as the things that make them angry.\n"},{"id":"22323","messageId":"7v1wtghga6.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060622235017.GH21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-23T00:22:41Z","receivedAt":"2006-06-23T00:22:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>> Eek.  It does not compile for me -- maybe there is more\n>> dependencies that need to be listed in INSTALL file?\n>> ...\n>> Git.xs: In function 'XS_Git_xs_hash_object':\n>> Git.xs:27: warning: ISO C90 forbids mixed declarations and code\n>> Git.xs:44: warning: passing argument 1 of 'Perl_io_close' from incompatible pointer type\n>> Git.xs:44: warning: passing argument 2 of 'Perl_io_close' makes pointer from integer without a cast\n>> Git.xs:44: error: too few arguments to function 'Perl_io_close'\n>\n> Oops, sorry. Apparently, I've digged too deep and unleashed a monster of\n> unstable API. Now I've finally discovered perlapio(1) and know I\n> should've just called PerlIO_close(). Below comes a fixed patch, I\n> didn't bother to bump the version number.\n\nThanks; it compiles now with a few more glitches.\n\n            /usr/bin/perl /usr/share/perl/5.8/ExtUtils/xsubpp  \\\n                    -typemap /usr/share/perl/5.8/ExtUtils/typemap  Git.xs > Git.xsc && \\\n                    mv Git.xsc Git.c\n            Please specify prototyping behavior for Git.xs (see perlxs manual)\n\nSays xsubpp.\n\n        cc -c  -I. -I.. -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS \\\n                -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include \\\n                -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 \\\n                -DVERSION=\\\"0.01\\\" -DXS_VERSION=\\\"0.01\\\" -fPIC \\\n                \"-I/usr/lib/perl/5.8/CORE\" -Wall\n                -Wdeclaration-after-statement \\\n                -g -DSHA1_HEADER='<openssl/sha.h>' \\\n                -DGIT_VERSION=\\\"1.4.1.rc1.g01a1\\\" Git.c\n        Git.xs: In function 'XS_Git_xs__execv_git_cmd':\n        Git.xs:57: warning: passing argument 1 of 'free' discards qualifiers from pointer target type\n        Git.xs: In function 'XS_Git_xs_hash_object':\n        Git.xs:65: warning: ISO C90 forbids mixed declarations and code\n\nI usually compile with -Wdeclaration-after-statement so I\nprobably get some more warnings than you saw; it probably is\nprimarily xsubpp's fault, but you could work it around by having\nCODE block to be inside an extra set of braces {}.  Constness\nreduction of free() is a bit annoying from the point of view of\nthe coder who has to cast away constness, so I won't be too\nstrict about that, but it would be nicer if we did not have to\nsee the warnings.\n\n        rm -f blib/arch/auto/Git/Git.so\n        cc  -shared -L/usr/local/lib Git.o  -o blib/arch/auto/Git/Git.so ../libgit.a\t\\\n                   -lz -lcrypto  \t\\\n\n        /usr/bin/ld: ../libgit.a(exec_cmd.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC\n        ../libgit.a: could not read symbols: Bad value\n        collect2: ld returned 1 exit status\n        make[1]: *** [blib/arch/auto/Git/Git.so] Error 1\n\nThis is a real killer.  If we compile everything with -fPIC,\nthis goes away, but I do not think we want -fPIC for the core\nlevel tools.  At least not until we are ready to do libgit.so.\n"},{"id":"22326","messageId":"20060623011205.GJ21864@pasky.or.cz","threadId":"4625","inReplyTo":"7v1wtghga6.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-06-23T01:12:05Z","receivedAt":"2006-06-23T01:12:05Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Fri, Jun 23, 2006 at 02:22:41AM CEST, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> >> Eek.  It does not compile for me -- maybe there is more\n> >> dependencies that need to be listed in INSTALL file?\n> >> ...\n> >> Git.xs: In function 'XS_Git_xs_hash_object':\n> >> Git.xs:27: warning: ISO C90 forbids mixed declarations and code\n> >> Git.xs:44: warning: passing argument 1 of 'Perl_io_close' from incompatible pointer type\n> >> Git.xs:44: warning: passing argument 2 of 'Perl_io_close' makes pointer from integer without a cast\n> >> Git.xs:44: error: too few arguments to function 'Perl_io_close'\n> >\n> > Oops, sorry. Apparently, I've digged too deep and unleashed a monster of\n> > unstable API. Now I've finally discovered perlapio(1) and know I\n> > should've just called PerlIO_close(). Below comes a fixed patch, I\n> > didn't bother to bump the version number.\n> \n> Thanks; it compiles now with a few more glitches.\n> \n>             /usr/bin/perl /usr/share/perl/5.8/ExtUtils/xsubpp  \\\n>                     -typemap /usr/share/perl/5.8/ExtUtils/typemap  Git.xs > Git.xsc && \\\n>                     mv Git.xsc Git.c\n>             Please specify prototyping behavior for Git.xs (see perlxs manual)\n> \n> Says xsubpp.\n\nIt's harmless but can be fixed by:\n\ndiff --git a/perl/Git.xs b/perl/Git.xs\nindex 3799ee9..8ab84bb 100644\n--- a/perl/Git.xs\n+++ b/perl/Git.xs\n@@ -17,6 +17,8 @@ #include \"ppport.h\"\n \n MODULE = Git\t\tPACKAGE = Git\t\t\n \n+PROTOTYPES: DISABLE\n+\n # /* TODO: xs_call_gate(). See Git.pm. */\n \n char *\n\n>         cc -c  -I. -I.. -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS \\\n>                 -DDEBIAN -fno-strict-aliasing -pipe -I/usr/local/include \\\n>                 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 \\\n>                 -DVERSION=\\\"0.01\\\" -DXS_VERSION=\\\"0.01\\\" -fPIC \\\n>                 \"-I/usr/lib/perl/5.8/CORE\" -Wall\n>                 -Wdeclaration-after-statement \\\n>                 -g -DSHA1_HEADER='<openssl/sha.h>' \\\n>                 -DGIT_VERSION=\\\"1.4.1.rc1.g01a1\\\" Git.c\n>         Git.xs: In function 'XS_Git_xs__execv_git_cmd':\n>         Git.xs:57: warning: passing argument 1 of 'free' discards qualifiers from pointer target type\n>         Git.xs: In function 'XS_Git_xs_hash_object':\n>         Git.xs:65: warning: ISO C90 forbids mixed declarations and code\n> \n> I usually compile with -Wdeclaration-after-statement so I\n> probably get some more warnings than you saw; it probably is\n> primarily xsubpp's fault, but you could work it around by having\n> CODE block to be inside an extra set of braces {}.\n\nSure. Should I resend all the .xs-related patches with the code blocks\nin {}, or will you add it at your side?\n\n> Constness reduction of free() is a bit annoying from the point of view of\n> the coder who has to cast away constness, so I won't be too\n> strict about that, but it would be nicer if we did not have to\n> see the warnings.\n\nSure, it should be trivial to fix.\n\n>         rm -f blib/arch/auto/Git/Git.so\n>         cc  -shared -L/usr/local/lib Git.o  -o blib/arch/auto/Git/Git.so ../libgit.a\t\\\n>                    -lz -lcrypto  \t\\\n> \n>         /usr/bin/ld: ../libgit.a(exec_cmd.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC\n>         ../libgit.a: could not read symbols: Bad value\n>         collect2: ld returned 1 exit status\n>         make[1]: *** [blib/arch/auto/Git/Git.so] Error 1\n> \n> This is a real killer.  If we compile everything with -fPIC,\n> this goes away, but I do not think we want -fPIC for the core\n> level tools.  At least not until we are ready to do libgit.so.\n\nHmm, I didn't get that; I guess that's x86-64 specific. :/ Do you have\nany idea what the error actually means? Could the environ be a problem?\n(Why aren't we calling just execv()?)\n\nAlso, is there any real problem with just using -fPIC?\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nA person is just about as big as the things that make them angry.\n"},{"id":"22333","messageId":"7vk678fpqy.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060623011205.GJ21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-23T04:41:09Z","receivedAt":"2006-06-23T04:41:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>>         cc  -shared -L/usr/local/lib Git.o  -o blib/arch/auto/Git/Git.so ../libgit.a\t\\\n>>                    -lz -lcrypto  \t\\\n>> \n>>         /usr/bin/ld: ../libgit.a(exec_cmd.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC\n>>         ../libgit.a: could not read symbols: Bad value\n>>         collect2: ld returned 1 exit status\n>>         make[1]: *** [blib/arch/auto/Git/Git.so] Error 1\n>> \n>> This is a real killer.  If we compile everything with -fPIC,\n>> this goes away, but I do not think we want -fPIC for the core\n>> level tools.  At least not until we are ready to do libgit.so.\n>\n> Hmm, I didn't get that; I guess that's x86-64 specific. :/\n\nSo it seems.  Both RH machines I have access at kernel.org and\nDebian machines I have locally exhibit that x86-32 is OK and\nx86-64 is bad.  They all run libc-2.3.6 except RH x86-32 is at\nlibc-2.3.4.\n"},{"id":"22334","messageId":"e7g079$8qt$1@sea.gmane.org","threadId":"4625","inReplyTo":"7vk678fpqy.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-06-23T06:03:23Z","receivedAt":"2006-06-23T06:03:23Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> Petr Baudis <pasky@suse.cz> writes:\n> \n>>>         cc  -shared -L/usr/local/lib Git.o  -o blib/arch/auto/Git/Git.so ../libgit.a        \\\n>>>                    -lz -lcrypto     \\\n>>> \n>>>         /usr/bin/ld: ../libgit.a(exec_cmd.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC\n>>>         ../libgit.a: could not read symbols: Bad value\n>>>         collect2: ld returned 1 exit status\n>>>         make[1]: *** [blib/arch/auto/Git/Git.so] Error 1\n>>> \n>>> This is a real killer.  If we compile everything with -fPIC,\n>>> this goes away, but I do not think we want -fPIC for the core\n>>> level tools.  At least not until we are ready to do libgit.so.\n>>\n>> Hmm, I didn't get that; I guess that's x86-64 specific. :/\n> \n> So it seems.  Both RH machines I have access at kernel.org and\n> Debian machines I have locally exhibit that x86-32 is OK and\n> x86-64 is bad.  They all run libc-2.3.6 except RH x86-32 is at\n> libc-2.3.4.\n\nPerhaps Git.pm should provide also generic, pure Perl (and slower)\nfallback implementation (when for some reason we cannot compile XS).\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"22335","messageId":"fcaeb9bf0606222334x59a76a65l52564a34858d98d4@mail.gmail.com","threadId":"4625","inReplyTo":"e7g079$8qt$1@sea.gmane.org","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2006-06-23T06:34:17Z","receivedAt":"2006-06-23T06:34:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On 6/23/06, Jakub Narebski <jnareb@gmail.com> wrote:\n> Perhaps Git.pm should provide also generic, pure Perl (and slower)\n> fallback implementation (when for some reason we cannot compile XS).\nHaven't looked at Git.pm. But I have written receive-pack in perl. It\nmay have some useful functions for Git.pm\n"},{"id":"22337","messageId":"7vejxgckq9.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060623011205.GJ21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-23T08:57:50Z","receivedAt":"2006-06-23T08:57:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> Also, is there any real problem with just using -fPIC?\n\nPersonally, not really, but I consider it a workaround having to\ncompile with -fPIC (being able to compile with -fPIC is a\nfeature).\n\nDoesn't it have performance implications to use -fPIC when you\ndo not have to?\n\nBy the way, you also need to adjust the testsuite so that it\nfinds the Perl modules from freshly built tree before\ninstalling.  I think (but haven't checked yet) the stuff written\nin Python does that already, so you might want to mimic it.\n"},{"id":"22345","messageId":"m1k678yt6m.fsf@ebiederm.dsl.xmission.com","threadId":"4625","inReplyTo":"7vejxgckq9.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2006-06-23T12:04:17Z","receivedAt":"2006-06-23T12:04:17Z","isPatch":true,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Petr Baudis <pasky@suse.cz> writes:\n>\n>> Also, is there any real problem with just using -fPIC?\n>\n> Personally, not really, but I consider it a workaround having to\n> compile with -fPIC (being able to compile with -fPIC is a\n> feature).\n>\n> Doesn't it have performance implications to use -fPIC when you\n> do not have to?\n>\n> By the way, you also need to adjust the testsuite so that it\n> finds the Perl modules from freshly built tree before\n> installing.  I think (but haven't checked yet) the stuff written\n> in Python does that already, so you might want to mimic it.\n\nSo what was being compiled was a shared Git.so.\n\n32bit x86 is on of the few architectures that allows you to build\na .so without compiling with -fPIC.  \n\nThe question is why are we building with a .so?\n\nEric\n"},{"id":"22351","messageId":"20060623123904.GL21864@pasky.or.cz","threadId":"4625","inReplyTo":"m1k678yt6m.fsf@ebiederm.dsl.xmission.com","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-06-23T12:39:04Z","receivedAt":"2006-06-23T12:39:04Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Fri, Jun 23, 2006 at 10:57:50AM CEST, I got a letter\nwhere Junio C Hamano <junkio@cox.net> said that...\n> Petr Baudis <pasky@suse.cz> writes:\n> \n> > Also, is there any real problem with just using -fPIC?\n> \n> Personally, not really, but I consider it a workaround having to\n> compile with -fPIC (being able to compile with -fPIC is a\n> feature).\n\nWell, for the .xs you do need an .so and for that you apparently need\n-fPIC on most architectures, so there's no way around it.\n\nThere's a patch to build libgit.so, would you take it as an excuse to\nalways compile with -fPIC? ;-)\n\n> Doesn't it have performance implications to use -fPIC when you\n> do not have to?\n\nNo idea here.\n\n> By the way, you also need to adjust the testsuite so that it\n> finds the Perl modules from freshly built tree before\n> installing.  I think (but haven't checked yet) the stuff written\n> in Python does that already, so you might want to mimic it.\n\nIt should be enough to -I../perl/blib/lib -I../perl/blib/arch/auto/Git.\n\n\nDear diary, on Fri, Jun 23, 2006 at 02:04:17PM CEST, I got a letter\nwhere \"Eric W. Biederman\" <ebiederm@xmission.com> said that...\n> The question is why are we building with a .so?\n\nTo make use of it in Git.pm - it can call libgit routines directly from\ninside of Perl, but for that it needs to dynamically link libgit to the\nPerl process on the fly (using dlopen()).\n\nWe _can_ avoid the .so, but that involved producing a new perl\nexecutable with libgit statically linked to it, which is quite\nimpractical, so to say.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nA person is just about as big as the things that make them angry.\n"},{"id":"22353","messageId":"20060623124539.GM21864@pasky.or.cz","threadId":"4625","inReplyTo":"e7g079$8qt$1@sea.gmane.org","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2006-06-23T12:45:39Z","receivedAt":"2006-06-23T12:45:39Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"Dear diary, on Fri, Jun 23, 2006 at 08:03:23AM CEST, I got a letter\nwhere Jakub Narebski <jnareb@gmail.com> said that...\n> Perhaps Git.pm should provide also generic, pure Perl (and slower)\n> fallback implementation (when for some reason we cannot compile XS).\n\nI fiercely want to avoid this if there is any other possible way to go\nabout it - this is a path to hell of massive code duplication and\nadditional work, as the number of routines will grow. If it is question\nof spending many developer-hours uselessly duplicating code in a way\nthat'll be much slower than possible anyway OR building with -fPIC... ;-)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nA person is just about as big as the things that make them angry.\n"},{"id":"22395","messageId":"7vlkrn75fa.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060623123904.GL21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-24T00:39:37Z","receivedAt":"2006-06-24T00:39:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n> There's a patch to build libgit.so, would you take it as an excuse to\n> always compile with -fPIC? ;-)\n\nThe only benerit we might gain from libgit.so in the current\nshape, aside from making it easier to do .xs, is that multiple\ngit processes would share it in core, and the disk consumption\nby 100+ little git commands are reduced -- which largely has\nbecome non-issue with the recent spurt of making everything\nbuilt-ins.  But that \"aside from\" is in itself a big plus, so,\nwell, I am torn. \n"},{"id":"22396","messageId":"7vejxf74e3.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060623123904.GL21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-24T01:01:56Z","receivedAt":"2006-06-24T01:01:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>> By the way, you also need to adjust the testsuite so that it\n>> finds the Perl modules from freshly built tree before\n>> installing.  I think (but haven't checked yet) the stuff written\n>> in Python does that already, so you might want to mimic it.\n>\n> It should be enough to -I../perl/blib/lib -I../perl/blib/arch/auto/Git.\n\n-- >8 --\n[PATCH] Perl interface: add build-time configuration to allow building with -fPIC\n\nOn x86-64 it seems that Git.xs does not link without compiling\nthe main git objects with -fPIC.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n * Also I moved explanation of MOZILLA_SHA1 closer to other SHA1\n   choices.\n\n Makefile |   20 +++++++++++++-------\n 1 files changed, 13 insertions(+), 7 deletions(-)\n\ndiff --git a/Makefile b/Makefile\nindex 7842195..c42521e 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1,11 +1,6 @@\n # The default target of this Makefile is...\n all:\n \n-# Define MOZILLA_SHA1 environment variable when running make to make use of\n-# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast\n-# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default\n-# choice) has very fast version optimized for i586.\n-#\n # Define NO_OPENSSL environment variable if you do not have OpenSSL.\n # This also implies MOZILLA_SHA1.\n #\n@@ -37,6 +32,14 @@ #\n # Define ARM_SHA1 environment variable when running make to make use of\n # a bundled SHA1 routine optimized for ARM.\n #\n+# Define MOZILLA_SHA1 environment variable when running make to make use of\n+# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast\n+# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default\n+# choice) has very fast version optimized for i586.\n+#\n+# Define USE_PIC if you need the main git objects to be built with -fPIC\n+# in order to build and link perl/Git.so.  x86-64 seems to need this.\n+#\n # Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin).\n #\n # Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).\n@@ -63,13 +66,13 @@ #\n # Define COLLISION_CHECK below if you believe that SHA1's\n # 1461501637330902918203684832716283019655932542976 hashes do not give you\n # sufficient guarantee that no collisions between objects will ever happen.\n-\n+#\n # Define USE_NSEC below if you want git to care about sub-second file mtimes\n # and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and\n # it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely\n # randomly break unless your underlying filesystem supports those sub-second\n # times (my ext3 doesn't).\n-\n+#\n # Define USE_STDEV below if you want git to care about the underlying device\n # change being considered an inode change from the update-cache perspective.\n \n@@ -450,6 +453,9 @@ else\n endif\n endif\n endif\n+ifdef USE_PIC\n+\tALL_CFLAGS += -fPIC\n+endif\n ifdef NO_ACCURATE_DIFF\n \tALL_CFLAGS += -DNO_ACCURATE_DIFF\n endif\n-- \n1.4.1.rc1.gf2641\n"},{"id":"22397","messageId":"7v4pyb74al.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"20060623123904.GL21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-24T01:04:02Z","receivedAt":"2006-06-24T01:04:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Petr Baudis <pasky@suse.cz> writes:\n\n>> By the way, you also need to adjust the testsuite so that it\n>> finds the Perl modules from freshly built tree before\n>> installing.  I think (but haven't checked yet) the stuff written\n>> in Python does that already, so you might want to mimic it.\n>\n> It should be enough to -I../perl/blib/lib -I../perl/blib/arch/auto/Git.\n\n-- >8 --\n[PATCH] Perl interface: make testsuite work again.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n t/test-lib.sh |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 05f6e79..fba0c51 100755\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -206,6 +206,8 @@ PYTHON=`sed -e '1{\n \tPYTHONPATH=$(pwd)/../compat\n \texport PYTHONPATH\n }\n+PERL5LIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git\n+export PERL5LIB\n test -d ../templates/blt || {\n \terror \"You haven't built things yet, have you?\"\n }\n-- \n1.4.1.rc1.gf2641\n"},{"id":"22398","messageId":"7vzmg35pkt.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"7vejxf74e3.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-24T01:07:14Z","receivedAt":"2006-06-24T01:07:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n>> It should be enough to -I../perl/blib/lib -I../perl/blib/arch/auto/Git.\n>\n> -- >8 --\n> [PATCH] Perl interface: add build-time configuration to allow building with -fPIC\n>\n> On x86-64 it seems that Git.xs does not link without compiling\n> the main git objects with -fPIC.\n>\n> Signed-off-by: Junio C Hamano <junkio@cox.net>\n\nEh, sorry this was in response to this part of Pasky's message:\n\n>> Well, for the .xs you do need an .so and for that you apparently need\n>> -fPIC on most architectures, so there's no way around it.\n>> \n>> There's a patch to build libgit.so, would you take it as an excuse to\n>> always compile with -fPIC? ;-)\n\nBy the way, I noticed NO_ACCURATE_DIFF is a compile time option\nto cause git-apply to accept diff output from implementations\nthat botch \"\\No newline at the end of file\", and I think it is\nwrong -- it should be a run time option to git-apply if we would\nwant to support it, because the version of diff you have does\nnot have much to do with which implementations of diff were used\nto generate patches you would receive and apply.\n\nThoughts?\n"},{"id":"22476","messageId":"Pine.LNX.4.63.0606242207510.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4625","inReplyTo":"7vzmg35pkt.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-24T20:10:11Z","receivedAt":"2006-06-24T20:10:11Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 23 Jun 2006, Junio C Hamano wrote:\n\n> By the way, I noticed NO_ACCURATE_DIFF is a compile time option\n> to cause git-apply to accept diff output from implementations\n> that botch \"\\No newline at the end of file\", and I think it is\n> wrong -- it should be a run time option to git-apply if we would\n> want to support it, because the version of diff you have does\n> not have much to do with which implementations of diff were used\n> to generate patches you would receive and apply.\n> \n> Thoughts?\n\nMy original idea: on a machine where you have no accurate diff, you at \nleast want to pass the tests, and you want to ensure you can apply a diff \nyou generated on that machine.\n\nBut I was wrong. This patch is just compile tested, but obviously correct \n(lacking usage() and Documentation updates as usual, since I do not want \nto do that work before I know the patch is applied):\n\n---\n[PATCH] apply: add --no-accurate-diff and --accurate-diff options\n\nYou can still set the default behaviour in the Makefile, but at least you\ncan override it.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n builtin-apply.c |   32 +++++++++++++++++++++++---------\n 1 files changed, 23 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-apply.c b/builtin-apply.c\nindex e113c74..2d26ade 100644\n--- a/builtin-apply.c\n+++ b/builtin-apply.c\n@@ -125,6 +125,7 @@ #define BINARY_LITERAL_DEFLATED 2\n \tunsigned long deflate_origlen;\n \tint lines_added, lines_deleted;\n \tint score;\n+\tint no_accurate_diff:1;\n \tstruct fragment *fragments;\n \tchar *result;\n \tunsigned long resultsize;\n@@ -1333,7 +1334,8 @@ static int apply_line(char *output, cons\n \treturn plen;\n }\n \n-static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)\n+static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag,\n+\tint no_accurate_diff)\n {\n \tint match_beginning, match_end;\n \tchar *buf = desc->buffer;\n@@ -1386,13 +1388,11 @@ static int apply_one_fragment(struct buf\n \t\tsize -= len;\n \t}\n \n-#ifdef NO_ACCURATE_DIFF\n-\tif (oldsize > 0 && old[oldsize - 1] == '\\n' &&\n+\tif (no_accurate_diff && oldsize > 0 && old[oldsize - 1] == '\\n' &&\n \t\t\tnewsize > 0 && new[newsize - 1] == '\\n') {\n \t\toldsize--;\n \t\tnewsize--;\n \t}\n-#endif\n \n \toldlines = old;\n \tnewlines = new;\n@@ -1614,7 +1614,7 @@ static int apply_fragments(struct buffer\n \t\treturn apply_binary(desc, patch);\n \n \twhile (frag) {\n-\t\tif (apply_one_fragment(desc, frag) < 0)\n+\t\tif (apply_one_fragment(desc, frag, patch->no_accurate_diff) < 0)\n \t\t\treturn error(\"patch failed: %s:%ld\",\n \t\t\t\t     name, frag->oldpos);\n \t\tfrag = frag->next;\n@@ -2097,7 +2097,7 @@ static int use_patch(struct patch *p)\n \treturn 1;\n }\n \n-static int apply_patch(int fd, const char *filename)\n+static int apply_patch(int fd, const char *filename, int no_accurate_diff)\n {\n \tunsigned long offset, size;\n \tchar *buffer = read_patch_file(fd, &size);\n@@ -2113,6 +2113,7 @@ static int apply_patch(int fd, const cha\n \t\tint nr;\n \n \t\tpatch = xcalloc(1, sizeof(*patch));\n+\t\tpatch->no_accurate_diff = no_accurate_diff;\n \t\tnr = parse_chunk(buffer + offset, size, patch);\n \t\tif (nr < 0)\n \t\t\tbreak;\n@@ -2180,6 +2181,11 @@ int cmd_apply(int argc, const char **arg\n {\n \tint i;\n \tint read_stdin = 1;\n+#ifdef NO_ACCURATE_DIFF\n+\tint no_accurate_diff = 1;\n+#else\n+\tint no_accurate_diff = 0;\n+#endif\n \tconst char *whitespace_option = NULL;\n \n \tfor (i = 1; i < argc; i++) {\n@@ -2188,7 +2194,7 @@ int cmd_apply(int argc, const char **arg\n \t\tint fd;\n \n \t\tif (!strcmp(arg, \"-\")) {\n-\t\t\tapply_patch(0, \"<stdin>\");\n+\t\t\tapply_patch(0, \"<stdin>\", no_accurate_diff);\n \t\t\tread_stdin = 0;\n \t\t\tcontinue;\n \t\t}\n@@ -2265,6 +2271,14 @@ int cmd_apply(int argc, const char **arg\n \t\t\tparse_whitespace_option(arg + 13);\n \t\t\tcontinue;\n \t\t}\n+\t\tif (!strcmp(arg, \"--no-accurate-diff\")) {\n+\t\t\tno_accurate_diff = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"--accurate-diff\")) {\n+\t\t\tno_accurate_diff = 0;\n+\t\t\tcontinue;\n+\t\t}\n \n \t\tif (check_index && prefix_length < 0) {\n \t\t\tprefix = setup_git_directory();\n@@ -2281,12 +2295,12 @@ int cmd_apply(int argc, const char **arg\n \t\t\tusage(apply_usage);\n \t\tread_stdin = 0;\n \t\tset_default_whitespace_mode(whitespace_option);\n-\t\tapply_patch(fd, arg);\n+\t\tapply_patch(fd, arg, no_accurate_diff);\n \t\tclose(fd);\n \t}\n \tset_default_whitespace_mode(whitespace_option);\n \tif (read_stdin)\n-\t\tapply_patch(0, \"<stdin>\");\n+\t\tapply_patch(0, \"<stdin>\", no_accurate_diff);\n \tif (whitespace_error) {\n \t\tif (squelch_whitespace_errors &&\n \t\t    squelch_whitespace_errors < whitespace_error) {\n"},{"id":"22490","messageId":"7vzmg2rpxt.fsf@assigned-by-dhcp.cox.net","threadId":"4625","inReplyTo":"Pine.LNX.4.63.0606242207510.29667@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-25T01:20:46Z","receivedAt":"2006-06-25T01:20:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> My original idea: on a machine where you have no accurate diff, you at \n> least want to pass the tests, and you want to ensure you can apply a diff \n> you generated on that machine.\n\nI remember that, but I think recently we converted t4100 and\nt4101 to use pregenerated test vectors so it might not be an\nissue anymore?\n\n> This patch is just compile tested, but obviously correct \n\nLooks sane, thanks.\n\nI would maybe rename the option to --inaccurate-eof and default\nit to off (i.e. no --accurate-eof option).  After all we are not\ntalking about arbitrary inaccuracy but the particular botch of\nnot having \"\\No newline at the end of file.\"\n"},{"id":"22502","messageId":"Pine.LNX.4.63.0606250353220.29667@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4625","inReplyTo":"7vzmg2rpxt.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-25T01:54:01Z","receivedAt":"2006-06-25T01:54:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sat, 24 Jun 2006, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > My original idea: on a machine where you have no accurate diff, you at \n> > least want to pass the tests, and you want to ensure you can apply a diff \n> > you generated on that machine.\n> \n> I remember that, but I think recently we converted t4100 and\n> t4101 to use pregenerated test vectors so it might not be an\n> issue anymore?\n\nExactly.\n\n> I would maybe rename the option to --inaccurate-eof and default\n> it to off (i.e. no --accurate-eof option).  After all we are not\n> talking about arbitrary inaccuracy but the particular botch of\n> not having \"\\No newline at the end of file.\"\n\nSure. Want me to redo the patch?\n\nCiao,\nDscho\n"},{"id":"22627","messageId":"200606270120.42031.jnareb@gmail.com","threadId":"4625","inReplyTo":"20060623124539.GM21864@pasky.or.cz","subject":"Re: [PATCH] Introduce Git.pm (v3)","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-06-26T23:20:41Z","receivedAt":"2006-06-26T23:20:41Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Dnia piątek 23. czerwca 2006 14:45, napisałeś:\n> Dear diary, on Fri, Jun 23, 2006 at 08:03:23AM CEST, I got a letter\n> where Jakub Narebski <jnareb@gmail.com> said that...\n>> Perhaps Git.pm should provide also generic, pure Perl (and slower)\n>> fallback implementation (when for some reason we cannot compile XS).\n> \n> I fiercely want to avoid this if there is any other possible way to go\n> about it - this is a path to hell of massive code duplication and\n> additional work, as the number of routines will grow. If it is question\n> of spending many developer-hours uselessly duplicating code in a way\n> that'll be much slower than possible anyway OR building with -fPIC... ;-)\n\nI have thought about reimplementing only the parts which are in XS. In C\none would probably write\n\n#if can_asm\n asm (...)\n#else\n /* C code equivalent */\n#endif\n\nIn addition to allowing use of Git.pm for people who cannot compile \nGit.xs, it would be helpful I guess in Git.pm development.\n\n-- \nJakub Narebski\nPoland\n"}]}