Эх сурвалжийг харах

Listing repos & autogenning keys working, next up we get mirroring

Also get the configuration files
George Baugh 1 жил өмнө
parent
commit
e806eec638
2 өөрчлөгдсөн 124 нэмэгдсэн , 32 устгасан
  1. 47 12
      bin/git-clone-entity
  2. 77 20
      lib/Gogs.pm

+ 47 - 12
bin/git-clone-entity

@@ -39,19 +39,20 @@ git clone-entity --user $user1 --user $user2 --org $org1 --org $org2 --alias $us
 =cut
 =cut
 
 
 sub _help {
 sub _help {
-    my ($code, $msg) = @_;
+    my ($code, $msg, $cb) = @_;
     $code //= 0;
     $code //= 0;
     $msg //= "";
     $msg //= "";
+	$cb->() if ref $cb eq 'CODE';
     return Pod::Usage::pod2usage( -message => $msg, -exitval => $code);
     return Pod::Usage::pod2usage( -message => $msg, -exitval => $code);
 }
 }
 
 
-my $domainRipper = qr{m/^\w+://([\w|\.]+)};
+my $domainRipper = qr{^\w+://([\w|\.]+)};
 
 
 sub main {
 sub main {
     my @args = @_;
     my @args = @_;
 
 
     my $help;
     my $help;
-    my ($users, $orgs, $aliases, $tokens, $mirrors, $baseurl, $gogs, $me) = ([],[],[],[],[],"", 0, "");
+    my ($users, $orgs, $aliases, $tokens, $mirrors, $baseurl, $gogs, $me, $insecure) = ([],[],[],[],[],"", 0, "", 0);
 
 
     GetOptionsFromArray(\@args,
     GetOptionsFromArray(\@args,
         'me=s'      => \$me,
         'me=s'      => \$me,
@@ -62,13 +63,14 @@ sub main {
         'baseurl=s' => \$baseurl,
         'baseurl=s' => \$baseurl,
         'mirror=s@' => \$mirrors,
         'mirror=s@' => \$mirrors,
         'gogs'      => \$gogs,
         'gogs'      => \$gogs,
+        'insecure'  => \$insecure,
         'help'      => \$help,
         'help'      => \$help,
     );
     );
 
 
     return _help() if $help;
     return _help() if $help;
     return _help(1, "Must pass at least one user or organization") unless (@$users + @$orgs);
     return _help(1, "Must pass at least one user or organization") unless (@$users + @$orgs);
     return _help(2, "Must pass baseurl") unless $baseurl;
     return _help(2, "Must pass baseurl") unless $baseurl;
-    return _help(3, "Must pass your username") unless $me;
+    return _help(3, "Must pass your username as --me") unless $me;
 
 
     # Parse Alias mappings
     # Parse Alias mappings
     my %alias_map;
     my %alias_map;
@@ -88,44 +90,70 @@ sub main {
         $tokens{$domain} = $token;
         $tokens{$domain} = $token;
     }
     }
 
 
-    $primary_token = $tokens{$primary_domain};
+    my $primary_token = $tokens{$primary_domain};
     my %args = (
     my %args = (
         user    => $me,
         user    => $me,
         api_uri => $baseurl,
         api_uri => $baseurl,
-        token   => $primary_token,
     );
     );
+    $args{token} = $primary_token if $primary_token;
 
 
     # It's important which is the primary, because we can have only one pull url, and many push urls.
     # It's important which is the primary, because we can have only one pull url, and many push urls.
     my $local  = $gogs ? Gogs->new(%args) : Pithub->new( %args );
     my $local  = $gogs ? Gogs->new(%args) : Pithub->new( %args );
 
 
     # If the primary is gogs and we have no token passed, let's make one.
     # If the primary is gogs and we have no token passed, let's make one.
+	my $password;
 	if (!$primary_token && $gogs) {
 	if (!$primary_token && $gogs) {
 		_help(5, "Program must be run interactively to auto-create keys on Gogs installs.") unless IO::Interactive::Tiny::is_interactive();
 		_help(5, "Program must be run interactively to auto-create keys on Gogs installs.") unless IO::Interactive::Tiny::is_interactive();
+		# Stash the password in case we gotta clean up
+		$password = _prompt("Please type in the password for ".$local->user.":");
 		$primary_token = $local->get_token(
 		$primary_token = $local->get_token(
 			name     => "git-clone-entity",
 			name     => "git-clone-entity",
-			password => _prompt("Please type in the password for $local->user:"),
+			password => $password,
+            insecure => $insecure,
 		);
 		);
+        _help(6, "Could not fetch token from gogs!  Check that you supplied the correct username & password.") unless $primary_token;
+        $local->token($primary_token);
 	}
 	}
 
 
+	my $cleanup = sub { _cleanup_token( $local, $password, $insecure ) if $password };
+
+	# TODO XXX this is not appending /api/v1 for some reason
     my @repos_local = _fetch_all($local, $users, $orgs);
     my @repos_local = _fetch_all($local, $users, $orgs);
+    _help(7, "Server at $baseurl could not list repos!", $cleanup ) unless @repos_local;
 
 
     my %repos_mirror;
     my %repos_mirror;
     foreach my $mirror_url (@$mirrors) {
     foreach my $mirror_url (@$mirrors) {
         my ($mirror_domain) = $mirror_url =~ $domainRipper;
         my ($mirror_domain) = $mirror_url =~ $domainRipper;
         my $muser = $me;
         my $muser = $me;
-        $muser = $alias_map->{$domain}{$me} if exists $alias_map->{$domain}{$me};
+        $muser = $alias_map{$mirror_domain}{$muser} if exists $alias_map{$mirror_domain}{$muser};
         my %margs = (
         my %margs = (
             user    => $muser,
             user    => $muser,
             api_uri => $mirror_url,
             api_uri => $mirror_url,
-            token   => $tokens{$mirror_domain},
         );
         );
+        $args{token} = $tokens{$mirror_domain} if $tokens{$mirror_domain};
 
 
         my $mirror = Pithub->new( api_uri => $mirror_url );
         my $mirror = Pithub->new( api_uri => $mirror_url );
         $repos_mirror{$mirror_url} = _fetch_all($mirror, $users, $orgs, \%alias_map);
         $repos_mirror{$mirror_url} = _fetch_all($mirror, $users, $orgs, \%alias_map);
+        _help(8, "The provided mirror ($mirror_url) could not list repos!", $cleanup ) unless @{$repos_mirror{$mirror_url}};
     }
     }
 
 
+	# Clean up
+	$cleanup->();
+
     use Data::Dumper;
     use Data::Dumper;
-    die Dumper(\%repos_mirror, \@repos_local, \%alias_map);
+    die Dumper(\%repos_mirror, \@repos_local);
+}
+
+sub _cleanup_token {
+	my ( $api, $password, $insecure ) = @_;
+
+	my $tok = $api->token();
+	# unset the token, so that we use simple auth once more
+	$api->token("");
+
+	my $result = $api->delete_token( sha1 => $tok, password => $password, insecure => $insecure );
+
+	die "Could not clean up token" unless $result && $result->response->is_success;
 }
 }
 
 
 sub _prompt {
 sub _prompt {
@@ -156,16 +184,23 @@ sub _fetch_all {
     foreach my $user (@$users) {
     foreach my $user (@$users) {
         $user = $alias_map->{$domain}{$user} if exists $alias_map->{$domain}{$user};
         $user = $alias_map->{$domain}{$user} if exists $alias_map->{$domain}{$user};
         my $result = $api->repos->list( user => $user );
         my $result = $api->repos->list( user => $user );
-        push(@repos, $result) if $result;
+        push(@repos, _array_content($result));
     }
     }
     foreach my $org (@$orgs) {
     foreach my $org (@$orgs) {
         $org = $alias_map->{$domain}{$org} if exists $alias_map->{$domain}{$org};
         $org = $alias_map->{$domain}{$org} if exists $alias_map->{$domain}{$org};
         my $result = $api->repos->list( org => $org );
         my $result = $api->repos->list( org => $org );
-        push(@repos, $result) if $result;
+        push(@repos, _array_content($result));
     }
     }
     return @repos;
     return @repos;
  }
  }
 
 
+sub _array_content {
+	my ($result) = @_;
+	return () unless $result && $result->response->is_success;
+	return @{$result->content()} if ref $result->content() eq 'ARRAY';
+	return ();
+}
+
 exit main(@ARGV) unless caller;
 exit main(@ARGV) unless caller;
 
 
 1;
 1;

+ 77 - 20
lib/Gogs.pm

@@ -5,8 +5,9 @@ use strict;
 use warnings;
 use warnings;
 
 
 use Moo;
 use Moo;
-use Mime::Base64;
+use MIME::Base64;
 
 
+#use Gogs::Repos;
 extends 'Pithub';
 extends 'Pithub';
 
 
 =head1 DESCRIPTION
 =head1 DESCRIPTION
@@ -17,17 +18,18 @@ However the two have a number of differences, so they must be accounted for.
 
 
 The most important of which being that all requests require an API token.
 The most important of which being that all requests require an API token.
 
 
-=head1 SUBROUTINES
+=head1 METHODS
 
 
 =head2 get_token(%options)
 =head2 get_token(%options)
 
 
-Gogs has no user-facing means of creating tokens like github does.
-You have to POST against the API using HTTP simple auth to acquire them.
+We can simplify tooling around this to not require you enter the "Applications" section of the gogs interface.
 
 
 Requires that the object is instantiated with a username,
 Requires that the object is instantiated with a username,
 that you pass a password, and that the api_uri is secure unless you pass the 'insecure' option.
 that you pass a password, and that the api_uri is secure unless you pass the 'insecure' option.
 
 
-Will either fetch (if it exists) or create the named token.
+If the named token exists already it will delete and re-create the named token.
+
+It is HIGHLY RECOMMENDED you delete the token at the end of your session with the delete_token() method.
 
 
 =cut
 =cut
 
 
@@ -35,23 +37,37 @@ Will either fetch (if it exists) or create the named token.
 # As such, I'm restricting every call not ending in /tokens
 # As such, I'm restricting every call not ending in /tokens
 my @TOKEN_REQUIRED_REGEXP = (qr{(?!/tokens$)});
 my @TOKEN_REQUIRED_REGEXP = (qr{(?!/tokens$)});
 
 
-sub get_token {
-    my ($self, %options) = @_;
-
+sub _validate_tok_args {
+	my ($self,%options) = @_;
     die "Must instantiate with username" unless $self->user;
     die "Must instantiate with username" unless $self->user;
-    die "Must pass token name" unless $options{name};
-    die "Refuse to operate over insecure connections" if !$options{insecure} && _insecure($uri);
+    die "Must pass token name or sha1" unless $options{name} || $options{sha1};
+    die "Refuse to operate over insecure connections" if !$options{insecure} && _insecure($self->api_uri);
     die "Must provide password to fetch tokens" unless $options{password};
     die "Must provide password to fetch tokens" unless $options{password};
+}
 
 
-    my %auth_headers = (
-        'Authorization' => "Basic ".encode_base64("$self->user:$options{password}"),
+sub _build_tok_headers {
+	my ($self, %options) = @_;
+    return (
+        'Authorization' => "Basic ".encode_base64($self->user.":$options{password}"),
         'Content-type'  => "application/json",
         'Content-type'  => "application/json",
     );
     );
 
 
-    my $token_endpoint = "/api/v1/users/$self->user/tokens";
+}
+
+sub get_token {
+    my ($self, %options) = @_;
+
+	# unset the token if passed, so that we use simple auth
+	my $tok = $self->token();
+	$self->token("") if $tok;
+
+	$self->_validate_tok_args(%options);
+	my %auth_headers = $self->_build_tok_headers(%options);
+
+    my $token_endpoint = "/users/".$self->user."/tokens";
     my %req = (
     my %req = (
-         method  => 'GET',
-        path    => $tokens_endpoint,
+        method  => 'GET',
+        path    => $token_endpoint,
         headers => \%auth_headers,
         headers => \%auth_headers,
     );
     );
     my $result = $self->request(%req);
     my $result = $self->request(%req);
@@ -60,21 +76,62 @@ sub get_token {
 
 
     my $token_actual;
     my $token_actual;
     foreach my $token (@$content) {
     foreach my $token (@$content) {
-        next unless $token->{name} eq $options{name};
-        return $token->{sha1};
+		# If it exists, we have no means of deleteing it unless we actually have the real SHA1 (the one in list is not real).
+        # As such just die.
+        die "Token with name $options{name} already exists, cannot continue.  Please delete it manually." if $token->{name} eq $options{name};
     }
     }
 
 
     # No such token named, so let's just make one.
     # No such token named, so let's just make one.
     $req{method} = 'POST';
     $req{method} = 'POST';
-    my $result = $self->request(%req);
-    my $content = $result->content();
+	$req{data} = qq|{ "name":"$options{name}" }|;
+    $result = $self->request(%req);
+    $content = $result->content();
+
+	# Set the token again, since we are done with the requests
+	$self->token($tok) if $tok;
+
     die "Got bad response from server" unless ref $content eq "HASH";
     die "Got bad response from server" unless ref $content eq "HASH";
     return $content->{sha1};
     return $content->{sha1};
 }
 }
 
 
+=head2 delete_token(%options)
+
+Delete the token identified by the provided sha1 in %options.
+
+Should return a token name.
+
+Dies when unsuccessful.
+
+=cut
+
+sub delete_token {
+	my ($self, %options) = @_;
+
+	# unset the token if passed, so that we use simple auth
+	my $tok = $self->token();
+	$self->token("") if $tok;
+
+	$self->_validate_tok_args(%options);
+	my %auth_headers = $self->_build_tok_headers(%options);
+
+    my %req = (
+        method  => 'DELETE',
+        path    => "/users/".$self->user."/tokens",
+        headers => \%auth_headers,
+    );
+	$req{data} = qq|{ "sha1":"$options{sha1}" }|;
+	my $result = $self->request(%req);
+
+	# Set the token again, since we are done with the requests
+	$self->token($tok) if $tok;
+
+	die "Got bad response from server on DELETE of token" unless $result &&  $result->response->is_success;
+	return $result;
+}
+
 sub _insecure {
 sub _insecure {
     my $uri = shift;
     my $uri = shift;
-    return m/^http:\/\//;
+    return $uri =~ m/^http:\/\//;
 }
 }
 
 
 1;
 1;