summaryrefslogtreecommitdiff
path: root/internal/sync/repository_setup.go
blob: 3ebafbd3a6d7cb575dede23d3c579e4eb9106f12 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package sync

import (
	"fmt"
	"os"
	"os/exec"

	"codeberg.org/snonux/gitsyncer/internal/config"
)

// setupRepository ensures the repository exists and all remotes are configured
func (s *Syncer) setupRepository(repoPath string) error {
	if _, err := os.Stat(repoPath); os.IsNotExist(err) {
		return s.setupNewRepository(repoPath)
	}
	return s.setupExistingRepository(repoPath)
}

// setupNewRepository clones and configures a new repository
func (s *Syncer) setupNewRepository(repoPath string) error {
	if len(s.config.Organizations) == 0 {
		return fmt.Errorf("no organizations configured")
	}

	// Find first non-backup organization to clone from
	var firstOrg *config.Organization
	var firstOrgIndex int
	for i := range s.config.Organizations {
		if !s.config.Organizations[i].BackupLocation {
			firstOrg = &s.config.Organizations[i]
			firstOrgIndex = i
			break
		}
	}

	if firstOrg == nil {
		return fmt.Errorf("no non-backup organizations configured to clone from")
	}

	if err := s.cloneRepository(firstOrg, repoPath); err != nil {
		return fmt.Errorf("failed to clone repository: %w", err)
	}

	// Rename origin to the proper remote name
	firstRemoteName := s.getRemoteName(firstOrg)
	cmd := exec.Command("git", "-C", repoPath, "remote", "rename", "origin", firstRemoteName)
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to rename origin remote: %w", err)
	}

	// Add other organizations as remotes
	for i := range s.config.Organizations {
		if i == firstOrgIndex {
			continue // Skip the first org we already cloned from
		}
		org := &s.config.Organizations[i]
		
		// Skip backup locations if backup is not enabled
		if org.BackupLocation && !s.backupEnabled {
			continue
		}
		
		if err := s.addRemote(repoPath, org); err != nil {
			return fmt.Errorf("failed to add remote %s: %w", s.getRemoteName(org), err)
		}
	}

	return nil
}

// setupExistingRepository ensures all remotes are configured for an existing repository
func (s *Syncer) setupExistingRepository(repoPath string) error {
	fmt.Printf("Using existing repository at %s\n", repoPath)

	// Check and add any missing remotes
	for i := range s.config.Organizations {
		org := &s.config.Organizations[i]
		
		// Skip backup locations if backup is not enabled
		if org.BackupLocation && !s.backupEnabled {
			continue
		}
		
		remoteName := s.getRemoteName(org)

		// Check if remote exists
		cmd := exec.Command("git", "-C", repoPath, "remote", "get-url", remoteName)
		if err := cmd.Run(); err != nil {
			// Remote doesn't exist, add it
			if err := s.addRemote(repoPath, org); err != nil {
				return fmt.Errorf("failed to add remote %s: %w", remoteName, err)
			}
		}
	}

	return nil
}

// changeToRepoDirectory changes to the repository directory and returns a function to restore the original directory
func changeToRepoDirectory(repoPath string) (func(), error) {
	originalDir, err := os.Getwd()
	if err != nil {
		return nil, fmt.Errorf("failed to get current directory: %w", err)
	}

	if err := os.Chdir(repoPath); err != nil {
		return nil, fmt.Errorf("failed to change to repository directory: %w", err)
	}

	return func() { os.Chdir(originalDir) }, nil
}

// getRemotesMap creates a map of remote names to organizations
func (s *Syncer) getRemotesMap() map[string]*config.Organization {
	remotes := make(map[string]*config.Organization)
	for i := range s.config.Organizations {
		org := &s.config.Organizations[i]
		
		// Skip backup locations if backup is not enabled
		if org.BackupLocation && !s.backupEnabled {
			continue
		}
		
		remoteName := s.getRemoteName(org)
		remotes[remoteName] = org
	}
	return remotes
}