git.go 5.81 KB
Newer Older
1
2
3
4
5
6
7
8
package internal

import (
	"fmt"
	"github.com/go-git/go-billy/v5/memfs"
	"github.com/go-git/go-git/v5"
	"github.com/go-git/go-git/v5/config"
	"github.com/go-git/go-git/v5/plumbing"
9
	"github.com/go-git/go-git/v5/plumbing/object"
10
11
12
13
14
15
16
	"github.com/go-git/go-git/v5/storage/memory"
	"io/ioutil"
	"log"
	"net/http"
	"path/filepath"
	"sort"
	"strings"
17
	"time"
18
19
)

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
type remoteTarget struct {
	remote string
	when   time.Time
}

type remoteTargetSlice []remoteTarget

func (p remoteTargetSlice) Len() int {
	return len(p)
}

func (p remoteTargetSlice) Less(i, j int) bool {
	return p[i].when.Before(p[j].when)
}

func (p remoteTargetSlice) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
type GitMode struct{}

func (g *GitMode) RetrieveSource(pd *ProcessData) *modeData {
	repo, err := git.Init(memory.NewStorage(), memfs.New())
	if err != nil {
		log.Fatalf("could not init git repo: %v", err)
	}

	w, err := repo.Worktree()
	if err != nil {
		log.Fatalf("could not get worktree: %v", err)
	}

	refspec := config.RefSpec("+refs/heads/*:refs/remotes/*")
	remote, err := repo.CreateRemote(&config.RemoteConfig{
		Name:  "upstream",
		URLs:  []string{pd.RpmLocation},
		Fetch: []config.RefSpec{refspec},
	})
	if err != nil {
		log.Fatalf("could not create remote: %v", err)
	}

62
63
64
65
66
67
	err = remote.Fetch(&git.FetchOptions{
		RemoteName: "upstream",
		RefSpecs:   []config.RefSpec{refspec},
		Tags:       git.AllTags,
		Force:      true,
	})
68
	if err != nil {
69
		log.Fatalf("could not fetch upstream: %v", err)
70
71
	}

72
	var branches remoteTargetSlice
73

74
75
76
	tagIter, err := repo.TagObjects()
	if err != nil {
		log.Fatalf("could not get tag objects: %v", err)
77
	}
78
79
80
81
82
83
84
	_ = tagIter.ForEach(func(tag *object.Tag) error {
		log.Printf("tag: %s", tag.Name)
		if strings.HasPrefix(tag.Name, fmt.Sprintf("imports/c%d", pd.Version)) {
			branches = append(branches, remoteTarget{
				remote: fmt.Sprintf("refs/tags/%s", tag.Name),
				when:   tag.Tagger.When,
			})
Mustafa Gezen's avatar
Mustafa Gezen committed
85
		}
86
87
88
89
90
91
92
		return nil
	})
	sort.Sort(branches)

	var sortedBranches []string
	for _, branch := range branches {
		sortedBranches = append(sortedBranches, branch.remote)
Mustafa Gezen's avatar
Mustafa Gezen committed
93
	}
94
95
96
97
98
99

	return &modeData{
		repo:       repo,
		worktree:   w,
		rpmFile:    createPackageFile(filepath.Base(pd.RpmLocation)),
		fileWrites: nil,
100
		branches:   sortedBranches,
101
102
103
104
105
106
107
108
109
	}
}

func (g *GitMode) WriteSource(md *modeData) {
	remote, err := md.repo.Remote("upstream")
	if err != nil {
		log.Fatalf("could not get upstream remote: %v", err)
	}

Mustafa Gezen's avatar
Mustafa Gezen committed
110
111
112
113
114
115
116
117
118
119
120
	var refspec config.RefSpec
	var branchName string

	if strings.HasPrefix(md.tagBranch, "refs/heads") {
		refspec = config.RefSpec(fmt.Sprintf("+%s:%s", md.tagBranch, md.tagBranch))
		branchName = strings.TrimPrefix(md.tagBranch, "refs/heads/")
	} else {
		match := tagImportRegex.FindStringSubmatch(md.tagBranch)
		branchName = match[2]
		refspec = config.RefSpec(fmt.Sprintf("+refs/heads/%s:%s", branchName, md.tagBranch))
	}
121
	log.Printf("checking out upstream refspec %s", refspec)
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
	err = remote.Fetch(&git.FetchOptions{
		RemoteName: "upstream",
		RefSpecs:   []config.RefSpec{refspec},
		Tags:       git.AllTags,
		Force:      true,
	})
	if err != nil {
		log.Fatalf("could not fetch upstream: %v", err)
	}

	err = md.worktree.Checkout(&git.CheckoutOptions{
		Branch: plumbing.ReferenceName(md.tagBranch),
		Force:  true,
	})
	if err != nil {
		log.Fatalf("could not checkout source from git: %v", err)
	}

	_, err = md.worktree.Add(".")
	if err != nil {
		log.Fatalf("could not add worktree: %v", err)
	}

	metadataFile, err := md.worktree.Filesystem.Open(fmt.Sprintf(".%s.metadata", md.rpmFile.Name()))
	if err != nil {
Mustafa Gezen's avatar
Mustafa Gezen committed
147
148
		log.Printf("warn: could not open metadata file, so skipping: %v", err)
		return
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
	}

	fileBytes, err := ioutil.ReadAll(metadataFile)
	if err != nil {
		log.Fatalf("could not read metadata file: %v", err)
	}

	client := &http.Client{
		Transport: &http.Transport{
			DisableCompression: false,
		},
	}
	fileContent := strings.Split(string(fileBytes), "\n")
	for _, line := range fileContent {
		if strings.TrimSpace(line) == "" {
			continue
		}

167
168
169
		lineInfo := strings.SplitN(line, " ", 2)
		hash := strings.TrimSpace(lineInfo[0])
		path := strings.TrimSpace(lineInfo[1])
170

Mustafa Gezen's avatar
Mustafa Gezen committed
171
		url := fmt.Sprintf("https://git.centos.org/sources/%s/%s/%s", md.rpmFile.Name(), branchName, hash)
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
		log.Printf("downloading %s", url)

		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			log.Fatalf("could not create new http request: %v", err)
		}
		req.Header.Set("Accept-Encoding", "*")

		resp, err := client.Do(req)
		if err != nil {
			log.Fatalf("could not download dist-git file: %v", err)
		}

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatalf("could not read the whole dist-git file: %v", err)
		}
		err = resp.Body.Close()
		if err != nil {
			log.Fatalf("could not close body handle: %v", err)
		}

		f, err := md.worktree.Filesystem.Create(path)
		if err != nil {
			log.Fatalf("could not open file pointer: %v", err)
		}

Mustafa Gezen's avatar
Mustafa Gezen committed
199
		hasher := CompareHash(body, hash)
200
201
202
203
204
		if hasher == nil {
			log.Fatal("checksum in metadata does not match dist-git file")
		}

		md.sourcesToIgnore = append(md.sourcesToIgnore, &ignoredSource{
205
			name:         path,
206
207
208
209
210
211
212
213
214
215
216
217
218
			hashFunction: hasher,
		})

		_, err = f.Write(body)
		if err != nil {
			log.Fatalf("could not copy dist-git file to in-tree: %v", err)
		}
		_ = f.Close()
	}
}

func (g *GitMode) PostProcess(md *modeData) {
	for _, source := range md.sourcesToIgnore {
219
220
221
222
223
224
		_, err := md.worktree.Filesystem.Stat(source.name)
		if err == nil {
			err := md.worktree.Filesystem.Remove(source.name)
			if err != nil {
				log.Fatalf("could not remove dist-git file: %v", err)
			}
225
226
227
228
229
230
231
232
233
234
		}
	}

	_, err := md.worktree.Add(".")
	if err != nil {
		log.Fatalf("could not add git sources: %v", err)
	}
}

func (g *GitMode) ImportName(_ *ProcessData, md *modeData) string {
Mustafa Gezen's avatar
Mustafa Gezen committed
235
236
237
238
239
240
	if tagImportRegex.MatchString(md.tagBranch) {
		match := tagImportRegex.FindStringSubmatch(md.tagBranch)
		return match[3]
	}

	return strings.TrimPrefix(md.tagBranch, "refs/heads/")
241
}