prereq.go (195 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" "os" "os/exec" "path/filepath" "strings" "github.com/apache/openserverless-cli/tools" "github.com/mitchellh/go-homedir" "gopkg.in/yaml.v3" ) var PrereqSeenMap = map[string]string{} // execute prereq task func execPrereqTask(bindir string, name string) error { me, err := os.Executable() if err != nil { return err } args := []string{ "-task", "-d", bindir, "-t", PREREQ, name, } if taskDryRun { fmt.Printf("invoking prereq for %s\n", name) return nil } trace("Exec:", me, args) err = exec.Command(me, args...).Run() if err != nil { return err } return nil } // load prerequisites in current dir func loadPrereq(dir string) (tasks []string, versions []string, err error) { err = nil tasks = []string{} versions = []string{} if !exists(dir, PREREQ) { return } trace("found prereq.yml in ", dir) data, err := os.ReadFile(joinpath(dir, PREREQ)) if err != nil { return } /* You have tasks = []strings and versions = []strings and dat a string with a YAML in format: ```yaml something: tasks: task: vars: VERSION: "123" anothertask: ``` I want to parse the file, find the entries under `tasks` vith a var with VERSION and append, in order, to tasks the name of the task and to version the version found I have to skip the entries without a version and everyhing not in tasks I wnato just the plain code no procedures */ var root yaml.Node if err = yaml.Unmarshal([]byte(data), &root); err != nil { return } for i := 0; i < len(root.Content[0].Content); i += 2 { if root.Content[0].Content[i].Value == "tasks" { tasksNode := root.Content[0].Content[i+1] for j := 0; j < len(tasksNode.Content); j += 2 { taskName := tasksNode.Content[j].Value taskVars := tasksNode.Content[j+1] for k := 0; k < len(taskVars.Content); k += 2 { if taskVars.Content[k].Value == "vars" { varsNode := taskVars.Content[k+1] for l := 0; l < len(varsNode.Content); l += 2 { if varsNode.Content[l].Value == "VERSION" { version := varsNode.Content[l+1].Value tasks = append(tasks, taskName) versions = append(versions, version) } } } } } } } return } func binDir() (string, error) { var err error bindir := os.Getenv("OPS_BIN") if bindir == "" { bindir, err = homedir.Expand(fmt.Sprintf("~/.ops/%s-%s/bin", tools.GetOS(), tools.GetARCH())) if err != nil { return "", err } } os.Setenv("OPS_BIN", bindir) return bindir, nil } func addExeExt(name string) string { if tools.GetOS() == "windows" { return name + ".exe" } return name } // ensure there is a bindir for downloading prerequisites // read it from OPS_BIN and create it // otherwise setup one in ~/ops/<os>-<arch>/bin // and sets OPS_BIN func EnsureBindir() (string, error) { var err error = nil bindir, err := binDir() if err != nil { return "", err } err = os.MkdirAll(bindir, 0755) if err != nil { return "", err } trace("bindir", bindir) return bindir, nil } // create a mark of current version touching <name>-<version> and remove all the other files starting with <name>- func touchAndClean(dir string, name string, version string) error { // Walk through the directory err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // Check if the file starts with the prefix if !info.IsDir() && strings.HasPrefix(info.Name(), name+"-") { trace("Removing file:", path) err := os.Remove(path) if err != nil { return err } } return nil }) if err != nil { return err } err = touch(dir, name+"-"+version) if err != nil { return err } return nil } // download a prerequisite func downloadPrereq(name string, version string) error { // names and version // xname = executeable name // vname = versioned executable name xname := addExeExt(name) vname := xname + "-" + version // ensure bindir bindir, err := EnsureBindir() if err != nil { return err } // check if file and version exists trace("checking", vname, version) if exists(bindir, vname) { trace("already downloaded", vname) return nil } // checking different versions of the same file oldver, seen := PrereqSeenMap[name] if seen { if oldver == version { trace("same version again", vname) return nil } return fmt.Errorf("WARNING: %s prerequisite found twice with different versions!\nPrevious version: %s, ignoring %s", name, oldver, version) } PrereqSeenMap[name] = version if taskDryRun { fmt.Printf("downloading %s %s\n", name, version) touch(bindir, name) } else { fmt.Printf("ensuring prerequisite %s %s\n", name, version) execPrereqTask(bindir, name) // check if file and version exists if !exists(bindir, xname) { return fmt.Errorf("failed to download %s version %s", name, version) } // check if a file is zero length and remove in this case fileInfo, err := os.Stat(joinpath(bindir, xname)) if err != nil { return fmt.Errorf("failed to download %s version %s", name, version) } if fileInfo.Size() == 0 { trace("removing the empty file ", xname) err := os.Remove(joinpath(bindir, xname)) if err != nil { return fmt.Errorf("cannot remove empty %s ", xname) } } } return touchAndClean(bindir, xname, version) } // ensure prereq are satified looking at the prereq.yml func ensurePrereq(root string) error { // skip prereq - useful for tests if os.Getenv("OPS_NO_PREREQ") != "" { return nil } err := os.Chdir(root) if err != nil { return err } trace("ensurePrereq in", root) tasks, versions, err := loadPrereq(root) if err != nil { return err } trace(tasks, versions, err) for i, task := range tasks { version := versions[i] trace("prereq", task, version) err = downloadPrereq(task, version) if err != nil { fmt.Printf("error in prereq %s: %v\n", task, err) } } return nil }