prepare.go (182 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package openserverless import ( "fmt" "log" "os" "os/exec" "path/filepath" "strings" "github.com/Masterminds/semver" git "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/mitchellh/go-homedir" ) func downloadTasksFromGitHub(force bool, silent bool) (string, error) { debug("Download tasks from github") repoURL := getOpsRepo() branch := getOpsBranch() opsDir, err := homedir.Expand("~/.ops") if err != nil { return "", err } if err := os.MkdirAll(opsDir, 0755); err != nil { return "", err } opsBranchDir := joinpath(opsDir, branch) localDir, err := homedir.Expand(joinpath(opsBranchDir, "olaris")) if err != nil { return "", err } debug("localDir", localDir) // Updating existing tools if exists(opsBranchDir, "olaris") { trace("Updating olaris in", opsBranchDir) fmt.Println("Updating tasks...") r, err := git.PlainOpen(localDir) if err != nil { return "", err } // Get the working directory for the repository w, err := r.Worktree() if err != nil { return "", err } // Pull the latest changes from the origin remote and merge into the current branch // Clone the repo if not existing ref := plumbing.NewBranchReferenceName(branch) err = w.Pull(&git.PullOptions{ RemoteName: "origin", ReferenceName: ref, SingleBranch: true, }) if err != nil { if err.Error() == "already up-to-date" { fmt.Println("Tasks are already up to date!") return localDir, nil } return "", err } fmt.Println("Tasks updated successfully") touchLatestCheckFile(joinpath(opsBranchDir, LATESTCHECK)) return localDir, nil } // Clone the repo if not existing ref := plumbing.NewBranchReferenceName(branch) cloneOpts := &git.CloneOptions{ URL: repoURL, Progress: os.Stderr, ReferenceName: ref, // Specify the branch to clone } fmt.Println("Cloning tasks...") _, err = git.PlainClone(localDir, false, cloneOpts) if err != nil { os.RemoveAll(opsBranchDir) warn(fmt.Sprintf("failed to clone olaris on branch '%s'", branch)) return "", err } fmt.Println("Tasks downloaded successfully") createLatestCheckFile(opsBranchDir) // clone return localDir, nil } func pullTasks(force, silent bool) (string, error) { // download from github localDir, err := downloadTasksFromGitHub(force, silent) debug("localDir", localDir) if err != nil { return "", fmt.Errorf("cannot update tasks because: %s\nremove the folder ~/.ops and run ops -update", err.Error()) } err = ensurePrereq(localDir) if err != nil { log.Fatalf("cannot download prerequisites: %v", err) } // validate OpsVersion semver against opsroot.json opsRoot, err := readOpsRootFile(localDir) if err != nil { return "", err } // check if the version is up to date opsVersion, err := semver.NewVersion(OpsVersion) if err != nil { // in development mode, we don't have a valid semver version warn("Unable to validate ops version", OpsVersion, ":", err) return localDir, nil } opsRootVersion, err := semver.NewVersion(opsRoot.Version) if err != nil { warn("Unable to validate opsroot.json version", opsRoot.Version, ":", err) return localDir, nil } // check if the version is up to date, if not warn the user if opsVersion.LessThan(opsRootVersion) { fmt.Println() fmt.Printf("Your ops version (%v) is older than the required version (%v).\n", opsVersion, opsRootVersion) if err := autoCLIUpdate(); err != nil { return "", err } } err = checkOperatorVersion(opsRoot.Config) if err == nil { fmt.Println() fmt.Println("New operator version detected!") fmt.Println("Current deployed operator can be updated with: ops update operator") } return localDir, nil } // locateOpsRoot locate the folder where starts execution // it can be a parent folder of the current folder or it can be downloaded // from github - it should contain a file opsfile.yml and a file opstools.yml in the root func locateOpsRoot(cur string) (string, error) { cur, err := filepath.Abs(cur) if err != nil { return "", err } // search the root from here search := locateOpsRootSearch(cur) if search != "" { trace("found searching up:", search) return search, nil } // is there olaris folder? olaris := joinpath(cur, "olaris") if exists(cur, "olaris") && exists(olaris, OPSFILE) && exists(olaris, OPSROOT) { trace("found sub olaris:", olaris) return olaris, nil } // is there an olaris folder in ~/.ops ? opsOlarisDir := fmt.Sprintf("~/.ops/%s/olaris", getOpsBranch()) olaris, err = homedir.Expand(opsOlarisDir) if err == nil && exists(olaris, OPSFILE) && exists(olaris, OPSROOT) { trace("found sub", opsOlarisDir, ":", olaris) return olaris, nil } return "", fmt.Errorf("cannot find opsfiles, download them with ops -update") } // locateOpsRootSearch search for `opsfiles.yml` // and goes up looking for a folder with also `opsroot.json` func locateOpsRootSearch(cur string) string { debug("locateOpsRootSearch:", cur) // exits opsfile.yml? if not, go up until you find it if !exists(cur, OPSFILE) { return "" } if exists(cur, OPSROOT) { return cur } parent := parent(cur) if parent == "" { return "" } return locateOpsRootSearch(parent) } func autoCLIUpdate() error { cli := os.Getenv("OPS_CMD") trace("autoCLIUpdate", cli) cmd := exec.Command(cli, "util", "update-cli") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() } func checkOperatorVersion(opsRootConfig map[string]interface{}) error { trace("checkOperatorVersion") images := opsRootConfig["images"].(map[string]interface{}) operator := images["operator"].(string) opVer := strings.Split(operator, ":")[1] cmd := exec.Command(os.Getenv("OPS_CMD"), "util", "check-operator-version", opVer) return cmd.Run() } func setOpsOlarisHash(olarisDir string) error { trace("setOpsOlarisHash", olarisDir) r, err := git.PlainOpen(olarisDir) if err != nil { return err } h, err := r.Head() if err != nil { return err } debug("olaris hash", h.Hash().String()) os.Setenv("OPS_OLARIS", h.Hash().String()) trace("OPS_OLARIS", os.Getenv("OPS_OLARIS")) return nil }