xref: /aosp_15_r20/external/swiftshader/tests/regres/git/git.go (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
2*03ce13f7SAndroid Build Coastguard Worker//
3*03ce13f7SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*03ce13f7SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*03ce13f7SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*03ce13f7SAndroid Build Coastguard Worker//
7*03ce13f7SAndroid Build Coastguard Worker//    http://www.apache.org/licenses/LICENSE-2.0
8*03ce13f7SAndroid Build Coastguard Worker//
9*03ce13f7SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*03ce13f7SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*03ce13f7SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*03ce13f7SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*03ce13f7SAndroid Build Coastguard Worker// limitations under the License.
14*03ce13f7SAndroid Build Coastguard Worker
15*03ce13f7SAndroid Build Coastguard Worker// Package git provides functions for interacting with Git.
16*03ce13f7SAndroid Build Coastguard Workerpackage git
17*03ce13f7SAndroid Build Coastguard Worker
18*03ce13f7SAndroid Build Coastguard Workerimport (
19*03ce13f7SAndroid Build Coastguard Worker	"encoding/hex"
20*03ce13f7SAndroid Build Coastguard Worker	"fmt"
21*03ce13f7SAndroid Build Coastguard Worker	"io/ioutil"
22*03ce13f7SAndroid Build Coastguard Worker	"net/url"
23*03ce13f7SAndroid Build Coastguard Worker	"os"
24*03ce13f7SAndroid Build Coastguard Worker	"os/exec"
25*03ce13f7SAndroid Build Coastguard Worker	"strings"
26*03ce13f7SAndroid Build Coastguard Worker	"time"
27*03ce13f7SAndroid Build Coastguard Worker
28*03ce13f7SAndroid Build Coastguard Worker	"swiftshader.googlesource.com/SwiftShader/tests/regres/shell"
29*03ce13f7SAndroid Build Coastguard Worker)
30*03ce13f7SAndroid Build Coastguard Worker
31*03ce13f7SAndroid Build Coastguard Workerconst (
32*03ce13f7SAndroid Build Coastguard Worker	gitTimeout = time.Minute * 15 // timeout for a git operation
33*03ce13f7SAndroid Build Coastguard Worker)
34*03ce13f7SAndroid Build Coastguard Worker
35*03ce13f7SAndroid Build Coastguard Workervar exe string
36*03ce13f7SAndroid Build Coastguard Worker
37*03ce13f7SAndroid Build Coastguard Workerfunc init() {
38*03ce13f7SAndroid Build Coastguard Worker	path, err := exec.LookPath("git")
39*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
40*03ce13f7SAndroid Build Coastguard Worker		panic(fmt.Errorf("failed to find path to git executable: %w", err))
41*03ce13f7SAndroid Build Coastguard Worker	}
42*03ce13f7SAndroid Build Coastguard Worker	exe = path
43*03ce13f7SAndroid Build Coastguard Worker}
44*03ce13f7SAndroid Build Coastguard Worker
45*03ce13f7SAndroid Build Coastguard Worker// Hash is a 20 byte, git object hash.
46*03ce13f7SAndroid Build Coastguard Workertype Hash [20]byte
47*03ce13f7SAndroid Build Coastguard Worker
48*03ce13f7SAndroid Build Coastguard Workerfunc (h Hash) String() string { return hex.EncodeToString(h[:]) }
49*03ce13f7SAndroid Build Coastguard Worker
50*03ce13f7SAndroid Build Coastguard Worker// ParseHash returns a Hash from a hexadecimal string.
51*03ce13f7SAndroid Build Coastguard Workerfunc ParseHash(s string) Hash {
52*03ce13f7SAndroid Build Coastguard Worker	b, _ := hex.DecodeString(s)
53*03ce13f7SAndroid Build Coastguard Worker	h := Hash{}
54*03ce13f7SAndroid Build Coastguard Worker	copy(h[:], b)
55*03ce13f7SAndroid Build Coastguard Worker	return h
56*03ce13f7SAndroid Build Coastguard Worker}
57*03ce13f7SAndroid Build Coastguard Worker
58*03ce13f7SAndroid Build Coastguard Worker// Add calls 'git add <file>'.
59*03ce13f7SAndroid Build Coastguard Workerfunc Add(wd, file string) error {
60*03ce13f7SAndroid Build Coastguard Worker	if err := shell.Shell(gitTimeout, exe, wd, "add", file); err != nil {
61*03ce13f7SAndroid Build Coastguard Worker		return fmt.Errorf("`git add %v` in working directory %v failed: %w", file, wd, err)
62*03ce13f7SAndroid Build Coastguard Worker	}
63*03ce13f7SAndroid Build Coastguard Worker	return nil
64*03ce13f7SAndroid Build Coastguard Worker}
65*03ce13f7SAndroid Build Coastguard Worker
66*03ce13f7SAndroid Build Coastguard Worker// CommitFlags advanced flags for Commit
67*03ce13f7SAndroid Build Coastguard Workertype CommitFlags struct {
68*03ce13f7SAndroid Build Coastguard Worker	Name  string // Used for author and committer
69*03ce13f7SAndroid Build Coastguard Worker	Email string // Used for author and committer
70*03ce13f7SAndroid Build Coastguard Worker}
71*03ce13f7SAndroid Build Coastguard Worker
72*03ce13f7SAndroid Build Coastguard Worker// Commit calls 'git commit -m <msg> --author <author>'.
73*03ce13f7SAndroid Build Coastguard Workerfunc Commit(wd, msg string, flags CommitFlags) error {
74*03ce13f7SAndroid Build Coastguard Worker	args := []string{}
75*03ce13f7SAndroid Build Coastguard Worker	if flags.Name != "" {
76*03ce13f7SAndroid Build Coastguard Worker		args = append(args, "-c", "user.name="+flags.Name)
77*03ce13f7SAndroid Build Coastguard Worker	}
78*03ce13f7SAndroid Build Coastguard Worker	if flags.Email != "" {
79*03ce13f7SAndroid Build Coastguard Worker		args = append(args, "-c", "user.email="+flags.Email)
80*03ce13f7SAndroid Build Coastguard Worker	}
81*03ce13f7SAndroid Build Coastguard Worker	args = append(args, "commit", "-m", msg)
82*03ce13f7SAndroid Build Coastguard Worker	return shell.Shell(gitTimeout, exe, wd, args...)
83*03ce13f7SAndroid Build Coastguard Worker}
84*03ce13f7SAndroid Build Coastguard Worker
85*03ce13f7SAndroid Build Coastguard Worker// PushFlags advanced flags for Commit
86*03ce13f7SAndroid Build Coastguard Workertype PushFlags struct {
87*03ce13f7SAndroid Build Coastguard Worker	Username string // Used for authentication when uploading
88*03ce13f7SAndroid Build Coastguard Worker	Password string // Used for authentication when uploading
89*03ce13f7SAndroid Build Coastguard Worker}
90*03ce13f7SAndroid Build Coastguard Worker
91*03ce13f7SAndroid Build Coastguard Worker// Push pushes the local branch to remote.
92*03ce13f7SAndroid Build Coastguard Workerfunc Push(wd, remote, localBranch, remoteBranch string, flags PushFlags) error {
93*03ce13f7SAndroid Build Coastguard Worker	args := []string{}
94*03ce13f7SAndroid Build Coastguard Worker	if flags.Username != "" {
95*03ce13f7SAndroid Build Coastguard Worker		f, err := ioutil.TempFile("", "regres-cookies.txt")
96*03ce13f7SAndroid Build Coastguard Worker		if err != nil {
97*03ce13f7SAndroid Build Coastguard Worker			return fmt.Errorf("failed to create cookie file: %w", err)
98*03ce13f7SAndroid Build Coastguard Worker		}
99*03ce13f7SAndroid Build Coastguard Worker		defer f.Close()
100*03ce13f7SAndroid Build Coastguard Worker		defer os.Remove(f.Name())
101*03ce13f7SAndroid Build Coastguard Worker		u, err := url.Parse(remote)
102*03ce13f7SAndroid Build Coastguard Worker		if err != nil {
103*03ce13f7SAndroid Build Coastguard Worker			return fmt.Errorf("failed to parse url '%v': %w", remote, err)
104*03ce13f7SAndroid Build Coastguard Worker		}
105*03ce13f7SAndroid Build Coastguard Worker		f.WriteString(fmt.Sprintf("%v	FALSE	/	TRUE	2147483647	o	%v=%v\n", u.Host, flags.Username, flags.Password))
106*03ce13f7SAndroid Build Coastguard Worker		f.Close()
107*03ce13f7SAndroid Build Coastguard Worker		args = append(args, "-c", "http.cookiefile="+f.Name())
108*03ce13f7SAndroid Build Coastguard Worker	}
109*03ce13f7SAndroid Build Coastguard Worker	args = append(args, "push", remote, localBranch+":"+remoteBranch)
110*03ce13f7SAndroid Build Coastguard Worker	return shell.Shell(gitTimeout, exe, wd, args...)
111*03ce13f7SAndroid Build Coastguard Worker}
112*03ce13f7SAndroid Build Coastguard Worker
113*03ce13f7SAndroid Build Coastguard Worker// CheckoutRemoteBranch performs a git fetch and checkout of the given branch into path.
114*03ce13f7SAndroid Build Coastguard Workerfunc CheckoutRemoteBranch(path, url string, branch string) error {
115*03ce13f7SAndroid Build Coastguard Worker	if err := os.MkdirAll(path, 0777); err != nil {
116*03ce13f7SAndroid Build Coastguard Worker		return fmt.Errorf("mkdir '"+path+"' failed: %w", err)
117*03ce13f7SAndroid Build Coastguard Worker	}
118*03ce13f7SAndroid Build Coastguard Worker
119*03ce13f7SAndroid Build Coastguard Worker	for _, cmds := range [][]string{
120*03ce13f7SAndroid Build Coastguard Worker		{"init"},
121*03ce13f7SAndroid Build Coastguard Worker		{"remote", "add", "origin", url},
122*03ce13f7SAndroid Build Coastguard Worker		{"fetch", "origin", "--depth=1", branch},
123*03ce13f7SAndroid Build Coastguard Worker		{"checkout", branch},
124*03ce13f7SAndroid Build Coastguard Worker	} {
125*03ce13f7SAndroid Build Coastguard Worker		if err := shell.Shell(gitTimeout, exe, path, cmds...); err != nil {
126*03ce13f7SAndroid Build Coastguard Worker			os.RemoveAll(path)
127*03ce13f7SAndroid Build Coastguard Worker			return err
128*03ce13f7SAndroid Build Coastguard Worker		}
129*03ce13f7SAndroid Build Coastguard Worker	}
130*03ce13f7SAndroid Build Coastguard Worker
131*03ce13f7SAndroid Build Coastguard Worker	return nil
132*03ce13f7SAndroid Build Coastguard Worker}
133*03ce13f7SAndroid Build Coastguard Worker
134*03ce13f7SAndroid Build Coastguard Worker// CheckoutRemoteCommit performs a git fetch and checkout of the given commit into path.
135*03ce13f7SAndroid Build Coastguard Workerfunc CheckoutRemoteCommit(path, url string, commit Hash) error {
136*03ce13f7SAndroid Build Coastguard Worker	if err := os.MkdirAll(path, 0777); err != nil {
137*03ce13f7SAndroid Build Coastguard Worker		return fmt.Errorf("mkdir '"+path+"' failed: %w", err)
138*03ce13f7SAndroid Build Coastguard Worker	}
139*03ce13f7SAndroid Build Coastguard Worker
140*03ce13f7SAndroid Build Coastguard Worker	for _, cmds := range [][]string{
141*03ce13f7SAndroid Build Coastguard Worker		{"init"},
142*03ce13f7SAndroid Build Coastguard Worker		{"remote", "add", "origin", url},
143*03ce13f7SAndroid Build Coastguard Worker		{"fetch", "origin", "--depth=1", commit.String()},
144*03ce13f7SAndroid Build Coastguard Worker		{"checkout", commit.String()},
145*03ce13f7SAndroid Build Coastguard Worker	} {
146*03ce13f7SAndroid Build Coastguard Worker		if err := shell.Shell(gitTimeout, exe, path, cmds...); err != nil {
147*03ce13f7SAndroid Build Coastguard Worker			os.RemoveAll(path)
148*03ce13f7SAndroid Build Coastguard Worker			return err
149*03ce13f7SAndroid Build Coastguard Worker		}
150*03ce13f7SAndroid Build Coastguard Worker	}
151*03ce13f7SAndroid Build Coastguard Worker
152*03ce13f7SAndroid Build Coastguard Worker	return nil
153*03ce13f7SAndroid Build Coastguard Worker}
154*03ce13f7SAndroid Build Coastguard Worker
155*03ce13f7SAndroid Build Coastguard Worker// CheckoutCommit performs a git checkout of the given commit.
156*03ce13f7SAndroid Build Coastguard Workerfunc CheckoutCommit(path string, commit Hash) error {
157*03ce13f7SAndroid Build Coastguard Worker	return shell.Shell(gitTimeout, exe, path, "checkout", commit.String())
158*03ce13f7SAndroid Build Coastguard Worker}
159*03ce13f7SAndroid Build Coastguard Worker
160*03ce13f7SAndroid Build Coastguard Worker// Apply applys the patch file to the git repo at dir.
161*03ce13f7SAndroid Build Coastguard Workerfunc Apply(dir, patch string) error {
162*03ce13f7SAndroid Build Coastguard Worker	return shell.Shell(gitTimeout, exe, dir, "apply", patch)
163*03ce13f7SAndroid Build Coastguard Worker}
164*03ce13f7SAndroid Build Coastguard Worker
165*03ce13f7SAndroid Build Coastguard Worker// FetchRefHash returns the git hash of the given ref.
166*03ce13f7SAndroid Build Coastguard Workerfunc FetchRefHash(ref, url string) (Hash, error) {
167*03ce13f7SAndroid Build Coastguard Worker	out, err := shell.Exec(gitTimeout, exe, "", nil, "", "ls-remote", url, ref)
168*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
169*03ce13f7SAndroid Build Coastguard Worker		return Hash{}, err
170*03ce13f7SAndroid Build Coastguard Worker	}
171*03ce13f7SAndroid Build Coastguard Worker	return ParseHash(string(out)), nil
172*03ce13f7SAndroid Build Coastguard Worker}
173*03ce13f7SAndroid Build Coastguard Worker
174*03ce13f7SAndroid Build Coastguard Workertype ChangeList struct {
175*03ce13f7SAndroid Build Coastguard Worker	Hash        Hash
176*03ce13f7SAndroid Build Coastguard Worker	Date        time.Time
177*03ce13f7SAndroid Build Coastguard Worker	Author      string
178*03ce13f7SAndroid Build Coastguard Worker	Subject     string
179*03ce13f7SAndroid Build Coastguard Worker	Description string
180*03ce13f7SAndroid Build Coastguard Worker}
181*03ce13f7SAndroid Build Coastguard Worker
182*03ce13f7SAndroid Build Coastguard Worker// Log returns the top count ChangeLists at HEAD.
183*03ce13f7SAndroid Build Coastguard Workerfunc Log(path string, count int) ([]ChangeList, error) {
184*03ce13f7SAndroid Build Coastguard Worker	return LogFrom(path, "HEAD", count)
185*03ce13f7SAndroid Build Coastguard Worker}
186*03ce13f7SAndroid Build Coastguard Worker
187*03ce13f7SAndroid Build Coastguard Worker// LogFrom returns the top count ChangeList starting from at.
188*03ce13f7SAndroid Build Coastguard Workerfunc LogFrom(path, at string, count int) ([]ChangeList, error) {
189*03ce13f7SAndroid Build Coastguard Worker	if at == "" {
190*03ce13f7SAndroid Build Coastguard Worker		at = "HEAD"
191*03ce13f7SAndroid Build Coastguard Worker	}
192*03ce13f7SAndroid Build Coastguard Worker	out, err := shell.Exec(gitTimeout, exe, "", nil, "", "log", at, "--pretty=format:"+prettyFormat, fmt.Sprintf("-%d", count), path)
193*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
194*03ce13f7SAndroid Build Coastguard Worker		return nil, err
195*03ce13f7SAndroid Build Coastguard Worker	}
196*03ce13f7SAndroid Build Coastguard Worker	return parseLog(string(out)), nil
197*03ce13f7SAndroid Build Coastguard Worker}
198*03ce13f7SAndroid Build Coastguard Worker
199*03ce13f7SAndroid Build Coastguard Worker// Parent returns the parent ChangeList for cl.
200*03ce13f7SAndroid Build Coastguard Workerfunc Parent(cl ChangeList) (ChangeList, error) {
201*03ce13f7SAndroid Build Coastguard Worker	out, err := shell.Exec(gitTimeout, exe, "", nil, "", "log", "--pretty=format:"+prettyFormat, fmt.Sprintf("%v^", cl.Hash))
202*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
203*03ce13f7SAndroid Build Coastguard Worker		return ChangeList{}, err
204*03ce13f7SAndroid Build Coastguard Worker	}
205*03ce13f7SAndroid Build Coastguard Worker	cls := parseLog(string(out))
206*03ce13f7SAndroid Build Coastguard Worker	if len(cls) == 0 {
207*03ce13f7SAndroid Build Coastguard Worker		return ChangeList{}, fmt.Errorf("Unexpected output")
208*03ce13f7SAndroid Build Coastguard Worker	}
209*03ce13f7SAndroid Build Coastguard Worker	return cls[0], nil
210*03ce13f7SAndroid Build Coastguard Worker}
211*03ce13f7SAndroid Build Coastguard Worker
212*03ce13f7SAndroid Build Coastguard Worker// HeadCL returns the HEAD ChangeList at the given commit/tag/branch.
213*03ce13f7SAndroid Build Coastguard Workerfunc HeadCL(path string) (ChangeList, error) {
214*03ce13f7SAndroid Build Coastguard Worker	cls, err := LogFrom(path, "HEAD", 1)
215*03ce13f7SAndroid Build Coastguard Worker	if err != nil {
216*03ce13f7SAndroid Build Coastguard Worker		return ChangeList{}, err
217*03ce13f7SAndroid Build Coastguard Worker	}
218*03ce13f7SAndroid Build Coastguard Worker	if len(cls) == 0 {
219*03ce13f7SAndroid Build Coastguard Worker		return ChangeList{}, fmt.Errorf("No commits found")
220*03ce13f7SAndroid Build Coastguard Worker	}
221*03ce13f7SAndroid Build Coastguard Worker	return cls[0], nil
222*03ce13f7SAndroid Build Coastguard Worker}
223*03ce13f7SAndroid Build Coastguard Worker
224*03ce13f7SAndroid Build Coastguard Worker// Show content of the file at path for the given commit/tag/branch.
225*03ce13f7SAndroid Build Coastguard Workerfunc Show(path, at string) ([]byte, error) {
226*03ce13f7SAndroid Build Coastguard Worker	return shell.Exec(gitTimeout, exe, "", nil, "", "show", at+":"+path)
227*03ce13f7SAndroid Build Coastguard Worker}
228*03ce13f7SAndroid Build Coastguard Worker
229*03ce13f7SAndroid Build Coastguard Workerconst prettyFormat = "ǁ%Hǀ%cIǀ%an <%ae>ǀ%sǀ%b"
230*03ce13f7SAndroid Build Coastguard Worker
231*03ce13f7SAndroid Build Coastguard Workerfunc parseLog(str string) []ChangeList {
232*03ce13f7SAndroid Build Coastguard Worker	msgs := strings.Split(str, "ǁ")
233*03ce13f7SAndroid Build Coastguard Worker	cls := make([]ChangeList, 0, len(msgs))
234*03ce13f7SAndroid Build Coastguard Worker	for _, s := range msgs {
235*03ce13f7SAndroid Build Coastguard Worker		if parts := strings.Split(s, "ǀ"); len(parts) == 5 {
236*03ce13f7SAndroid Build Coastguard Worker			cl := ChangeList{
237*03ce13f7SAndroid Build Coastguard Worker				Hash:        ParseHash(parts[0]),
238*03ce13f7SAndroid Build Coastguard Worker				Author:      strings.TrimSpace(parts[2]),
239*03ce13f7SAndroid Build Coastguard Worker				Subject:     strings.TrimSpace(parts[3]),
240*03ce13f7SAndroid Build Coastguard Worker				Description: strings.TrimSpace(parts[4]),
241*03ce13f7SAndroid Build Coastguard Worker			}
242*03ce13f7SAndroid Build Coastguard Worker			date, err := time.Parse(time.RFC3339, parts[1])
243*03ce13f7SAndroid Build Coastguard Worker			if err != nil {
244*03ce13f7SAndroid Build Coastguard Worker				panic(err)
245*03ce13f7SAndroid Build Coastguard Worker			}
246*03ce13f7SAndroid Build Coastguard Worker			cl.Date = date
247*03ce13f7SAndroid Build Coastguard Worker
248*03ce13f7SAndroid Build Coastguard Worker			cls = append(cls, cl)
249*03ce13f7SAndroid Build Coastguard Worker		}
250*03ce13f7SAndroid Build Coastguard Worker	}
251*03ce13f7SAndroid Build Coastguard Worker	return cls
252*03ce13f7SAndroid Build Coastguard Worker}
253