github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/performance/utils/dolt_builder/run.go (about) 1 // Copyright 2019-2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package dolt_builder 16 17 import ( 18 "context" 19 "errors" 20 "fmt" 21 "os" 22 "os/signal" 23 "path/filepath" 24 "runtime" 25 "sync" 26 "syscall" 27 28 "golang.org/x/sync/errgroup" 29 ) 30 31 const envDoltBin = "DOLT_BIN" 32 33 func Run(parentCtx context.Context, commitList []string, profilePath string) error { 34 if profilePath != "" && len(commitList) > 1 { 35 return errors.New("cannot build more that one binary when a profile is supplied") 36 } 37 38 doltBin, err := getDoltBin() 39 if err != nil { 40 return err 41 } 42 43 // check for git on path 44 err = GitVersion(parentCtx) 45 if err != nil { 46 return err 47 } 48 49 cwd, err := os.Getwd() 50 if err != nil { 51 return err 52 } 53 54 // make temp dir for cloning/copying dolt source 55 tempDir := filepath.Join(cwd, "clones-copies") 56 err = os.MkdirAll(tempDir, os.ModePerm) 57 if err != nil { 58 return err 59 } 60 61 // clone dolt source 62 err = GitCloneBare(parentCtx, tempDir, GithubDolt) 63 if err != nil { 64 return err 65 } 66 67 repoDir := filepath.Join(tempDir, "dolt.git") 68 69 withKeyCtx, cancel := context.WithCancel(parentCtx) 70 g, ctx := errgroup.WithContext(withKeyCtx) 71 72 // handle user interrupt 73 quit := make(chan os.Signal, 1) 74 signal.Notify(quit, os.Interrupt, syscall.SIGTERM) 75 var wg sync.WaitGroup 76 wg.Add(1) 77 go func() { 78 <-quit 79 defer wg.Done() 80 signal.Stop(quit) 81 cancel() 82 }() 83 84 for _, commit := range commitList { 85 commit := commit // https://golang.org/doc/faq#closures_and_goroutines 86 g.Go(func() error { 87 return buildBinaries(ctx, tempDir, repoDir, doltBin, profilePath, commit) 88 }) 89 } 90 91 builderr := g.Wait() 92 close(quit) 93 wg.Wait() 94 95 // remove clones-copies after all go routines complete 96 // will exit successfully if removal fails 97 if err := os.RemoveAll(tempDir); err != nil { 98 fmt.Printf("WARN: %s was not removed\n", tempDir) 99 fmt.Printf("WARN: error: %v\n", err) 100 } 101 102 if builderr != nil { 103 return builderr 104 } 105 106 return nil 107 } 108 109 // getDoltBin creates and returns the absolute path for DOLT_BIN 110 // if it was found, otherwise uses the current working directory 111 // as the parent directory for a `doltBin` directory 112 func getDoltBin() (string, error) { 113 var doltBin string 114 dir := os.Getenv(envDoltBin) 115 if dir == "" { 116 cwd, err := os.Getwd() 117 if err != nil { 118 return "", err 119 } 120 doltBin = filepath.Join(cwd, "doltBin") 121 } else { 122 abs, err := filepath.Abs(dir) 123 if err != nil { 124 return "", err 125 } 126 doltBin = abs 127 } 128 err := os.MkdirAll(doltBin, os.ModePerm) 129 if err != nil { 130 return "", err 131 } 132 return doltBin, nil 133 } 134 135 // buildBinaries builds a dolt binary at the given commit and stores it in the doltBin 136 func buildBinaries(ctx context.Context, tempDir, repoDir, doltBinDir, profilePath, commit string) error { 137 checkoutDir := filepath.Join(tempDir, commit) 138 if err := os.MkdirAll(checkoutDir, os.ModePerm); err != nil { 139 return err 140 } 141 142 err := GitCheckoutTree(ctx, repoDir, checkoutDir, commit) 143 if err != nil { 144 return err 145 } 146 147 commitDir := filepath.Join(doltBinDir, commit) 148 if err := os.MkdirAll(commitDir, os.ModePerm); err != nil { 149 return err 150 } 151 152 command, err := goBuild(ctx, checkoutDir, commitDir, profilePath) 153 if err != nil { 154 return err 155 } 156 157 return doltVersion(ctx, commitDir, command) 158 } 159 160 // goBuild builds the dolt binary and returns the filename 161 func goBuild(ctx context.Context, source, dest, profilePath string) (string, error) { 162 goDir := filepath.Join(source, "go") 163 doltFileName := "dolt" 164 if runtime.GOOS == "windows" { 165 doltFileName = "dolt.exe" 166 } 167 168 args := make([]string, 0) 169 args = append(args, "build") 170 171 if profilePath != "" { 172 args = append(args, fmt.Sprintf("-pgo=%s", profilePath)) 173 } 174 175 toBuild := filepath.Join(dest, doltFileName) 176 args = append(args, "-o", toBuild, filepath.Join(goDir, "cmd", "dolt")) 177 178 build := ExecCommand(ctx, "go", args...) 179 build.Dir = goDir 180 err := build.Run() 181 if err != nil { 182 return "", err 183 } 184 return toBuild, nil 185 } 186 187 // doltVersion prints dolt version of binary 188 func doltVersion(ctx context.Context, dir, command string) error { 189 doltVersion := ExecCommand(ctx, command, "version") 190 doltVersion.Stderr = os.Stderr 191 doltVersion.Stdout = os.Stdout 192 doltVersion.Dir = dir 193 return doltVersion.Run() 194 }