| // 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("Opsfiles 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 "", err |
| } |
| |
| 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("we 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 |
| } |