github.com/nuvolaris/nuv@v0.0.0-20240511174247-a74e3a52bfd8/prepare.go (about) 1 // Licensed to the Apache Software Foundation (ASF) under one 2 // or more contributor license agreements. See the NOTICE file 3 // distributed with this work for additional information 4 // regarding copyright ownership. The ASF licenses this file 5 // to you under the Apache License, Version 2.0 (the 6 // "License"); you may not use this file except in compliance 7 // with the License. You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 package main 18 19 import ( 20 "fmt" 21 "os" 22 "os/exec" 23 "path/filepath" 24 "strings" 25 26 "github.com/Masterminds/semver" 27 git "github.com/go-git/go-git/v5" 28 "github.com/go-git/go-git/v5/plumbing" 29 "github.com/mitchellh/go-homedir" 30 ) 31 32 func downloadTasksFromGitHub(force bool, silent bool) (string, error) { 33 debug("Download tasks from github") 34 repoURL := getNuvRepo() 35 branch := getNuvBranch() 36 nuvDir, err := homedir.Expand("~/.nuv") 37 if err != nil { 38 return "", err 39 } 40 if err := os.MkdirAll(nuvDir, 0755); err != nil { 41 return "", err 42 } 43 44 nuvBranchDir := joinpath(nuvDir, branch) 45 localDir, err := homedir.Expand(joinpath(nuvBranchDir, "olaris")) 46 if err != nil { 47 return "", err 48 } 49 debug("localDir", localDir) 50 51 // Updating existing tools 52 if exists(nuvBranchDir, "olaris") { 53 trace("Updating olaris in", nuvBranchDir) 54 fmt.Println("Updating tasks...") 55 r, err := git.PlainOpen(localDir) 56 if err != nil { 57 return "", err 58 } 59 // Get the working directory for the repository 60 w, err := r.Worktree() 61 if err != nil { 62 return "", err 63 } 64 65 // Pull the latest changes from the origin remote and merge into the current branch 66 // Clone the repo if not existing 67 ref := plumbing.NewBranchReferenceName(branch) 68 err = w.Pull(&git.PullOptions{ 69 RemoteName: "origin", 70 ReferenceName: ref, 71 SingleBranch: true, 72 }) 73 if err != nil { 74 if err.Error() == "already up-to-date" { 75 fmt.Println("Tasks are already up to date!") 76 return localDir, nil 77 } 78 return "", err 79 } 80 81 fmt.Println("Nuvfiles updated successfully") 82 touchLatestCheckFile(joinpath(nuvBranchDir, LATESTCHECK)) 83 return localDir, nil 84 } 85 86 // Clone the repo if not existing 87 ref := plumbing.NewBranchReferenceName(branch) 88 cloneOpts := &git.CloneOptions{ 89 URL: repoURL, 90 Progress: os.Stderr, 91 ReferenceName: ref, // Specify the branch to clone 92 } 93 94 fmt.Println("Cloning tasks...") 95 _, err = git.PlainClone(localDir, false, cloneOpts) 96 if err != nil { 97 os.RemoveAll(nuvBranchDir) 98 warn(fmt.Sprintf("failed to clone olaris on branch '%s'", branch)) 99 return "", err 100 } 101 102 fmt.Println("Nuvfiles downloaded successfully") 103 104 createLatestCheckFile(nuvBranchDir) 105 106 // clone 107 return localDir, nil 108 } 109 110 func pullTasks(force, silent bool) (string, error) { 111 // download from github 112 localDir, err := downloadTasksFromGitHub(force, silent) 113 debug("localDir", localDir) 114 if err != nil { 115 return "", err 116 } 117 118 // validate NuvVersion semver against nuvroot.json 119 nuvRoot, err := readNuvRootFile(localDir) 120 if err != nil { 121 return "", err 122 } 123 124 // check if the version is up to date 125 nuvVersion, err := semver.NewVersion(NuvVersion) 126 if err != nil { 127 // in development mode, we don't have a valid semver version 128 warn("Unable to validate nuv version", NuvVersion, ":", err) 129 return localDir, nil 130 } 131 132 nuvRootVersion, err := semver.NewVersion(nuvRoot.Version) 133 if err != nil { 134 warn("Unable to validate nuvroot.json version", nuvRoot.Version, ":", err) 135 return localDir, nil 136 } 137 138 // check if the version is up to date, if not warn the user 139 if nuvVersion.LessThan(nuvRootVersion) { 140 fmt.Println() 141 fmt.Printf("Your nuv version (%v) is older than the required version in nuvroot.json (%v).\n", nuvVersion, nuvRootVersion) 142 fmt.Println("Attempting to update nuv...") 143 if err := autoCLIUpdate(); err != nil { 144 return "", err 145 } 146 } 147 148 err = checkOperatorVersion(nuvRoot.Config) 149 if err == nil { 150 fmt.Println() 151 fmt.Println("New operator version detected!") 152 fmt.Println("Current deployed operator can be updated with: nuv update operator") 153 } 154 155 return localDir, nil 156 } 157 158 // locateNuvRoot locate the folder where starts execution 159 // it can be a parent folder of the current folder or it can be downloaded 160 // from github - it should contain a file nuvfile.yml and a file nuvtools.yml in the root 161 func locateNuvRoot(cur string) (string, error) { 162 cur, err := filepath.Abs(cur) 163 if err != nil { 164 return "", err 165 } 166 167 // search the root from here 168 search := locateNuvRootSearch(cur) 169 if search != "" { 170 trace("found searching up:", search) 171 return search, nil 172 } 173 174 // is there olaris folder? 175 olaris := joinpath(cur, "olaris") 176 if exists(cur, "olaris") && exists(olaris, NUVFILE) && exists(olaris, NUVROOT) { 177 trace("found sub olaris:", olaris) 178 return olaris, nil 179 } 180 181 // is there an olaris folder in ~/.nuv ? 182 nuvOlarisDir := fmt.Sprintf("~/.nuv/%s/olaris", getNuvBranch()) 183 olaris, err = homedir.Expand(nuvOlarisDir) 184 if err == nil && exists(olaris, NUVFILE) && exists(olaris, NUVROOT) { 185 trace("found sub", nuvOlarisDir, ":", olaris) 186 return olaris, nil 187 } 188 189 // is there an olaris folder in NUV_BIN? 190 nuvBin := os.Getenv("NUV_BIN") 191 if nuvBin != "" { 192 olaris = joinpath(nuvBin, "olaris") 193 if exists(olaris, NUVFILE) && exists(olaris, NUVROOT) { 194 trace("found sub NUV_BIN olaris:", olaris) 195 return olaris, nil 196 } 197 } 198 199 return "", fmt.Errorf("we cannot find nuvfiles, download them with nuv -update") 200 } 201 202 // locateNuvRootSearch search for `nuvfiles.yml` 203 // and goes up looking for a folder with also `nuvroot.json` 204 func locateNuvRootSearch(cur string) string { 205 debug("locateNuvRootSearch:", cur) 206 // exits nuvfile.yml? if not, go up until you find it 207 if !exists(cur, NUVFILE) { 208 return "" 209 } 210 if exists(cur, NUVROOT) { 211 return cur 212 } 213 parent := parent(cur) 214 if parent == "" { 215 return "" 216 } 217 return locateNuvRootSearch(parent) 218 } 219 220 func autoCLIUpdate() error { 221 trace("autoCLIUpdate") 222 cmd := exec.Command("nuv", "update", "cli") 223 cmd.Stdout = os.Stdout 224 cmd.Stderr = os.Stderr 225 return cmd.Run() 226 } 227 228 func checkOperatorVersion(nuvRootConfig map[string]interface{}) error { 229 trace("checkOperatorVersion") 230 images := nuvRootConfig["images"].(map[string]interface{}) 231 operator := images["operator"].(string) 232 opVer := strings.Split(operator, ":")[1] 233 234 cmd := exec.Command("nuv", "util", "check-operator-version", opVer) 235 return cmd.Run() 236 } 237 238 func setNuvOlarisHash(olarisDir string) error { 239 trace("setNuvOlarisHash", olarisDir) 240 r, err := git.PlainOpen(olarisDir) 241 if err != nil { 242 return err 243 } 244 h, err := r.Head() 245 if err != nil { 246 return err 247 } 248 debug("olaris hash", h.Hash().String()) 249 os.Setenv("NUV_OLARIS", h.Hash().String()) 250 trace("NUV_OLARIS", os.Getenv("NUV_OLARIS")) 251 return nil 252 }