Skip to content

Commit

Permalink
Move stuff out of main (#98)
Browse files Browse the repository at this point in the history
* Move the options parsing out of main

* move more stuff out of main
  • Loading branch information
amitsaha authored Aug 24, 2023
1 parent 1c62a8d commit dd62fb0
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 148 deletions.
22 changes: 22 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

type appConfig struct {
service string
gitHostURL string
backupDir string
ignorePrivate bool
ignoreFork bool
useHTTPSClone bool
bare bool

githubRepoType string
githubNamespaceWhitelist []string
githubCreateUserMigration bool
githubCreateUserMigrationRetry bool
githubCreateUserMigrationRetryMax int
githubListUserMigrations bool
githubWaitForMigrationComplete bool

gitlabProjectVisibility string
gitlabProjectMembershipType string
}
45 changes: 45 additions & 0 deletions git_repository_clone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"log"
"sync"
)

func handleGitRepositoryClone(client interface{}, c *appConfig) {

// Used for waiting for all the goroutines to finish before exiting
var wg sync.WaitGroup
defer wg.Wait()

tokens := make(chan bool, MaxConcurrentClones)
gitHostUsername = getUsername(client, c.service)

if len(gitHostUsername) == 0 && !*ignorePrivate && *useHTTPSClone {
log.Fatal("Your Git host's username is needed for backing up private repositories via HTTPS")
}
repos, err := getRepositories(
client,
c.service,
c.githubRepoType,
c.githubNamespaceWhitelist,
c.gitlabProjectVisibility,
c.gitlabProjectMembershipType,
c.ignoreFork,
)
if err != nil {
log.Fatal(err)
} else {
log.Printf("Backing up %v repositories now..\n", len(repos))
for _, repo := range repos {
tokens <- true
wg.Add(1)
go func(repo *Repository) {
stdoutStderr, err := backUp(c.backupDir, repo, c.bare, &wg)
if err != nil {
log.Printf("Error backing up %s: %s\n", repo.Name, stdoutStderr)
}
<-tokens
}(repo)
}
}
}
78 changes: 78 additions & 0 deletions github_create_user_migration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package main

import (
"context"
"log"
"time"
)

func handleGithubCreateUserMigration(client interface{}, c *appConfig) {
repos, err := getRepositories(
client,
c.service,
c.githubRepoType,
c.githubNamespaceWhitelist,
c.gitlabProjectVisibility,
c.gitlabProjectMembershipType,
c.ignoreFork,
)
if err != nil {
log.Fatalf("Error getting list of repositories: %v", err)
}

log.Printf("Creating a user migration for %d repos", len(repos))
m, err := createGithubUserMigration(
context.Background(),
client, repos,
c.githubCreateUserMigrationRetry,
c.githubCreateUserMigrationRetryMax,
)
if err != nil {
log.Fatalf("Error creating migration: %v", err)
}

if c.githubWaitForMigrationComplete {
migrationStatePollingDuration := 60 * time.Second
err = downloadGithubUserMigrationData(
context.Background(),
client, c.backupDir,
m.ID,
migrationStatePollingDuration,
)
if err != nil {
log.Fatalf("Error querying/downloading migration: %v", err)
}
}

orgs, err := getGithubUserOwnedOrgs(context.Background(), client)
if err != nil {
log.Fatal("Error getting user organizations", err)
}
for _, o := range orgs {
orgRepos, err := getGithubOrgRepositories(context.Background(), client, o)
if err != nil {
log.Fatal("Error getting org repos", err)
}
if len(orgRepos) == 0 {
log.Printf("No repos found in %s", *o.Login)
continue
}
log.Printf("Creating a org migration (%s) for %d repos", *o.Login, len(orgRepos))
oMigration, err := createGithubOrgMigration(context.Background(), client, *o.Login, orgRepos)
if err != nil {
log.Fatalf("Error creating migration: %v", err)
}
if c.githubWaitForMigrationComplete {
migrationStatePollingDuration := 60 * time.Second
downloadGithubOrgMigrationData(
context.Background(),
client,
*o.Login,
c.backupDir,
oMigration.ID,
migrationStatePollingDuration,
)
}
}

}
35 changes: 35 additions & 0 deletions github_list_user_migrations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"context"
"fmt"
"log"

"github.com/google/go-github/v34/github"
)

func handleGithubListUserMigrations(client interface{}, c *appConfig) {

mList, err := getGithubUserMigrations(client)
if err != nil {
log.Fatal(err)
}

for _, m := range mList {
mData, err := GetGithubUserMigration(client, m.ID)
if err != nil {
fmt.Printf("Error getting migration data: %v", *m.ID)
// FIXME
continue
}

var archiveURL string
_, err = client.(*github.Client).Migrations.UserMigrationArchiveURL(context.Background(), *m.ID)
if err != nil {
archiveURL = "No Longer Available"
} else {
archiveURL = "Available for Download"
}
fmt.Printf("%v - %v - %v - %v\n", *mData.ID, *mData.CreatedAt, *mData.State, archiveURL)
}
}
161 changes: 15 additions & 146 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
package main

import (
"context"
"flag"
"fmt"
"log"
"sync"
"strings"
"time"

"github.com/google/go-github/v34/github"
"os"
)

// MaxConcurrentClones is the upper limit of the maximum number of
Expand All @@ -32,148 +25,24 @@ var knownServices = map[string]string{

func main() {

// Used for waiting for all the goroutines to finish before exiting
var wg sync.WaitGroup
defer wg.Wait()

// Generic flags
service := flag.String("service", "", "Git Hosted Service Name (github/gitlab/bitbucket)")
githostURL := flag.String("githost.url", "", "DNS of the custom Git host")
backupDir := flag.String("backupdir", "", "Backup directory")
ignorePrivate = flag.Bool("ignore-private", false, "Ignore private repositories/projects")
ignoreFork := flag.Bool("ignore-fork", false, "Ignore repositories which are forks")
useHTTPSClone = flag.Bool("use-https-clone", false, "Use HTTPS for cloning instead of SSH")
bare := flag.Bool("bare", false, "Clone bare repositories")

// GitHub specific flags
githubRepoType := flag.String("github.repoType", "all", "Repo types to backup (all, owner, member, starred)")
githubNamespaceWhitelistString := flag.String("github.namespaceWhitelist", "", "Organizations/Users from where we should clone (separate each value by a comma: 'user1,org2')")

githubCreateUserMigration := flag.Bool("github.createUserMigration", false, "Download user data")
githubCreateUserMigrationRetry := flag.Bool("github.createUserMigrationRetry", true, "Retry creating the GitHub user migration if we get an error")
githubCreateUserMigrationRetryMax := flag.Int("github.createUserMigrationRetryMax", defaultMaxUserMigrationRetry, "Number of retries to attempt for creating GitHub user migration")
githubListUserMigrations := flag.Bool("github.listUserMigrations", false, "List available user migrations")
githubWaitForMigrationComplete := flag.Bool("github.waitForUserMigration", true, "Wait for migration to complete")

// Gitlab specific flags
gitlabProjectVisibility := flag.String("gitlab.projectVisibility", "internal", "Visibility level of Projects to clone (internal, public, private)")
gitlabProjectMembershipType := flag.String("gitlab.projectMembershipType", "all", "Project type to clone (all, owner, member, starred)")

flag.Parse()

// Split namespaces
githubNamespaceWhitelist := []string{}

if len(*githubNamespaceWhitelistString) > 0 {
githubNamespaceWhitelist = strings.Split(*githubNamespaceWhitelistString, ",")
}

if _, ok := knownServices[*service]; !ok {
log.Fatal("Please specify the git service type: github, gitlab, bitbucket")
c, err := initConfig(os.Args[1:])
if err != nil {
log.Fatal(err)
}

if !validGitlabProjectMembership(*gitlabProjectMembershipType) {
log.Fatal("Please specify a valid gitlab project membership - all/owner/member")
err = validateConfig(c)
if err != nil {
log.Fatal(err)
}

*backupDir = setupBackupDir(backupDir, service, githostURL)
client := newClient(*service, *githostURL)

if *githubListUserMigrations {
mList, err := getGithubUserMigrations(client)
if err != nil {
log.Fatal(err)
}

for _, m := range mList {
mData, err := GetGithubUserMigration(client, m.ID)
if err != nil {
fmt.Printf("Error getting migration data: %v", *m.ID)
// FIXME
continue
}

var archiveURL string
_, err = client.(*github.Client).Migrations.UserMigrationArchiveURL(context.Background(), *m.ID)
if err != nil {
archiveURL = "No Longer Available"
} else {
archiveURL = "Available for Download"
}
fmt.Printf("%v - %v - %v - %v\n", *mData.ID, *mData.CreatedAt, *mData.State, archiveURL)
}

} else if *githubCreateUserMigration {

repos, err := getRepositories(client, *service, *githubRepoType, githubNamespaceWhitelist, *gitlabProjectVisibility, *gitlabProjectMembershipType, *ignoreFork)
if err != nil {
log.Fatalf("Error getting list of repositories: %v", err)
}

log.Printf("Creating a user migration for %d repos", len(repos))
m, err := createGithubUserMigration(context.Background(), client, repos, *githubCreateUserMigrationRetry, *githubCreateUserMigrationRetryMax)
if err != nil {
log.Fatalf("Error creating migration: %v", err)
}

if *githubWaitForMigrationComplete {
migrationStatePollingDuration := 60 * time.Second
err = downloadGithubUserMigrationData(context.Background(), client, *backupDir, m.ID, migrationStatePollingDuration)
if err != nil {
log.Fatalf("Error querying/downloading migration: %v", err)
}
}

orgs, err := getGithubUserOwnedOrgs(context.Background(), client)
if err != nil {
log.Fatal("Error getting user organizations", err)
}
for _, o := range orgs {
orgRepos, err := getGithubOrgRepositories(context.Background(), client, o)
if err != nil {
log.Fatal("Error getting org repos", err)
}
if len(orgRepos) == 0 {
log.Printf("No repos found in %s", *o.Login)
continue
}
log.Printf("Creating a org migration (%s) for %d repos", *o.Login, len(orgRepos))
oMigration, err := createGithubOrgMigration(context.Background(), client, *o.Login, orgRepos)
if err != nil {
log.Fatalf("Error creating migration: %v", err)
}
if *githubWaitForMigrationComplete {
migrationStatePollingDuration := 60 * time.Second
downloadGithubOrgMigrationData(context.Background(), client, *o.Login, *backupDir, oMigration.ID, migrationStatePollingDuration)
}
}
client := newClient(c.service, c.gitHostURL)

// TODO implement validation of options so that we don't
// allow multiple operations at one go
if c.githubListUserMigrations {
handleGithubListUserMigrations(client, c)
} else if c.githubCreateUserMigration {
handleGithubCreateUserMigration(client, c)
} else {
tokens := make(chan bool, MaxConcurrentClones)
gitHostUsername = getUsername(client, *service)

if len(gitHostUsername) == 0 && !*ignorePrivate && *useHTTPSClone {
log.Fatal("Your Git host's username is needed for backing up private repositories via HTTPS")
}
repos, err := getRepositories(
client, *service, *githubRepoType, githubNamespaceWhitelist,
*gitlabProjectVisibility, *gitlabProjectMembershipType, *ignoreFork,
)
if err != nil {
log.Fatal(err)
} else {
log.Printf("Backing up %v repositories now..\n", len(repos))
for _, repo := range repos {
tokens <- true
wg.Add(1)
go func(repo *Repository) {
stdoutStderr, err := backUp(*backupDir, repo, *bare, &wg)
if err != nil {
log.Printf("Error backing up %s: %s\n", repo.Name, stdoutStderr)
}
<-tokens
}(repo)
}
}
handleGitRepositoryClone(client, c)
}
}
Loading

0 comments on commit dd62fb0

Please sign in to comment.