Make it possible to set up libgit directly (instead of from the environment)
[gitweb.git] / perl / Git.pm
index 5ec7ef8c246bdcfab725490ce383fee083ff8f82..9da15e9c8c208ffd6a51b524edc828c85dce5355 100644 (file)
@@ -98,6 +98,8 @@ =head1 DESCRIPTION
 
 }
 
+my $instance_id = 0;
+
 
 =head1 CONSTRUCTORS
 
@@ -178,7 +180,8 @@ sub repository {
                };
 
                if ($dir) {
-                       $opts{Repository} = abs_path($dir);
+                       $dir =~ m#^/# or $dir = $opts{Directory} . '/' . $dir;
+                       $opts{Repository} = $dir;
 
                        # If --git-dir went ok, this shouldn't die either.
                        my $prefix = $search->command_oneline('rev-parse', '--show-prefix');
@@ -214,7 +217,7 @@ sub repository {
                delete $opts{Directory};
        }
 
-       $self = { opts => \%opts };
+       $self = { opts => \%opts, id => $instance_id++ };
        bless $self, $class;
 }
 
@@ -472,7 +475,6 @@ sub command_noisy {
 
 sub wc_chdir {
        my ($self, $subdir) = @_;
-
        $self->wc_path()
                or throw Error::Simple("bare repository");
 
@@ -485,6 +487,91 @@ sub wc_chdir {
 }
 
 
+=item config ( VARIABLE )
+
+Retrieve the configuration C<VARIABLE> in the same manner as C<repo-config>
+does. In scalar context requires the variable to be set only one time
+(exception is thrown otherwise), in array context returns allows the
+variable to be set multiple times and returns all the values.
+
+Must be called on a repository instance.
+
+This currently wraps command('repo-config') so it is not so fast.
+
+=cut
+
+sub config {
+       my ($self, $var) = @_;
+       $self->repo_path()
+               or throw Error::Simple("not a repository");
+
+       try {
+               if (wantarray) {
+                       return $self->command('repo-config', '--get-all', $var);
+               } else {
+                       return $self->command_oneline('repo-config', '--get', $var);
+               }
+       } catch Git::Error::Command with {
+               my $E = shift;
+               if ($E->value() == 1) {
+                       # Key not found.
+                       return undef;
+               } else {
+                       throw $E;
+               }
+       };
+}
+
+
+=item ident ( TYPE | IDENTSTR )
+
+=item ident_person ( TYPE | IDENTSTR | IDENTARRAY )
+
+This suite of functions retrieves and parses ident information, as stored
+in the commit and tag objects or produced by C<var GIT_type_IDENT> (thus
+C<TYPE> can be either I<author> or I<committer>; case is insignificant).
+
+The C<ident> method retrieves the ident information from C<git-var>
+and either returns it as a scalar string or as an array with the fields parsed.
+Alternatively, it can take a prepared ident string (e.g. from the commit
+object) and just parse it.
+
+C<ident_person> returns the person part of the ident - name and email;
+it can take the same arguments as C<ident> or the array returned by C<ident>.
+
+The synopsis is like:
+
+       my ($name, $email, $time_tz) = ident('author');
+       "$name <$email>" eq ident_person('author');
+       "$name <$email>" eq ident_person($name);
+       $time_tz =~ /^\d+ [+-]\d{4}$/;
+
+Both methods must be called on a repository instance.
+
+=cut
+
+sub ident {
+       my ($self, $type) = @_;
+       my $identstr;
+       if (lc $type eq lc 'committer' or lc $type eq lc 'author') {
+               $identstr = $self->command_oneline('var', 'GIT_'.uc($type).'_IDENT');
+       } else {
+               $identstr = $type;
+       }
+       if (wantarray) {
+               return $identstr =~ /^(.*) <(.*)> (\d+ [+-]\d{4})$/;
+       } else {
+               return $identstr;
+       }
+}
+
+sub ident_person {
+       my ($self, @ident) = @_;
+       $#ident == 0 and @ident = $self->ident($ident[0]);
+       return "$ident[0] <$ident[1]>";
+}
+
+
 =item hash_object ( TYPE, FILENAME )
 
 =item hash_object ( TYPE, FILEHANDLE )
@@ -510,7 +597,19 @@ sub wc_chdir {
 
 =cut
 
-# Implemented in Git.xs.
+sub hash_object {
+       my ($self, $type, $file) = _maybe_self(@_);
+
+       # hash_object_* implemented in Git.xs.
+
+       if (ref($file) eq 'GLOB') {
+               my $hash = hash_object_pipe($type, fileno($file));
+               close $file;
+               return $hash;
+       } else {
+               hash_object_file($type, $file);
+       }
+}
 
 
 
@@ -736,11 +835,10 @@ sub _call_gate {
        if (defined $self) {
                # XXX: We ignore the WorkingCopy! To properly support
                # that will require heavy changes in libgit.
+               # For now, when we will need to do it we could temporarily
+               # chdir() there and then chdir() back after the call is done.
 
-               # XXX: And we ignore everything else as well. libgit
-               # at least needs to be extended to let us specify
-               # the $GIT_DIR instead of looking it up in environment.
-               #xs_call_gate($self->{opts}->{Repository});
+               xs__call_gate($self->{id}, $self->repo_path());
        }
 
        # Having to call throw from the C code is a sure path to insanity.