|
|
@@ -7,7 +7,7 @@ use warnings;
|
|
|
|
|
|
use FindBin::libs;
|
|
|
|
|
|
-use List::Util qw{first};
|
|
|
+use List::Util qw{first any uniq};
|
|
|
use HTTP::Tiny;
|
|
|
use Config::Simple;
|
|
|
use Getopt::Long qw{GetOptionsFromArray};
|
|
|
@@ -15,10 +15,15 @@ use Pod::Usage;
|
|
|
use Pithub;
|
|
|
use Gogs;
|
|
|
use Git;
|
|
|
+use Clone qw{clone};
|
|
|
|
|
|
use Term::ReadKey();
|
|
|
use IO::Interactive::Tiny();
|
|
|
|
|
|
+use Data::Dumper;
|
|
|
+$Data::Dumper::Purity=1;
|
|
|
+$Data::Dumper::Deepcopy=1;
|
|
|
+
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
It is a common pattern in organizations to have their own git resources, but mirror everything public on one of the big platforms with network effect.
|
|
|
@@ -149,7 +154,7 @@ Allow insecure mirrors or baseurls. This is just to prevent footgunning by pass
|
|
|
|
|
|
=head3 create
|
|
|
|
|
|
-Automatically create a copy of the repo on the mirror if it doesn't exist.
|
|
|
+Automatically create a copy of the repo on the mirror or baseurl if it doesn't exist.
|
|
|
|
|
|
--create
|
|
|
|
|
|
@@ -237,6 +242,8 @@ sub main {
|
|
|
'primary_user=s' => \$options{primary},
|
|
|
'primary_org=s' => \$options{primary_org},
|
|
|
'verbose' => \$options{verbose},
|
|
|
+ 'create' => \$options{create},
|
|
|
+ 'sync' => \$options{sync},
|
|
|
);
|
|
|
$verbose = $options{verbose};
|
|
|
|
|
|
@@ -308,7 +315,7 @@ sub main {
|
|
|
$clients{$mirror_domain} = $mirror;
|
|
|
}
|
|
|
|
|
|
- my @fetched = _fetch_all($mirror, $options{users}, $options{orgs}, \%alias_map, $field_name);
|
|
|
+ my @fetched = _fetch_all($mirror, clone($options{users}), clone($options{orgs}), \%alias_map, $field_name);
|
|
|
_help(7, "The provided server ($mirror_url) could not list repos!", $cleanup ) unless @fetched;
|
|
|
|
|
|
# GOGS will list all the repos the user *has access to* not all the ones they own.
|
|
|
@@ -338,19 +345,69 @@ sub main {
|
|
|
# Set up the "special" URIs
|
|
|
foreach my $remote (qw{origin upstream parent}) {
|
|
|
next unless $repo_info->{$remote};
|
|
|
- $repodata{$repo->{name}}{$remote}{fetch} = $repo_info->{clone_uri} if $repo_info->{is_primary_domain};
|
|
|
+ $repodata{$repo->{name}}{$remote}{fetch} = $repo_info if $repo_info->{is_primary_domain};
|
|
|
$repodata{$repo->{name}}{$remote}{push} //= [];
|
|
|
- push(@{$repodata{$repo->{name}}{$remote}{push}}, $repo_info->{clone_uri});
|
|
|
+ push(@{$repodata{$repo->{name}}{$remote}{push}}, $repo_info);
|
|
|
}
|
|
|
# Set up the user's remote
|
|
|
- $repodata{$repo->{name}}{$aliased}{fetch} = $repo_info->{clone_uri} if $repo_info->{is_primary_domain};
|
|
|
+ $repodata{$repo->{name}}{$aliased}{fetch} = $repo_info if $repo_info->{is_primary_domain};
|
|
|
$repodata{$repo->{name}}{$aliased}{push} //= [];
|
|
|
- push(@{$repodata{$repo->{name}}{$aliased}{push}}, $repo_info->{clone_uri});
|
|
|
+ push(@{$repodata{$repo->{name}}{$aliased}{push}}, $repo_info);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ # Remotes which we (probably) ought to have.
|
|
|
+ # Also add in 'me' if it's in the list of users
|
|
|
+ my $add_me = any { $_ eq $options{me} } @{$options{users}};
|
|
|
+ my @known_remotes = (qw{origin upstream parent}, $prime_name);
|
|
|
+ push(@known_remotes, $options{me}) if $add_me;
|
|
|
+ @known_remotes = uniq @known_remotes;
|
|
|
+
|
|
|
+ # TODO build a set of repos we need -- be they either mirrors needing setup or things on mirrors needing to be brought into the fold
|
|
|
+ foreach my $repo (keys(%repodata)) {
|
|
|
+ foreach my $remote (@known_remotes) {
|
|
|
+ my $repository = $repodata{$repo}{$remote} // {};
|
|
|
+ # If we only have the push URI for a mirror, then we don't have it locally
|
|
|
+ if (!exists $repository->{fetch}) {
|
|
|
+ LOG("$repo does not exist at $options{baseurl}");
|
|
|
+ next unless $options{create};
|
|
|
+ my $new_repo = _create_repo( $clients{$primary_domain}, $repo, $primary_domain);
|
|
|
+ $repository->{fetch} = $new_repo;
|
|
|
+ $repository->{push} //= [];
|
|
|
+ push(@{$repository->{push}}, $new_repo);
|
|
|
+ }
|
|
|
+ # If we only have the fetch URI, then we don't have it on the mirrors
|
|
|
+ foreach my $push_repo (@{$options{mirrors}}) {
|
|
|
+ next if $push_repo eq $options{baseurl};
|
|
|
+ my ($push_domain) = $push_repo =~ $domainRipper;
|
|
|
+ next if any { $_->{domain} eq $push_domain } @{$repository->{push}};
|
|
|
+ LOG("Repo $repo does not exist at $push_domain");
|
|
|
+ next unless $options{create};
|
|
|
+ my $new_repo = _create_repo( $clients{$push_domain}, $push_repo, $push_domain );
|
|
|
+ $repository->{push} //= [];
|
|
|
+ push(@{$repository->{push}}, $new_repo);
|
|
|
+ }
|
|
|
+ $repodata{$repo}{$remote} = $repository;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ # Now that we have everything created that we want, let's prune the info down
|
|
|
+ foreach my $repo (keys(%repodata)) {
|
|
|
+ foreach my $remote (keys(%{$repodata{$repo}})) {
|
|
|
+ LOG("MAP $repo $remote");
|
|
|
+ my $repository = $repodata{$repo}{$remote};
|
|
|
+ my @push_uris = map { $_->{clone_uri} } @{$repository->{push}};
|
|
|
+ $repository = {
|
|
|
+ fetch => $repository->{fetch}{clone_uri},
|
|
|
+ push => \@push_uris,
|
|
|
+ };
|
|
|
+ $repodata{$repo}{$remote} = $repository;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
$cleanup->();
|
|
|
- use Data::Dumper;
|
|
|
- die Dumper(\%repodata);
|
|
|
+ print Dumper(\%repodata);
|
|
|
+ die;
|
|
|
|
|
|
_clone_repos(%repodata);
|
|
|
|
|
|
@@ -359,6 +416,21 @@ sub main {
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+sub _create_repo {
|
|
|
+ my ($api, $repo, $domain) =@_;
|
|
|
+ LOG("Creating $repo on $domain");
|
|
|
+ return { 'clone_uri' => "$domain TODO" };
|
|
|
+
|
|
|
+ #TODO check that we haven't already created it
|
|
|
+
|
|
|
+ #my $result = $api->repos->create( data => { name => $repo } );
|
|
|
+ #TODO handle errors
|
|
|
+ #my $new_repo = $result->content();
|
|
|
+
|
|
|
+ #TODO fortify the new repo with the needed infos along the lines of L335
|
|
|
+ #TODO set upstream fork if applicable
|
|
|
+}
|
|
|
+
|
|
|
sub _clone_repos {
|
|
|
my (%repodata) = @_;
|
|
|
|
|
|
@@ -407,7 +479,11 @@ sub _fetch_upstream_uri {
|
|
|
if ($repo->{fork}) {
|
|
|
LOG("Looking up what $repo->{name} was forked from...");
|
|
|
my $details = $mirror->repos->get( user => $muser, repo => $repo->{name});
|
|
|
- _help(9, "Could not fetch repository details for $repo->{name}") unless $details && $details->response->is_success();
|
|
|
+ if (!$details || !$details->response->is_success()) {
|
|
|
+ #LOG("Could not fetch repository details for $repo->{name}, skipping...");
|
|
|
+ #next;
|
|
|
+ _help(9, "Could not fetch repository details for $repo->{name}") unless $details && $details->response->is_success();
|
|
|
+ }
|
|
|
my $content = $details->content();
|
|
|
$upstream_uri = $content->{parent}{$field_name};
|
|
|
_help(10, "Could not discern upstream URI for forked repo $repo->{name}!") unless $upstream_uri;
|