http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/pkg/localpackage.go ---------------------------------------------------------------------- diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go deleted file mode 100644 index 3ce55e6..0000000 --- a/newt/pkg/localpackage.go +++ /dev/null @@ -1,463 +0,0 @@ -/** - * 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 pkg - -import ( - "bytes" - "crypto/sha1" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - - log "github.com/Sirupsen/logrus" - - "mynewt.apache.org/newt/newt/interfaces" - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/newt/repo" - "mynewt.apache.org/newt/util" - "mynewt.apache.org/newt/viper" - "mynewt.apache.org/newt/yaml" -) - -var PackageHashIgnoreDirs = map[string]bool{ - "obj": true, - "bin": true, - ".": true, -} - -var LocalPackageSpecialNames = map[string]bool{ - "src": true, - "include": true, - "bin": true, -} - -type LocalPackage struct { - repo *repo.Repo - name string - basePath string - packageType interfaces.PackageType - - // General information about the package - desc *PackageDesc - - // Package init function name and stage. These are used to generate the - // sysinit C file. - init map[string]int - - // Extra package-specific settings that don't come from syscfg. For - // example, SELFTEST gets set when the newt test command is used. - injectedSettings map[string]string - - // Settings read from pkg.yml. - PkgV *viper.Viper - - // Settings read from syscfg.yml. - SyscfgV *viper.Viper - - // Names of all source yml files; used to determine if rebuild required. - cfgFilenames []string -} - -func NewLocalPackage(r *repo.Repo, pkgDir string) *LocalPackage { - pkg := &LocalPackage{ - desc: &PackageDesc{}, - PkgV: viper.New(), - SyscfgV: viper.New(), - repo: r, - basePath: filepath.ToSlash(filepath.Clean(pkgDir)), - init: map[string]int{}, - injectedSettings: map[string]string{}, - } - return pkg -} - -func (pkg *LocalPackage) Name() string { - return pkg.name -} - -func (pkg *LocalPackage) FullName() string { - r := pkg.Repo() - if r.IsLocal() { - return pkg.Name() - } else { - return newtutil.BuildPackageString(r.Name(), pkg.Name()) - } -} - -func (pkg *LocalPackage) BasePath() string { - return pkg.basePath -} - -func (pkg *LocalPackage) RelativePath() string { - proj := interfaces.GetProject() - return strings.TrimPrefix(pkg.BasePath(), proj.Path()) -} - -func (pkg *LocalPackage) Type() interfaces.PackageType { - return pkg.packageType -} - -func (pkg *LocalPackage) Repo() interfaces.RepoInterface { - return pkg.repo -} - -func (pkg *LocalPackage) Desc() *PackageDesc { - return pkg.desc -} - -func (pkg *LocalPackage) SetName(name string) { - pkg.name = name - // XXX: Also set "pkg.name" in viper object (possibly just remove cached - // variable from code entirely). -} - -func (pkg *LocalPackage) SetBasePath(basePath string) { - pkg.basePath = filepath.ToSlash(filepath.Clean(basePath)) -} - -func (pkg *LocalPackage) SetType(packageType interfaces.PackageType) { - pkg.packageType = packageType - // XXX: Also set "pkg.type" in viper object (possibly just remove cached - // variable from code entirely). -} - -func (pkg *LocalPackage) SetDesc(desc *PackageDesc) { - pkg.desc = desc - // XXX: Also set desc fields in viper object (possibly just remove cached - // variable from code entirely). -} - -func (pkg *LocalPackage) SetRepo(r *repo.Repo) { - pkg.repo = r -} - -func (pkg *LocalPackage) Hash() (string, error) { - hash := sha1.New() - - err := filepath.Walk(pkg.basePath, - func(path string, info os.FileInfo, err error) error { - name := info.Name() - if PackageHashIgnoreDirs[name] { - return filepath.SkipDir - } - - if info.IsDir() { - // SHA the directory name into the hash - hash.Write([]byte(name)) - } else { - // SHA the file name & contents into the hash - contents, err := ioutil.ReadFile(path) - if err != nil { - return err - } - hash.Write(contents) - } - return nil - }) - if err != nil && err != filepath.SkipDir { - return "", util.NewNewtError(err.Error()) - } - - hashStr := fmt.Sprintf("%x", hash.Sum(nil)) - - return hashStr, nil -} - -func (pkg *LocalPackage) CfgFilenames() []string { - return pkg.cfgFilenames -} - -func (pkg *LocalPackage) AddCfgFilename(cfgFilename string) { - pkg.cfgFilenames = append(pkg.cfgFilenames, cfgFilename) -} - -func (pkg *LocalPackage) readDesc(v *viper.Viper) (*PackageDesc, error) { - pdesc := &PackageDesc{} - - pdesc.Author = v.GetString("pkg.author") - pdesc.Homepage = v.GetString("pkg.homepage") - pdesc.Description = v.GetString("pkg.description") - pdesc.Keywords = v.GetStringSlice("pkg.keywords") - - return pdesc, nil -} - -func (pkg *LocalPackage) sequenceString(key string) string { - var buffer bytes.Buffer - - if pkg.PkgV != nil { - for _, f := range pkg.PkgV.GetStringSlice(key) { - buffer.WriteString(" - " + yaml.EscapeString(f) + "\n") - } - } - - if buffer.Len() == 0 { - return "" - } else { - return key + ":\n" + buffer.String() - } -} - -func (lpkg *LocalPackage) SaveSyscfgVals() error { - dirpath := lpkg.BasePath() - if err := os.MkdirAll(dirpath, 0755); err != nil { - return util.NewNewtError(err.Error()) - } - - filepath := dirpath + "/" + SYSCFG_YAML_FILENAME - - syscfgVals := lpkg.SyscfgV.GetStringMapString("syscfg.vals") - if syscfgVals == nil || len(syscfgVals) == 0 { - os.Remove(filepath) - return nil - } - - file, err := os.Create(filepath) - if err != nil { - return util.NewNewtError(err.Error()) - } - defer file.Close() - - names := make([]string, 0, len(syscfgVals)) - for k, _ := range syscfgVals { - names = append(names, k) - } - sort.Strings(names) - - fmt.Fprintf(file, "### Package: %s\n", lpkg.Name()) - fmt.Fprintf(file, "\n") - fmt.Fprintf(file, "syscfg.vals:\n") - for _, name := range names { - fmt.Fprintf(file, " %s: %s\n", name, syscfgVals[name]) - } - - return nil -} - -// Saves the package's pkg.yml file. -// NOTE: This does not save every field in the package. Only the fields -// necessary for creating a new target get saved. -func (pkg *LocalPackage) Save() error { - dirpath := pkg.BasePath() - if err := os.MkdirAll(dirpath, 0755); err != nil { - return util.NewNewtError(err.Error()) - } - - filepath := dirpath + "/" + PACKAGE_FILE_NAME - file, err := os.Create(filepath) - if err != nil { - return util.NewNewtError(err.Error()) - } - defer file.Close() - - file.WriteString("### Package: " + pkg.Name() + "\n") - - // XXX: Just iterate viper object's settings rather than calling out - // cached settings individually. - file.WriteString("pkg.name: " + yaml.EscapeString(pkg.Name()) + "\n") - file.WriteString("pkg.type: " + - yaml.EscapeString(PackageTypeNames[pkg.Type()]) + "\n") - file.WriteString("pkg.description: " + - yaml.EscapeString(pkg.Desc().Description) + "\n") - file.WriteString("pkg.author: " + - yaml.EscapeString(pkg.Desc().Author) + "\n") - file.WriteString("pkg.homepage: " + - yaml.EscapeString(pkg.Desc().Homepage) + "\n") - - file.WriteString("\n") - - file.WriteString(pkg.sequenceString("pkg.aflags")) - file.WriteString(pkg.sequenceString("pkg.cflags")) - file.WriteString(pkg.sequenceString("pkg.lflags")) - - return nil -} - -// Load reads everything that isn't identity specific into the -// package -func (pkg *LocalPackage) Load() error { - // Load configuration - log.Debugf("Loading configuration for package %s", pkg.basePath) - - var err error - - pkg.PkgV, err = util.ReadConfig(pkg.basePath, - strings.TrimSuffix(PACKAGE_FILE_NAME, ".yml")) - if err != nil { - return err - } - pkg.AddCfgFilename(pkg.basePath + "/" + PACKAGE_FILE_NAME) - - // Set package name from the package - pkg.name = pkg.PkgV.GetString("pkg.name") - - typeString := pkg.PkgV.GetString("pkg.type") - pkg.packageType = PACKAGE_TYPE_LIB - for t, n := range PackageTypeNames { - if typeString == n { - pkg.packageType = t - break - } - } - - init := pkg.PkgV.GetStringMapString("pkg.init") - for name, stageStr := range init { - stage, err := strconv.ParseInt(stageStr, 10, 64) - if err != nil { - return util.NewNewtError(fmt.Sprintf("Parsing pkg %s config: %s", - pkg.FullName(), err.Error())) - } - pkg.init[name] = int(stage) - } - initFnName := pkg.PkgV.GetString("pkg.init_function") - initStage := pkg.PkgV.GetInt("pkg.init_stage") - - if initFnName != "" { - pkg.init[initFnName] = initStage - } - - // Read the package description from the file - pkg.desc, err = pkg.readDesc(pkg.PkgV) - if err != nil { - return err - } - - // Load syscfg settings. - if util.NodeExist(pkg.basePath + "/" + SYSCFG_YAML_FILENAME) { - pkg.SyscfgV, err = util.ReadConfig(pkg.basePath, - strings.TrimSuffix(SYSCFG_YAML_FILENAME, ".yml")) - if err != nil { - return err - } - pkg.AddCfgFilename(pkg.basePath + "/" + SYSCFG_YAML_FILENAME) - } - - return nil -} - -func (pkg *LocalPackage) Init() map[string]int { - return pkg.init -} - -func (pkg *LocalPackage) InjectedSettings() map[string]string { - return pkg.injectedSettings -} - -func (pkg *LocalPackage) Clone(newRepo *repo.Repo, - newName string) *LocalPackage { - - // XXX: Validate name. - - // Copy the package. - newPkg := *pkg - newPkg.repo = newRepo - newPkg.name = newName - newPkg.basePath = newRepo.Path() + "/" + newPkg.name - - // Insert the clone into the global package map. - proj := interfaces.GetProject() - pMap := proj.PackageList() - - (*pMap[newRepo.Name()])[newPkg.name] = &newPkg - - return &newPkg -} - -func LoadLocalPackage(repo *repo.Repo, pkgDir string) (*LocalPackage, error) { - pkg := NewLocalPackage(repo, pkgDir) - err := pkg.Load() - return pkg, err -} - -func LocalPackageSpecialName(dirName string) bool { - _, ok := LocalPackageSpecialNames[dirName] - return ok -} - -func ReadLocalPackageRecursive(repo *repo.Repo, - pkgList map[string]interfaces.PackageInterface, basePath string, - pkgName string, searchedMap map[string]struct{}) ([]string, error) { - - var warnings []string - - dirList, err := repo.FilteredSearchList(pkgName, searchedMap) - if err != nil { - return warnings, util.NewNewtError(err.Error()) - } - - for _, name := range dirList { - if LocalPackageSpecialName(name) || strings.HasPrefix(name, ".") { - continue - } - - subWarnings, err := ReadLocalPackageRecursive(repo, pkgList, - basePath, filepath.Join(pkgName, name), searchedMap) - warnings = append(warnings, subWarnings...) - if err != nil { - return warnings, err - } - } - - if util.NodeNotExist(filepath.Join(basePath, pkgName, - PACKAGE_FILE_NAME)) { - - return warnings, nil - } - - pkg, err := LoadLocalPackage(repo, filepath.Join(basePath, pkgName)) - if err != nil { - warnings = append(warnings, err.Error()) - return warnings, nil - } - - if oldPkg, ok := pkgList[pkg.Name()]; ok { - oldlPkg := oldPkg.(*LocalPackage) - warnings = append(warnings, - fmt.Sprintf("Multiple packages with same pkg.name=%s "+ - "in repo %s; path1=%s path2=%s", oldlPkg.Name(), repo.Name(), - oldlPkg.BasePath(), pkg.BasePath())) - - return warnings, nil - } - - pkgList[pkg.Name()] = pkg - - return warnings, nil -} - -func ReadLocalPackages(repo *repo.Repo, basePath string) ( - *map[string]interfaces.PackageInterface, []string, error) { - - pkgMap := &map[string]interfaces.PackageInterface{} - - // Keep track of which directories we have traversed. Prevent infinite - // loops caused by symlink cycles by not inspecting the same directory - // twice. - searchedMap := map[string]struct{}{} - - warnings, err := ReadLocalPackageRecursive(repo, *pkgMap, - basePath, "", searchedMap) - - return pkgMap, warnings, err -}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/pkg/package.go ---------------------------------------------------------------------- diff --git a/newt/pkg/package.go b/newt/pkg/package.go deleted file mode 100644 index 58bf523..0000000 --- a/newt/pkg/package.go +++ /dev/null @@ -1,94 +0,0 @@ -/** -* 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 pkg - -import "mynewt.apache.org/newt/newt/interfaces" - -const PACKAGE_FILE_NAME = "pkg.yml" -const SYSCFG_YAML_FILENAME = "syscfg.yml" - -const ( - PACKAGE_STABILITY_STABLE = "stable" - PACKAGE_STABILITY_LATEST = "latest" - PACKAGE_STABILITY_DEV = "dev" -) - -// Define constants with values of increasing priority. -const ( - PACKAGE_TYPE_COMPILER interfaces.PackageType = iota - PACKAGE_TYPE_MFG - PACKAGE_TYPE_SDK - PACKAGE_TYPE_GENERATED - PACKAGE_TYPE_LIB - PACKAGE_TYPE_BSP - PACKAGE_TYPE_UNITTEST - PACKAGE_TYPE_APP - PACKAGE_TYPE_TARGET -) - -var PackageTypeNames = map[interfaces.PackageType]string{ - PACKAGE_TYPE_COMPILER: "compiler", - PACKAGE_TYPE_MFG: "mfg", - PACKAGE_TYPE_SDK: "sdk", - PACKAGE_TYPE_GENERATED: "generated", - PACKAGE_TYPE_LIB: "lib", - PACKAGE_TYPE_BSP: "bsp", - PACKAGE_TYPE_UNITTEST: "unittest", - PACKAGE_TYPE_APP: "app", - PACKAGE_TYPE_TARGET: "target", -} - -// An interface, representing information about a Package -// This interface is implemented by both packages in the -// local directory, but also packages that are stored in -// remote repositories. It is abstracted so that routines -// that do package search & installation can work across -// both local & remote packages without needing to special -// case. -type Package interface { - // The repository this package belongs to - Repo() interfaces.RepoInterface - // The name of this package - Name() string - // The full name of this package, including repo - FullName() string - // The type of package (lib, target, bsp, etc.) - Type() interfaces.PackageType - // BasePath is the path on disk if it's a local package - BasePath() string - // Hash of the contents of the package - Hash() (string, error) - // Description of this package - Desc() *PackageDesc - // APIs exported by this package - Apis() []string - // APIs required by this package - ReqApis() []string -} - -// Description of a package -type PackageDesc struct { - // Author of the package - Author string - // Homepage of the package for more information - Homepage string - Description string - Keywords []string -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/pkg/packageutil.go ---------------------------------------------------------------------- diff --git a/newt/pkg/packageutil.go b/newt/pkg/packageutil.go deleted file mode 100644 index 27b463c..0000000 --- a/newt/pkg/packageutil.go +++ /dev/null @@ -1,58 +0,0 @@ -/** -* 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 pkg - -import ( - "path/filepath" - "sort" - - "mynewt.apache.org/newt/newt/interfaces" -) - -type lpkgSorter struct { - pkgs []*LocalPackage -} - -func (s lpkgSorter) Len() int { - return len(s.pkgs) -} -func (s lpkgSorter) Swap(i, j int) { - s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i] -} -func (s lpkgSorter) Less(i, j int) bool { - return s.pkgs[i].FullName() < s.pkgs[j].FullName() -} - -func SortLclPkgs(pkgs []*LocalPackage) []*LocalPackage { - sorter := lpkgSorter{ - pkgs: make([]*LocalPackage, 0, len(pkgs)), - } - - for _, p := range pkgs { - sorter.pkgs = append(sorter.pkgs, p) - } - - sort.Sort(sorter) - return sorter.pkgs -} - -func ShortName(p interfaces.PackageInterface) string { - return filepath.Base(p.Name()) -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/project/pkgwriter.go ---------------------------------------------------------------------- diff --git a/newt/project/pkgwriter.go b/newt/project/pkgwriter.go deleted file mode 100644 index 6e39245..0000000 --- a/newt/project/pkgwriter.go +++ /dev/null @@ -1,174 +0,0 @@ -/** - * 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 project - -import ( - "fmt" - "io/ioutil" - "os" - "path" - "regexp" - "strings" - - "mynewt.apache.org/newt/newt/downloader" - "mynewt.apache.org/newt/util" -) - -type PackageWriter struct { - downloader *downloader.GithubDownloader - repo string - targetPath string - template string - fullName string - project *Project -} - -var TemplateRepoMap = map[string]string{ - "SDK": "incubator-incubator-mynewt-pkg-sdk", - "BSP": "incubator-incubator-mynewt-pkg-bsp", - "PKG": "incubator-incubator-mynewt-pkg-pkg", -} - -const PACKAGEWRITER_GITHUB_DOWNLOAD_USER = "apache" -const PACKAGEWRITER_GITHUB_DOWNLOAD_BRANCH = "master" - -func (pw *PackageWriter) ConfigurePackage(template string, loc string) error { - str, ok := TemplateRepoMap[template] - if !ok { - return util.NewNewtError(fmt.Sprintf("Cannot find matching "+ - "repository for template %s", template)) - } - pw.repo = str - - pw.fullName = path.Clean(loc) - path := pw.project.Path() - path = path + "/" + pw.fullName - - if util.NodeExist(path) { - return util.NewNewtError(fmt.Sprintf("Cannot place a new package in "+ - "%s, path already exists.", path)) - } - - pw.template = template - pw.targetPath = path - - return nil -} - -func (pw *PackageWriter) cleanupPackageFile(pfile string) error { - f, err := os.Open(pfile) - if err != nil { - return util.ChildNewtError(err) - } - defer f.Close() - - data, _ := ioutil.ReadAll(f) - - // Search & replace file contents - re := regexp.MustCompile("your-pkg-name") - res := re.ReplaceAllString(string(data), pw.fullName) - - if err := ioutil.WriteFile(pfile, []byte(res), 0666); err != nil { - return util.ChildNewtError(err) - } - - return nil -} - -func (pw *PackageWriter) fixupPKG() error { - pkgBase := path.Base(pw.fullName) - - // Move include file to name after package name - if err := util.MoveFile(pw.targetPath+"/include/your-path/your-file.h", - pw.targetPath+"/include/your-path/"+pkgBase+".h"); err != nil { - return err - } - - // Move source file - if err := util.MoveFile(pw.targetPath+"/src/your-source.c", - pw.targetPath+"/src/"+pkgBase+".c"); err != nil { - return err - } - - if err := util.CopyDir(pw.targetPath+"/include/your-path/", - pw.targetPath+"/include/"+pkgBase+"/"); err != nil { - return err - } - - if err := os.RemoveAll(pw.targetPath + "/include/your-path/"); err != nil { - return util.ChildNewtError(err) - } - - if err := pw.cleanupPackageFile(pw.targetPath + "/pkg.yml"); err != nil { - return err - } - - return nil -} - -func (pw *PackageWriter) WritePackage() error { - dl := pw.downloader - - dl.User = PACKAGEWRITER_GITHUB_DOWNLOAD_USER - dl.Repo = pw.repo - - util.StatusMessage(util.VERBOSITY_DEFAULT, - "Download package template for package type %s.\n", - strings.ToLower(pw.template)) - - tmpdir, err := dl.DownloadRepo(PACKAGEWRITER_GITHUB_DOWNLOAD_BRANCH) - if err != nil { - return err - } - - if err := os.RemoveAll(tmpdir + "/.git/"); err != nil { - return util.NewNewtError(err.Error()) - } - - if err := util.CopyDir(tmpdir, pw.targetPath); err != nil { - return err - } - - switch pw.template { - case "PKG": - if err := pw.fixupPKG(); err != nil { - return err - } - } - - util.StatusMessage(util.VERBOSITY_DEFAULT, - "Package successfuly installed into %s.\n", pw.targetPath) - - return nil -} - -/** - * Create new PackageWriter structure, and return it - */ -func NewPackageWriter() *PackageWriter { - proj := GetProject() - - pw := &PackageWriter{ - project: proj, - downloader: downloader.NewGithubDownloader(), - } - - return pw -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/project/project.go ---------------------------------------------------------------------- diff --git a/newt/project/project.go b/newt/project/project.go deleted file mode 100644 index 75b0b31..0000000 --- a/newt/project/project.go +++ /dev/null @@ -1,719 +0,0 @@ -/** - * 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 project - -import ( - "bufio" - "fmt" - "os" - "path" - "path/filepath" - "strings" - - log "github.com/Sirupsen/logrus" - - "mynewt.apache.org/newt/newt/compat" - "mynewt.apache.org/newt/newt/downloader" - "mynewt.apache.org/newt/newt/interfaces" - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/newt/pkg" - "mynewt.apache.org/newt/newt/repo" - "mynewt.apache.org/newt/util" - "mynewt.apache.org/newt/viper" -) - -var globalProject *Project = nil - -const PROJECT_FILE_NAME = "project.yml" - -var ignoreSearchDirs []string = []string{ - "bin", - "repos", -} - -type Project struct { - // Name of this project - name string - - // Base path of the project - BasePath string - - packages interfaces.PackageList - - projState *ProjectState - - // Repositories configured on this project - repos map[string]*repo.Repo - warnings []string - - localRepo *repo.Repo - - v *viper.Viper -} - -func initProject(dir string) error { - var err error - - globalProject, err = LoadProject(dir) - if err != nil { - return err - } - if err := globalProject.loadPackageList(); err != nil { - return err - } - - return nil -} - -func initialize() error { - if globalProject == nil { - wd, err := os.Getwd() - if err != nil { - return util.NewNewtError(err.Error()) - } - if err := initProject(wd); err != nil { - return err - } - } - return nil -} - -func TryGetProject() (*Project, error) { - if err := initialize(); err != nil { - return nil, err - } - return globalProject, nil -} - -func GetProject() *Project { - if _, err := TryGetProject(); err != nil { - panic(err.Error()) - } - - return globalProject -} - -func ResetProject() { - globalProject = nil -} - -func ResetDeps(newList interfaces.PackageList) interfaces.PackageList { - return nil - if globalProject == nil { - return nil - } - oldList := globalProject.packages - globalProject.packages = newList - - if newList == nil { - globalProject.loadPackageList() - } - return oldList -} - -func NewProject(dir string) (*Project, error) { - proj := &Project{} - - if err := proj.Init(dir); err != nil { - return nil, err - } - - return proj, nil -} - -func (proj *Project) Path() string { - return proj.BasePath -} - -func (proj *Project) Name() string { - return proj.name -} - -func (proj *Project) Repos() map[string]*repo.Repo { - return proj.repos -} - -func (proj *Project) FindRepo(rname string) *repo.Repo { - if rname == repo.REPO_NAME_LOCAL { - return proj.LocalRepo() - } else { - r, _ := proj.repos[rname] - return r - } -} - -func (proj *Project) FindRepoPath(rname string) string { - r := proj.FindRepo(rname) - if r == nil { - return "" - } - - return r.Path() -} - -func (proj *Project) LocalRepo() *repo.Repo { - return proj.localRepo -} - -func (proj *Project) Warnings() []string { - return proj.warnings -} - -func (proj *Project) upgradeCheck(r *repo.Repo, vers *repo.Version, - force bool) (bool, error) { - rdesc, err := r.GetRepoDesc() - if err != nil { - return false, err - } - - branch, newVers, _ := rdesc.Match(r) - if newVers == nil { - util.StatusMessage(util.VERBOSITY_DEFAULT, - "No matching version to upgrade to "+ - "found for %s. Please check your project requirements.", - r.Name()) - return false, util.NewNewtError(fmt.Sprintf("Cannot find a "+ - "version of repository %s that matches project requirements.", - r.Name())) - } - - // If the change between the old repository and the new repository would cause - // and upgrade. Then prompt for an upgrade response, unless the force option - // is present. - if vers.CompareVersions(newVers, vers) != 0 || - vers.Stability() != newVers.Stability() { - if !force { - str := "" - if newVers.Stability() != repo.VERSION_STABILITY_NONE { - str += "(" + branch + ")" - } - - fmt.Printf("Would you like to upgrade repository %s from %s to %s %s? [Yn] ", - r.Name(), vers.String(), newVers.String(), str) - line, more, err := bufio.NewReader(os.Stdin).ReadLine() - if more || err != nil { - return false, util.NewNewtError(fmt.Sprintf( - "Couldn't read upgrade response: %s\n", err.Error())) - } - - // Anything but no means yes. - answer := strings.ToUpper(strings.Trim(string(line), " ")) - if answer == "N" || answer == "NO" { - fmt.Printf("User says don't upgrade, skipping upgrade of %s\n", - r.Name()) - return true, nil - } - } - } else { - util.StatusMessage(util.VERBOSITY_VERBOSE, - "Repository %s doesn't need to be upgraded, latest "+ - "version installed.\n", r.Name()) - return true, nil - } - - return false, nil -} - -func (proj *Project) checkVersionRequirements(r *repo.Repo, upgrade bool, force bool) (bool, error) { - rdesc, err := r.GetRepoDesc() - if err != nil { - return false, err - } - - rname := r.Name() - - vers := proj.projState.GetInstalledVersion(rname) - if vers != nil { - ok := rdesc.SatisfiesVersion(vers, r.VersionRequirements()) - if !ok && !upgrade { - util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: Installed "+ - "version %s of repository %s does not match desired "+ - "version %s in project file. You can fix this by either upgrading"+ - " your repository, or modifying the project.yml file.\n", - vers, rname, r.VersionRequirementsString()) - return true, err - } else { - if !upgrade { - util.StatusMessage(util.VERBOSITY_VERBOSE, "%s correct version already installed\n", r.Name()) - return true, nil - } else { - skip, err := proj.upgradeCheck(r, vers, force) - return skip, err - } - } - } else { - // Fallthrough and perform the installation. - // Check to make sure that this repository contains a version - // that can satisfy. - _, _, ok := rdesc.Match(r) - if !ok { - fmt.Printf("WARNING: No matching repository version found for repository "+ - "%s specified in project.\n", r.Name()) - return true, err - } - } - - return false, nil -} - -func (proj *Project) checkDeps(r *repo.Repo) error { - repos, updated, err := r.UpdateDesc() - if err != nil { - return err - } - - if !updated { - return nil - } - - for _, newRepo := range repos { - curRepo, ok := proj.repos[newRepo.Name()] - if !ok { - proj.repos[newRepo.Name()] = newRepo - return proj.UpdateRepos() - } else { - // Add any dependencies we might have found here. - for _, dep := range newRepo.Deps() { - newRepo.DownloadDesc() - newRepo.ReadDesc() - curRepo.AddDependency(dep) - } - } - } - - return nil -} - -func (proj *Project) UpdateRepos() error { - repoList := proj.Repos() - for _, r := range repoList { - if r.IsLocal() { - continue - } - - err := proj.checkDeps(r) - if err != nil { - return err - } - } - return nil -} - -func (proj *Project) Install(upgrade bool, force bool) error { - repoList := proj.Repos() - - for rname, _ := range repoList { - // Ignore the local repo on install - if rname == repo.REPO_NAME_LOCAL { - continue - } - - // First thing we do is update repository description. This - // will get us available branches and versions in the repository. - if err := proj.UpdateRepos(); err != nil { - return err - } - } - - // Get repository list, and print every repo and it's dependencies. - if err := repo.CheckDeps(upgrade, proj.Repos()); err != nil { - return err - } - - for rname, r := range proj.Repos() { - if r.IsLocal() { - continue - } - // Check the version requirements on this repository, and see - // whether or not we need to install/upgrade it. - skip, err := proj.checkVersionRequirements(r, upgrade, force) - if err != nil { - return err - } - if skip { - continue - } - - // Do the hard work of actually copying and installing the repository. - rvers, err := r.Install(upgrade || force) - if err != nil { - return err - } - - if upgrade { - util.StatusMessage(util.VERBOSITY_VERBOSE, "%s successfully upgraded to version %s\n", - r.Name(), rvers.String()) - } else { - util.StatusMessage(util.VERBOSITY_VERBOSE, "%s successfully installed version %s\n", - r.Name(), rvers.String()) - } - - // Update the project state with the new repository version information. - proj.projState.Replace(rname, rvers) - } - - // Save the project state, including any updates or changes to the project - // information that either install or upgrade caused. - if err := proj.projState.Save(); err != nil { - return err - } - - return nil -} - -func (proj *Project) Upgrade(force bool) error { - return proj.Install(true, force) -} - -func (proj *Project) loadRepo(rname string, v *viper.Viper) error { - varName := fmt.Sprintf("repository.%s", rname) - - repoVars := v.GetStringMapString(varName) - if len(repoVars) == 0 { - return util.NewNewtError(fmt.Sprintf("Missing configuration for "+ - "repository %s.", rname)) - } - if repoVars["type"] == "" { - return util.NewNewtError(fmt.Sprintf("Missing type for repository " + - rname)) - } - - dl, err := downloader.LoadDownloader(rname, repoVars) - if err != nil { - return err - } - - rversreq := repoVars["vers"] - r, err := repo.NewRepo(rname, rversreq, dl) - if err != nil { - return err - } - - for _, ignDir := range ignoreSearchDirs { - r.AddIgnoreDir(ignDir) - } - - rd, err := repo.NewRepoDependency(rname, rversreq) - if err != nil { - return err - } - rd.Storerepo = r - - proj.localRepo.AddDependency(rd) - - // Read the repo's descriptor file so that we have its newt version - // compatibility map. - r.ReadDesc() - - rvers := proj.projState.GetInstalledVersion(rname) - code, msg := r.CheckNewtCompatibility(rvers, newtutil.NewtVersion) - switch code { - case compat.NEWT_COMPAT_GOOD: - case compat.NEWT_COMPAT_WARN: - util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: %s.\n", msg) - case compat.NEWT_COMPAT_ERROR: - return util.NewNewtError(msg) - } - - log.Debugf("Loaded repository %s (type: %s, user: %s, repo: %s)", rname, - repoVars["type"], repoVars["user"], repoVars["repo"]) - - proj.repos[r.Name()] = r - return nil -} - -func (proj *Project) checkNewtVer() error { - compatSms := proj.v.GetStringMapString("project.newt_compatibility") - // If this project doesn't have a newt compatibility map, just assume there - // is no incompatibility. - if len(compatSms) == 0 { - return nil - } - - tbl, err := compat.ParseNcTable(compatSms) - if err != nil { - return util.FmtNewtError("Error reading project.yml: %s", err.Error()) - } - - code, msg := tbl.CheckNewtVer(newtutil.NewtVersion) - msg = fmt.Sprintf("This version of newt (%s) is incompatible with "+ - "your project; %s", newtutil.NewtVersion.String(), msg) - - switch code { - case compat.NEWT_COMPAT_GOOD: - return nil - case compat.NEWT_COMPAT_WARN: - util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: %s.\n", msg) - return nil - case compat.NEWT_COMPAT_ERROR: - return util.NewNewtError(msg) - default: - return nil - } -} - -func (proj *Project) loadConfig() error { - v, err := util.ReadConfig(proj.BasePath, - strings.TrimSuffix(PROJECT_FILE_NAME, ".yml")) - if err != nil { - return util.NewNewtError(err.Error()) - } - // Store configuration object for access to future values, - // this avoids keeping every string around as a project variable when - // we need to process it later. - proj.v = v - - proj.projState, err = LoadProjectState() - if err != nil { - return err - } - - proj.name = v.GetString("project.name") - - // Local repository always included in initialization - r, err := repo.NewLocalRepo(proj.name) - if err != nil { - return err - } - - proj.repos[proj.name] = r - proj.localRepo = r - for _, ignDir := range ignoreSearchDirs { - r.AddIgnoreDir(ignDir) - } - - rstrs := v.GetStringSlice("project.repositories") - for _, repoName := range rstrs { - if err := proj.loadRepo(repoName, v); err != nil { - return err - } - } - - ignoreDirs := v.GetStringSlice("project.ignore_dirs") - for _, ignDir := range ignoreDirs { - repoName, dirName, err := newtutil.ParsePackageString(ignDir) - if err != nil { - return err - } - if repoName == "" { - r = proj.LocalRepo() - } else { - r = proj.FindRepo(repoName) - } - if r == nil { - return util.NewNewtError( - fmt.Sprintf("ignore_dirs: unknown repo %s", repoName)) - } - r.AddIgnoreDir(dirName) - } - - if err := proj.checkNewtVer(); err != nil { - return err - } - - return nil -} - -func (proj *Project) Init(dir string) error { - proj.BasePath = filepath.ToSlash(filepath.Clean(dir)) - - // Only one project per system, when created, set it as the global project - interfaces.SetProject(proj) - - proj.repos = map[string]*repo.Repo{} - - // Load Project configuration - if err := proj.loadConfig(); err != nil { - return err - } - - return nil -} - -func matchNamePath(name, path string) bool { - // assure that name and path use the same path separator... - names := filepath.SplitList(name) - name = filepath.Join(names...) - - if strings.HasSuffix(path, name) { - return true - } - return false -} - -func (proj *Project) ResolveDependency(dep interfaces.DependencyInterface) interfaces.PackageInterface { - type NamePath struct { - name string - path string - } - - var errorPkgs []NamePath - for _, pkgList := range proj.packages { - for _, pkg := range *pkgList { - name := pkg.Name() - path := pkg.BasePath() - if !matchNamePath(name, path) { - errorPkgs = append(errorPkgs, NamePath{name: name, path: path}) - } - if dep.SatisfiesDependency(pkg) { - return pkg - } - } - } - - for _, namepath := range errorPkgs { - util.StatusMessage(util.VERBOSITY_VERBOSE, - "Package name \"%s\" doesn't match path \"%s\"\n", namepath.name, namepath.path) - } - - return nil -} - -func (proj *Project) ResolvePackage( - dfltRepo interfaces.RepoInterface, name string) (*pkg.LocalPackage, error) { - // Trim trailing slash from name. This is necessary when tab - // completion is used to specify the name. - name = strings.TrimSuffix(name, "/") - - repoName, pkgName, err := newtutil.ParsePackageString(name) - if err != nil { - return nil, util.FmtNewtError("invalid package name: %s (%s)", name, - err.Error()) - } - - var repo interfaces.RepoInterface - if repoName == "" { - repo = dfltRepo - } else { - repo = proj.repos[repoName] - } - - dep, err := pkg.NewDependency(repo, pkgName) - if err != nil { - return nil, util.FmtNewtError("invalid package name: %s (%s)", name, - err.Error()) - } - if dep == nil { - return nil, util.NewNewtError("invalid package name: " + name) - } - pack := proj.ResolveDependency(dep) - if pack == nil { - return nil, util.NewNewtError("unknown package: " + name) - } - - return pack.(*pkg.LocalPackage), nil -} - -// Resolves a path with an optional repo prefix (e.g., "@apache-mynewt-core"). -func (proj *Project) ResolvePath( - basePath string, name string) (string, error) { - - repoName, subPath, err := newtutil.ParsePackageString(name) - if err != nil { - return "", util.FmtNewtError("invalid path: %s (%s)", name, - err.Error()) - } - - if repoName == "" { - return basePath + "/" + subPath, nil - } else { - repo := proj.repos[repoName] - if repo == nil { - return "", util.FmtNewtError("Unknown repository: %s", repoName) - } - - return repo.Path() + "/" + subPath, nil - } -} - -func findProjectDir(dir string) (string, error) { - for { - projFile := path.Clean(dir) + "/" + PROJECT_FILE_NAME - - log.Debugf("Searching for project file %s", projFile) - if util.NodeExist(projFile) { - break - } - - // Move back one directory and continue searching - dir = path.Clean(dir + "../../") - if dir == "/" { - return "", util.NewNewtError("No project file found!") - } - } - - return dir, nil -} - -func (proj *Project) loadPackageList() error { - proj.packages = interfaces.PackageList{} - - // Go through a list of repositories, starting with local, and search for - // packages / store them in the project package list. - repos := proj.Repos() - for name, repo := range repos { - list, warnings, err := pkg.ReadLocalPackages(repo, repo.Path()) - if err != nil { - /* Failed to read the repo's package list. Report the failure as a - * warning if the project state indicates that this repo should be - * installed. - */ - if proj.projState.installedRepos[name] != nil { - util.StatusMessage(util.VERBOSITY_QUIET, err.Error()+"\n") - } - } else { - proj.packages[name] = list - } - - proj.warnings = append(proj.warnings, warnings...) - } - - return nil -} - -func (proj *Project) PackageList() interfaces.PackageList { - return proj.packages -} - -func (proj *Project) PackagesOfType(pkgType interfaces.PackageType) []interfaces.PackageInterface { - matches := []interfaces.PackageInterface{} - - packs := proj.PackageList() - for _, packHash := range packs { - for _, pack := range *packHash { - if pkgType == -1 || pack.Type() == pkgType { - matches = append(matches, pack) - } - } - } - - return matches -} - -func LoadProject(dir string) (*Project, error) { - projDir, err := findProjectDir(dir) - if err != nil { - return nil, err - } - - proj, err := NewProject(projDir) - - return proj, err -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/project/projectstate.go ---------------------------------------------------------------------- diff --git a/newt/project/projectstate.go b/newt/project/projectstate.go deleted file mode 100644 index 2c14359..0000000 --- a/newt/project/projectstate.go +++ /dev/null @@ -1,109 +0,0 @@ -/** - * 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 project - -import ( - "bufio" - "fmt" - "os" - "strings" - - "mynewt.apache.org/newt/newt/interfaces" - "mynewt.apache.org/newt/newt/repo" - "mynewt.apache.org/newt/util" -) - -const PROJECT_STATE_FILE = "project.state" - -type ProjectState struct { - installedRepos map[string]*repo.Version -} - -func (ps *ProjectState) GetInstalledVersion(rname string) *repo.Version { - v, _ := ps.installedRepos[rname] - return v -} - -func (ps *ProjectState) Replace(rname string, rvers *repo.Version) { - ps.installedRepos[rname] = rvers -} - -func (ps *ProjectState) StateFile() string { - return interfaces.GetProject().Path() + "/" + PROJECT_STATE_FILE -} - -func (ps *ProjectState) Save() error { - file, err := os.Create(ps.StateFile()) - if err != nil { - return util.NewNewtError(err.Error()) - } - defer file.Close() - - for k, v := range ps.installedRepos { - str := fmt.Sprintf("%s,%d.%d.%d\n", k, v.Major(), v.Minor(), v.Revision()) - file.WriteString(str) - } - - return nil -} - -func (ps *ProjectState) Init() error { - ps.installedRepos = map[string]*repo.Version{} - - path := ps.StateFile() - - // Read project state file. If doesn't exist, it will be empty until somebody - // installs a repo - if util.NodeNotExist(path) { - return nil - } - - file, err := os.Open(path) - if err != nil { - return err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - line := strings.Split(scanner.Text(), ",") - if len(line) != 2 { - return util.NewNewtError(fmt.Sprintf( - "Invalid format for line in project.state file: %s\n", line)) - } - - repoName := line[0] - repoVers, err := repo.LoadVersion(line[1]) - if err != nil { - return err - } - - ps.installedRepos[repoName] = repoVers - } - return nil -} - -func LoadProjectState() (*ProjectState, error) { - ps := &ProjectState{} - if err := ps.Init(); err != nil { - return nil, err - } - return ps, nil -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/repo/repo.go ---------------------------------------------------------------------- diff --git a/newt/repo/repo.go b/newt/repo/repo.go deleted file mode 100644 index e058466..0000000 --- a/newt/repo/repo.go +++ /dev/null @@ -1,757 +0,0 @@ -/** - * 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 repo - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" - - log "github.com/Sirupsen/logrus" - "github.com/spf13/cast" - - "mynewt.apache.org/newt/newt/compat" - "mynewt.apache.org/newt/newt/downloader" - "mynewt.apache.org/newt/newt/interfaces" - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/util" - "mynewt.apache.org/newt/viper" -) - -const REPO_NAME_LOCAL = "local" -const REPO_DEFAULT_PERMS = 0755 - -const REPO_FILE_NAME = "repository.yml" -const REPOS_DIR = "repos" - -type Repo struct { - name string - downloader downloader.Downloader - localPath string - versreq []interfaces.VersionReqInterface - rdesc *RepoDesc - deps []*RepoDependency - ignDirs []string - updated bool - local bool - ncMap compat.NewtCompatMap -} - -type RepoDesc struct { - name string - vers map[*Version]string -} - -type RepoDependency struct { - versreq []interfaces.VersionReqInterface - name string - Storerepo *Repo -} - -func (r *Repo) Deps() []*RepoDependency { - return r.deps -} - -func (r *Repo) AddDependency(rd *RepoDependency) { - r.deps = append(r.deps, rd) -} - -func (rd *RepoDependency) Name() string { - return rd.name -} - -func (r *Repo) AddIgnoreDir(ignDir string) { - r.ignDirs = append(r.ignDirs, ignDir) -} - -func (r *Repo) ignoreDir(dir string) bool { - for _, idir := range r.ignDirs { - if idir == dir { - return true - } - } - return false -} - -func (repo *Repo) FilteredSearchList( - curPath string, searchedMap map[string]struct{}) ([]string, error) { - - list := []string{} - - path := filepath.Join(repo.Path(), curPath) - dirList, err := ioutil.ReadDir(path) - if err != nil { - return list, util.FmtNewtError("failed to read repo \"%s\": %s", - repo.Name(), err.Error()) - } - - for _, dirEnt := range dirList { - // Resolve symbolic links. - entPath := filepath.Join(path, dirEnt.Name()) - entry, err := os.Stat(entPath) - if err != nil { - return nil, util.ChildNewtError(err) - } - - name := entry.Name() - if err != nil { - continue - } - - if !entry.IsDir() { - continue - } - - // Don't search the same directory twice. This check is necessary in - // case of symlink cycles. - absPath, err := filepath.EvalSymlinks(entPath) - if err != nil { - return nil, util.ChildNewtError(err) - } - if _, ok := searchedMap[absPath]; ok { - continue - } - searchedMap[absPath] = struct{}{} - - if strings.HasPrefix(name, ".") { - continue - } - if repo.ignoreDir(filepath.Join(curPath, name)) { - continue - } - list = append(list, name) - } - return list, nil -} - -func NewRepoDependency(rname string, verstr string) (*RepoDependency, error) { - var err error - - rd := &RepoDependency{} - rd.versreq, err = LoadVersionMatches(verstr) - if err != nil { - return nil, err - } - rd.name = rname - - return rd, nil -} - -func CheckDeps(upgrade bool, checkRepos map[string]*Repo) error { - // For each dependency, get it's version - depArray := map[string][]*Version{} - - for _, checkRepo := range checkRepos { - for _, rd := range checkRepo.Deps() { - lookupRepo := checkRepos[rd.Name()] - - _, vers, ok := lookupRepo.rdesc.Match(rd.Storerepo) - if !ok { - return util.NewNewtError(fmt.Sprintf("No "+ - "matching version for dependent repository %s", rd.name)) - } - log.Debugf("Dependency for %s: %s (%s)", checkRepo.Name(), rd.Name(), vers.String()) - - _, ok = depArray[rd.Name()] - if !ok { - depArray[rd.Name()] = []*Version{} - } - depArray[rd.Name()] = append(depArray[rd.Name()], vers) - } - } - - for repoName, depVersList := range depArray { - for _, depVers := range depVersList { - for _, curVers := range depVersList { - if depVers.CompareVersions(depVers, curVers) != 0 || - depVers.Stability() != curVers.Stability() { - return util.NewNewtError(fmt.Sprintf( - "Conflict detected. Repository %s has multiple dependency versions on %s. "+ - "Notion of repository version is %s, whereas required is %s ", - repoName, curVers, depVers)) - } - } - } - } - - return nil -} - -func (rd *RepoDesc) MatchVersion(searchVers *Version) (string, *Version, bool) { - for vers, curBranch := range rd.vers { - if vers.CompareVersions(vers, searchVers) == 0 && - searchVers.Stability() == vers.Stability() { - return curBranch, vers, true - } - } - return "", nil, false -} - -func (rd *RepoDesc) Match(r *Repo) (string, *Version, bool) { - for vers, branch := range rd.vers { - log.Debugf("Repository version requires for %s are %s\n", r.Name(), r.VersionRequirements()) - if vers.SatisfiesVersion(r.VersionRequirements()) { - log.Debugf("Found matching version %s for repo %s", - vers.String(), r.Name()) - if vers.Stability() != VERSION_STABILITY_NONE { - // Load the branch as a version, and search for it - searchVers, err := LoadVersion(branch) - if err != nil { - return "", nil, false - } - // Need to match the NONE stability in order to find the right - // branch. - searchVers.stability = VERSION_STABILITY_NONE - - var ok bool - branch, vers, ok = rd.MatchVersion(searchVers) - if !ok { - return "", nil, false - } - log.Debugf("Founding matching version %s for search version %s, related branch is %s\n", - vers, searchVers, branch) - - } - - return branch, vers, true - } - } - - return "", nil, false -} - -func (rd *RepoDesc) SatisfiesVersion(vers *Version, versReqs []interfaces.VersionReqInterface) bool { - var err error - versMatches := []interfaces.VersionReqInterface{} - for _, versReq := range versReqs { - versMatch := &VersionMatch{} - versMatch.compareType = versReq.CompareType() - - if versReq.Version().Stability() != VERSION_STABILITY_NONE { - // Look up this item in the RepoDescription, and get a version - searchVers := versReq.Version().(*Version) - branch, _, ok := rd.MatchVersion(searchVers) - if !ok { - return false - } - versMatch.Vers, err = LoadVersion(branch) - if err != nil { - return false - } - } else { - versMatch.Vers = versReq.Version().(*Version) - } - - versMatches = append(versMatches, versMatch) - } - - return vers.SatisfiesVersion(versMatches) -} - -func (rd *RepoDesc) Init(name string, versBranchMap map[string]string) error { - rd.name = name - rd.vers = map[*Version]string{} - - for versStr, branch := range versBranchMap { - log.Debugf("Printing version %s for remote repo %s", versStr, name) - vers, err := LoadVersion(versStr) - if err != nil { - return err - } - - // store branch->version mapping - rd.vers[vers] = branch - } - - return nil -} - -func (rd *RepoDesc) String() string { - name := rd.name + "@" - for k, v := range rd.vers { - name += fmt.Sprintf("%s=%s", k.String(), v) - name += "#" - } - - return name -} - -func NewRepoDesc(name string, versBranchMap map[string]string) (*RepoDesc, error) { - rd := &RepoDesc{} - - if err := rd.Init(name, versBranchMap); err != nil { - return nil, err - } - - return rd, nil -} - -func (r *Repo) GetRepoDesc() (*RepoDesc, error) { - if r.rdesc == nil { - return nil, util.NewNewtError(fmt.Sprintf( - "Repository description for %s not yet initialized. Must "+ - "download it first. ", r.Name())) - } else { - return r.rdesc, nil - } -} - -func (r *Repo) Name() string { - return r.name -} - -func (r *Repo) Path() string { - return r.localPath -} - -func (r *Repo) IsLocal() bool { - return r.local -} - -func (r *Repo) VersionRequirements() []interfaces.VersionReqInterface { - return r.versreq -} - -func (r *Repo) VersionRequirementsString() string { - str := "" - for _, vreq := range r.versreq { - str += vreq.String() - } - - return str -} - -func (r *Repo) repoFilePath() string { - return interfaces.GetProject().Path() + "/" + REPOS_DIR + "/" + - ".configs/" + r.name + "/" -} - -func (r *Repo) patchesFilePath() string { - return interfaces.GetProject().Path() + "/" + REPOS_DIR + - "/.patches/" -} - -func (r *Repo) downloadRepo(branchName string) error { - dl := r.downloader - - // Download the git repo, returns the git repo, checked out to that branch - tmpdir, err := dl.DownloadRepo(branchName) - if err != nil { - return util.NewNewtError(fmt.Sprintf("Error download repository %s, : %s", - r.Name(), err.Error())) - } - - // Copy the Git repo into the the desired local path of the repo - if err := util.CopyDir(tmpdir, r.Path()); err != nil { - // Cleanup any directory that might have been created if we error out - // here. - os.RemoveAll(r.Path()) - return err - } - - return nil -} - -func (r *Repo) checkExists() bool { - return util.NodeExist(r.Path()) -} - -func (r *Repo) updateRepo(branchName string) error { - dl := r.downloader - err := dl.UpdateRepo(r.Path(), branchName) - if err != nil { - return util.NewNewtError(fmt.Sprintf("Error updating\n")) - } - return nil -} - -func (r *Repo) cleanupRepo(branchName string) error { - dl := r.downloader - err := dl.CleanupRepo(r.Path(), branchName) - if err != nil { - return util.NewNewtError(fmt.Sprintf("Error cleaning and updating\n")) - } - return nil -} - -func (r *Repo) saveLocalDiff() (string, error) { - dl := r.downloader - diff, err := dl.LocalDiff(r.Path()) - if err != nil { - return "", util.NewNewtError(fmt.Sprintf( - "Error creating diff for \"%s\" : %s", r.Name(), err.Error())) - } - - // NOTE: date was not a typo: https://golang.org/pkg/time/#Time.Format - timenow := time.Now().Format("20060102_150405") - filename := r.patchesFilePath() + r.Name() + "_" + timenow + ".diff" - - f, err := os.Create(filename) - if err != nil { - return "", util.NewNewtError(fmt.Sprintf( - "Error creating repo diff file \"%s\"", filename)) - } - defer f.Close() - - _, err = f.Write(diff) - if err != nil { - return "", util.NewNewtError(fmt.Sprintf( - "Error writing repo diff file \"%s\"", filename)) - } - - return filename, nil -} - -func (r *Repo) currentBranch() (string, error) { - dl := r.downloader - branch, err := dl.CurrentBranch(r.Path()) - if err != nil { - return "", util.NewNewtError(fmt.Sprintf("Error finding current branch for \"%s\" : %s", - r.Name(), err.Error())) - } - return filepath.Base(branch), nil -} - -func (r *Repo) Install(force bool) (*Version, error) { - exists := util.NodeExist(r.Path()) - if exists && !force { - return nil, util.NewNewtError(fmt.Sprintf( - "Repository %s already exists, provide the -f option "+ - "to overwrite", r.Name())) - } - - branchName, vers, found := r.rdesc.Match(r) - if !found { - return nil, util.NewNewtError(fmt.Sprintf("No repository matching description %s found", - r.rdesc.String())) - } - - // if the repo is already cloned, try to cleanup and checkout the requested branch - if exists { - err := r.cleanupRepo(branchName) - if err == nil { - return vers, nil - } - - // cleanup failed, so remove current copy and let download clone again... - if err := os.RemoveAll(r.Path()); err != nil { - return nil, util.NewNewtError(err.Error()) - } - } - - // repo was not already cloned or cleanup failed... - if err := r.downloadRepo(branchName); err != nil { - return nil, err - } - - return vers, nil -} - -func (r *Repo) Sync(vers *Version, force bool) (bool, bool, error) { - var exists bool - var err error - var currBranch string - - exists = r.checkExists() - - // Update the repo description - if _, updated, err := r.UpdateDesc(); updated != true || err != nil { - return exists, false, util.NewNewtError("Cannot update repository description.") - } - - branchName, _, found := r.rdesc.MatchVersion(vers) - if found == false { - return exists, false, util.NewNewtError(fmt.Sprintf( - "Branch description for %s not found", r.Name())) - } - - if exists { - // Here assuming that if the branch was changed by the user, - // the user must know what he's doing... - // but, if -f is passed let's just save the work and re-clone - currBranch, err = r.currentBranch() - - // currBranch == HEAD means we're dettached from HEAD, so - // ignore and move to "new" tag - if err != nil { - return exists, false, err - } else if currBranch != "HEAD" && currBranch != branchName { - msg := "Unexpected local branch for %s: \"%s\" != \"%s\"\n" - if force { - util.StatusMessage(util.VERBOSITY_VERBOSE, - msg, r.rdesc.name, currBranch, branchName) - } else { - err = util.NewNewtError( - fmt.Sprintf(msg, r.rdesc.name, currBranch, branchName)) - return exists, false, err - } - } - - // Don't try updating if on an invalid branch... - if currBranch == "HEAD" || currBranch == branchName { - util.StatusMessage(util.VERBOSITY_VERBOSE, "Updating repository...\n") - err = r.updateRepo(branchName) - if err == nil { - util.StatusMessage(util.VERBOSITY_VERBOSE, "Update successful!\n") - return exists, true, err - } else { - util.StatusMessage(util.VERBOSITY_VERBOSE, "Update failed!\n") - if !force { - return exists, false, err - } - } - } - - filename, err := r.saveLocalDiff() - if err != nil { - return exists, false, err - } - wd, _ := os.Getwd() - filename, _ = filepath.Rel(wd, filename) - - util.StatusMessage(util.VERBOSITY_DEFAULT, "Saved local diff: "+ - "\"%s\"\n", filename) - - err = r.cleanupRepo(branchName) - if err != nil { - return exists, false, err - } - - } else { - // fresh or updating was unsuccessfull and force was given... - err = r.downloadRepo(branchName) - if err != nil { - return exists, false, err - } - } - - return exists, true, nil -} - -func (r *Repo) UpdateDesc() ([]*Repo, bool, error) { - var err error - - if r.updated { - return nil, false, nil - } - - util.StatusMessage(util.VERBOSITY_VERBOSE, "[%s]:\n", r.Name()) - - if err = r.DownloadDesc(); err != nil { - return nil, false, err - } - - _, repos, err := r.ReadDesc() - if err != nil { - fmt.Printf("ReadDesc: %v\n", err) - return nil, false, err - } - - r.updated = true - - return repos, true, nil -} - -// Download the repository description. -func (r *Repo) DownloadDesc() error { - dl := r.downloader - - util.StatusMessage(util.VERBOSITY_VERBOSE, "Downloading "+ - "repository description\n") - - // Configuration path - cpath := r.repoFilePath() - if util.NodeNotExist(cpath) { - if err := os.MkdirAll(cpath, REPO_DEFAULT_PERMS); err != nil { - return util.NewNewtError(err.Error()) - } - } - - dl.SetBranch("master") - if err := dl.FetchFile(REPO_FILE_NAME, - cpath+"/"+REPO_FILE_NAME); err != nil { - util.StatusMessage(util.VERBOSITY_VERBOSE, "Download failed\n") - return err - } - - // also create a directory to save diffs for sync - cpath = r.patchesFilePath() - if util.NodeNotExist(cpath) { - if err := os.MkdirAll(cpath, REPO_DEFAULT_PERMS); err != nil { - return util.NewNewtError(err.Error()) - } - } - - util.StatusMessage(util.VERBOSITY_VERBOSE, "Download successful!\n") - - return nil -} - -func (r *Repo) readDepRepos(v *viper.Viper) ([]*Repo, error) { - rdesc := r.rdesc - repos := []*Repo{} - - branch, _, ok := rdesc.Match(r) - if !ok { - // No matching branch, barf! - return nil, util.NewNewtError(fmt.Sprintf("No "+ - "matching branch for %s repo", r.Name())) - } - - repoTag := fmt.Sprintf("%s.repositories", branch) - - repoList := v.GetStringMap(repoTag) - for repoName, repoItf := range repoList { - repoVars := cast.ToStringMapString(repoItf) - - dl, err := downloader.LoadDownloader(repoName, repoVars) - if err != nil { - return nil, err - } - - rversreq := repoVars["vers"] - newRepo, err := NewRepo(repoName, rversreq, dl) - if err != nil { - return nil, err - } - - rd, err := NewRepoDependency(repoName, rversreq) - if err != nil { - return nil, err - } - rd.Storerepo = newRepo - - r.AddDependency(rd) - - repos = append(repos, newRepo) - } - return repos, nil -} - -func (r *Repo) ReadDesc() (*RepoDesc, []*Repo, error) { - if util.NodeNotExist(r.repoFilePath() + REPO_FILE_NAME) { - return nil, nil, - util.NewNewtError("No configuration exists for repository " + r.name) - } - - v, err := util.ReadConfig(r.repoFilePath(), - strings.TrimSuffix(REPO_FILE_NAME, ".yml")) - if err != nil { - return nil, nil, err - } - - name := v.GetString("repo.name") - versMap := v.GetStringMapString("repo.versions") - - rdesc, err := NewRepoDesc(name, versMap) - if err != nil { - return nil, nil, err - } - r.rdesc = rdesc - - repos, err := r.readDepRepos(v) - if err != nil { - return nil, nil, err - } - - // Read the newt version compatibility map. - r.ncMap, err = compat.ReadNcMap(v) - if err != nil { - return nil, nil, err - } - - return rdesc, repos, nil -} - -func (r *Repo) Init(repoName string, rversreq string, d downloader.Downloader) error { - var err error - - r.name = repoName - r.downloader = d - r.deps = []*RepoDependency{} - r.versreq, err = LoadVersionMatches(rversreq) - if err != nil { - return err - } - - path := interfaces.GetProject().Path() - - if r.local { - r.localPath = filepath.ToSlash(filepath.Clean(path)) - } else { - r.localPath = filepath.ToSlash(filepath.Clean(path + "/" + REPOS_DIR + "/" + r.name)) - } - - return nil -} - -func (r *Repo) CheckNewtCompatibility(rvers *Version, nvers newtutil.Version) ( - compat.NewtCompatCode, string) { - - // If this repo doesn't have a newt compatibility map, just assume there is - // no incompatibility. - if len(r.ncMap) == 0 { - return compat.NEWT_COMPAT_GOOD, "" - } - - rnuver := rvers.ToNuVersion() - tbl, ok := r.ncMap[rnuver] - if !ok { - // Unknown repo version. - return compat.NEWT_COMPAT_WARN, - "Repo version missing from compatibility map" - } - - code, text := tbl.CheckNewtVer(nvers) - if code == compat.NEWT_COMPAT_GOOD { - return code, text - } - - return code, fmt.Sprintf("This version of newt (%s) is incompatible with "+ - "your version of the %s repo (%s); %s", - nvers.String(), r.name, rnuver.String(), text) -} - -func NewRepo(repoName string, rversreq string, d downloader.Downloader) (*Repo, error) { - r := &Repo{ - local: false, - } - - if err := r.Init(repoName, rversreq, d); err != nil { - return nil, err - } - - return r, nil -} - -func NewLocalRepo(repoName string) (*Repo, error) { - r := &Repo{ - local: true, - } - - if err := r.Init(repoName, "", nil); err != nil { - return nil, err - } - - return r, nil -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/repo/version.go ---------------------------------------------------------------------- diff --git a/newt/repo/version.go b/newt/repo/version.go deleted file mode 100644 index bbf5b56..0000000 --- a/newt/repo/version.go +++ /dev/null @@ -1,257 +0,0 @@ -/** - * 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 repo - -import ( - "fmt" - "regexp" - "strconv" - "strings" - - "mynewt.apache.org/newt/newt/interfaces" - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/util" -) - -const VERSION_FORMAT = "%d.%d.%d-%s" - -const ( - VERSION_STABILITY_NONE = "none" - VERSION_STABILITY_STABLE = "stable" - VERSION_STABILITY_DEV = "dev" - VERSION_STABILITY_LATEST = "latest" -) - -type VersionMatch struct { - compareType string - Vers *Version -} - -type Version struct { - major int64 - minor int64 - revision int64 - stability string -} - -func (vm *VersionMatch) CompareType() string { - return vm.compareType -} - -func (vm *VersionMatch) Version() interfaces.VersionInterface { - return vm.Vers -} - -func (vm *VersionMatch) String() string { - return vm.compareType + vm.Vers.String() -} - -func (v *Version) Major() int64 { - return v.major -} - -func (v *Version) Minor() int64 { - return v.minor -} - -func (v *Version) Revision() int64 { - return v.revision -} - -func (v *Version) Stability() string { - return v.stability -} - -func (v *Version) CompareVersions(vers1 interfaces.VersionInterface, - vers2 interfaces.VersionInterface) int64 { - if r := vers1.Major() - vers2.Major(); r != 0 { - return r - } - - if r := vers1.Minor() - vers2.Minor(); r != 0 { - return r - } - - if r := vers1.Revision() - vers2.Revision(); r != 0 { - return r - } - - return 0 -} - -func (v *Version) SatisfiesVersion(versMatches []interfaces.VersionReqInterface) bool { - if versMatches == nil { - return true - } - - for _, match := range versMatches { - r := v.CompareVersions(match.Version(), v) - switch match.CompareType() { - case "<": - if r <= 0 { - return false - } - case "<=": - if r < 0 { - return false - } - case ">": - if r >= 0 { - return false - } - case ">=": - if r > 0 { - return false - } - case "==": - if r != 0 { - return false - } - } - - if match.Version().Stability() != v.Stability() { - return false - } - } - - return true -} - -func (vers *Version) String() string { - return fmt.Sprintf(VERSION_FORMAT, vers.Major(), vers.Minor(), vers.Revision(), vers.Stability()) -} - -func (vers *Version) ToNuVersion() newtutil.Version { - return newtutil.Version{ - Major: vers.major, - Minor: vers.minor, - Revision: vers.revision, - } -} - -func LoadVersion(versStr string) (*Version, error) { - var err error - - // Split to get stability level first - sparts := strings.Split(versStr, "-") - stability := VERSION_STABILITY_NONE - if len(sparts) > 1 { - stability = strings.Trim(sparts[1], " ") - switch stability { - case VERSION_STABILITY_STABLE: - fallthrough - case VERSION_STABILITY_DEV: - fallthrough - case VERSION_STABILITY_LATEST: - default: - return nil, util.NewNewtError( - fmt.Sprintf("Unknown stability (%s) in version ", stability) + versStr) - } - } - - parts := strings.Split(sparts[0], ".") - if len(parts) > 3 { - return nil, util.NewNewtError(fmt.Sprintf("Invalid version string: %s", versStr)) - } - - if strings.Trim(parts[0], " ") == "" || strings.Trim(parts[0], " ") == "none" { - return nil, nil - } - - vers := &Version{} - vers.stability = stability - - // convert first string to an int - if vers.major, err = strconv.ParseInt(parts[0], 10, 64); err != nil { - return nil, util.NewNewtError(err.Error()) - } - if len(parts) >= 2 { - if vers.minor, err = strconv.ParseInt(parts[1], 10, 64); err != nil { - return nil, util.NewNewtError(err.Error()) - } - } - if len(parts) == 3 { - if vers.revision, err = strconv.ParseInt(parts[2], 10, 64); err != nil { - return nil, util.NewNewtError(err.Error()) - } - } - - return vers, nil -} - -func NewVersion(major int64, minor int64, rev int64) *Version { - vers := &Version{} - - vers.major = major - vers.minor = minor - vers.revision = rev - - return vers -} - -// Parse a set of version string constraints on a dependency. -// This function -// The version string contains a list of version constraints in the following format: -// - <comparison><version> -// Where <comparison> can be any one of the following comparison -// operators: <=, <, >, >=, == -// And <version> is specified in the form: X.Y.Z where X, Y and Z are all -// int64 types in decimal form -func LoadVersionMatches(versStr string) ([]interfaces.VersionReqInterface, error) { - var err error - - versMatches := []interfaces.VersionReqInterface{} - - re, err := regexp.Compile(`(<=|>=|==|>|<)([\d\.]+)`) - if err != nil { - return nil, err - } - - matches := re.FindAllStringSubmatch(versStr, -1) - if matches != nil { - for _, match := range matches { - vm := &VersionMatch{} - vm.compareType = match[1] - if vm.Vers, err = LoadVersion(match[2]); err != nil { - return nil, err - } - - if vm.Vers != nil { - versMatches = append(versMatches, vm) - } - } - } else { - vm := &VersionMatch{} - vm.compareType = "==" - if vm.Vers, err = LoadVersion(versStr); err != nil { - return nil, err - } - - if vm.Vers != nil { - versMatches = append(versMatches, vm) - } - } - - if len(versMatches) == 0 { - versMatches = nil - } - - return versMatches, nil -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/resolve/resolve.go ---------------------------------------------------------------------- diff --git a/newt/resolve/resolve.go b/newt/resolve/resolve.go deleted file mode 100644 index 6e03592..0000000 --- a/newt/resolve/resolve.go +++ /dev/null @@ -1,626 +0,0 @@ -/** - * 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 resolve - -import ( - "fmt" - "sort" - "strings" - - log "github.com/Sirupsen/logrus" - - "mynewt.apache.org/newt/newt/flash" - "mynewt.apache.org/newt/newt/newtutil" - "mynewt.apache.org/newt/newt/pkg" - "mynewt.apache.org/newt/newt/project" - "mynewt.apache.org/newt/newt/syscfg" - "mynewt.apache.org/newt/util" -) - -type Resolver struct { - apis map[string]*ResolvePackage - pkgMap map[*pkg.LocalPackage]*ResolvePackage - injectedSettings map[string]string - flashMap flash.FlashMap - cfg syscfg.Cfg -} - -type ResolveDep struct { - // Package being depended on. - Rpkg *ResolvePackage - - // Name of API that generated the dependency; "" if a hard dependency. - Api string - - // XXX: slice of syscfg settings that generated this dependency. -} - -type ResolvePackage struct { - Lpkg *pkg.LocalPackage - Deps map[*ResolvePackage]*ResolveDep - - // Keeps track of API requirements and whether they are satisfied. - reqApiMap map[string]bool - - depsResolved bool - apisSatisfied bool -} - -type ResolveSet struct { - // Parent resoluion. Contains this ResolveSet. - Res *Resolution - - // All seed pacakges and their dependencies. - Rpkgs []*ResolvePackage -} - -// The result of resolving a target's configuration, APIs, and dependencies. -type Resolution struct { - Cfg syscfg.Cfg - ApiMap map[string]*ResolvePackage - UnsatisfiedApis map[string][]*ResolvePackage - - LpkgRpkgMap map[*pkg.LocalPackage]*ResolvePackage - - // Contains all dependencies; union of loader and app. - MasterSet *ResolveSet - - LoaderSet *ResolveSet - AppSet *ResolveSet -} - -func newResolver( - seedPkgs []*pkg.LocalPackage, - injectedSettings map[string]string, - flashMap flash.FlashMap) *Resolver { - - r := &Resolver{ - apis: map[string]*ResolvePackage{}, - pkgMap: map[*pkg.LocalPackage]*ResolvePackage{}, - injectedSettings: injectedSettings, - flashMap: flashMap, - cfg: syscfg.NewCfg(), - } - - if injectedSettings == nil { - r.injectedSettings = map[string]string{} - } - - for _, lpkg := range seedPkgs { - r.addPkg(lpkg) - } - - return r -} - -func newResolution() *Resolution { - r := &Resolution{ - ApiMap: map[string]*ResolvePackage{}, - UnsatisfiedApis: map[string][]*ResolvePackage{}, - } - - r.MasterSet = &ResolveSet{Res: r} - r.LoaderSet = &ResolveSet{Res: r} - r.AppSet = &ResolveSet{Res: r} - - return r -} - -func NewResolvePkg(lpkg *pkg.LocalPackage) *ResolvePackage { - return &ResolvePackage{ - Lpkg: lpkg, - reqApiMap: map[string]bool{}, - Deps: map[*ResolvePackage]*ResolveDep{}, - } -} - -func (r *Resolver) resolveDep(dep *pkg.Dependency, depender string) (*pkg.LocalPackage, error) { - proj := project.GetProject() - - if proj.ResolveDependency(dep) == nil { - return nil, util.FmtNewtError("Could not resolve package dependency: "+ - "%s; depender: %s", dep.String(), depender) - } - lpkg := proj.ResolveDependency(dep).(*pkg.LocalPackage) - - return lpkg, nil -} - -// @return true if rhe package's dependency list was -// modified. -func (rpkg *ResolvePackage) AddDep(apiPkg *ResolvePackage, api string) bool { - if dep := rpkg.Deps[apiPkg]; dep != nil { - if dep.Api != "" && api == "" { - dep.Api = api - return true - } else { - return false - } - } else { - rpkg.Deps[apiPkg] = &ResolveDep{ - Rpkg: apiPkg, - Api: api, - } - return true - } -} - -func (r *Resolver) rpkgSlice() []*ResolvePackage { - rpkgs := make([]*ResolvePackage, len(r.pkgMap)) - - i := 0 - for _, rpkg := range r.pkgMap { - rpkgs[i] = rpkg - i++ - } - - return rpkgs -} - -func (r *Resolver) apiSlice() []string { - apis := make([]string, len(r.apis)) - - i := 0 - for api, _ := range r.apis { - apis[i] = api - i++ - } - - return apis -} - -// @return ResolvePackage The rpkg corresponding to the specified lpkg. -// This is a new package if a package was -// added; old if it was already present. -// bool true if this is a new package. -func (r *Resolver) addPkg(lpkg *pkg.LocalPackage) (*ResolvePackage, bool) { - if rpkg := r.pkgMap[lpkg]; rpkg != nil { - return rpkg, false - } - - rpkg := NewResolvePkg(lpkg) - r.pkgMap[lpkg] = rpkg - return rpkg, true -} - -// @return bool true if this is a new API. -func (r *Resolver) addApi(apiString string, rpkg *ResolvePackage) bool { - curRpkg := r.apis[apiString] - if curRpkg == nil { - r.apis[apiString] = rpkg - return true - } else { - if curRpkg != rpkg { - util.StatusMessage(util.VERBOSITY_QUIET, - "Warning: API conflict: %s (%s <-> %s)\n", apiString, - curRpkg.Lpkg.Name(), rpkg.Lpkg.Name()) - } - return false - } -} - -// Searches for a package which can satisfy bpkg's API requirement. If such a -// package is found, bpkg's API requirement is marked as satisfied, and the -// package is added to bpkg's dependency list. -// -// @return bool true if the API is now satisfied. -func (r *Resolver) satisfyApi(rpkg *ResolvePackage, reqApi string) bool { - depRpkg := r.apis[reqApi] - if depRpkg == nil { - // Insert nil to indicate an unsatisfied API. - r.apis[reqApi] = nil - return false - } - - rpkg.reqApiMap[reqApi] = true - - // This package now has a new unresolved dependency. - rpkg.depsResolved = false - - log.Debugf("API requirement satisfied; pkg=%s API=(%s, %s)", - rpkg.Lpkg.Name(), reqApi, depRpkg.Lpkg.FullName()) - - return true -} - -// @return bool true if a new dependency was detected as a -// result of satisfying an API for this -// package. -func (r *Resolver) satisfyApis(rpkg *ResolvePackage) bool { - // Assume all this package's APIs are satisfied and that no new - // dependencies will be detected. - rpkg.apisSatisfied = true - newDeps := false - - features := r.cfg.FeaturesForLpkg(rpkg.Lpkg) - - // Determine if any of the package's API requirements can now be satisfied. - // If so, another full iteration is required. - reqApis := newtutil.GetStringSliceFeatures(rpkg.Lpkg.PkgV, features, - "pkg.req_apis") - for _, reqApi := range reqApis { - reqStatus := rpkg.reqApiMap[reqApi] - if !reqStatus { - apiSatisfied := r.satisfyApi(rpkg, reqApi) - if apiSatisfied { - // An API was satisfied; the package now has a new dependency - // that needs to be resolved. - newDeps = true - reqStatus = true - } else { - rpkg.reqApiMap[reqApi] = false - rpkg.apisSatisfied = false - } - } - } - - return newDeps -} - -// @return bool True if this this function changed the resolver -// state; another full iteration is required -// in this case. -// error non-nil on failure. -func (r *Resolver) loadDepsForPkg(rpkg *ResolvePackage) (bool, error) { - features := r.cfg.FeaturesForLpkg(rpkg.Lpkg) - - changed := false - newDeps := newtutil.GetStringSliceFeatures(rpkg.Lpkg.PkgV, features, - "pkg.deps") - depender := rpkg.Lpkg.Name() - for _, newDepStr := range newDeps { - newDep, err := pkg.NewDependency(rpkg.Lpkg.Repo(), newDepStr) - if err != nil { - return false, err - } - - lpkg, err := r.resolveDep(newDep, depender) - if err != nil { - return false, err - } - - depRpkg, _ := r.addPkg(lpkg) - if rpkg.AddDep(depRpkg, "") { - changed = true - } - } - - // Determine if this package supports any APIs that we haven't seen - // yet. If so, another full iteration is required. - apis := newtutil.GetStringSliceFeatures(rpkg.Lpkg.PkgV, features, - "pkg.apis") - for _, api := range apis { - if r.addApi(api, rpkg) { - changed = true - } - } - - return changed, nil -} - -// Attempts to resolve all of a build package's dependencies, APIs, and -// required APIs. This function should be called repeatedly until the package -// is fully resolved. -// -// If a dependency is resolved by this function, the new dependency needs to be -// processed. The caller should attempt to resolve all packages again. -// -// @return bool true if >=1 dependencies were resolved. -// error non-nil on failure. -func (r *Resolver) resolvePkg(rpkg *ResolvePackage) (bool, error) { - var err error - newDeps := false - - if !rpkg.depsResolved { - newDeps, err = r.loadDepsForPkg(rpkg) - if err != nil { - return false, err - } - - rpkg.depsResolved = !newDeps - } - - if !rpkg.apisSatisfied { - newApiDep := r.satisfyApis(rpkg) - if newApiDep { - newDeps = true - } - } - - return newDeps, nil -} - -// @return changed,err -func (r *Resolver) reloadCfg() (bool, error) { - lpkgs := RpkgSliceToLpkgSlice(r.rpkgSlice()) - apis := r.apiSlice() - - // Determine which features have been detected so far. The feature map is - // required for reloading syscfg, as features may unlock additional - // settings. - features := r.cfg.Features() - cfg, err := syscfg.Read(lpkgs, apis, r.injectedSettings, features, - r.flashMap) - if err != nil { - return false, err - } - - changed := false - for k, v := range cfg.Settings { - oldval, ok := r.cfg.Settings[k] - if !ok || len(oldval.History) != len(v.History) { - r.cfg = cfg - changed = true - } - } - - return changed, nil -} - -func (r *Resolver) resolveDepsOnce() (bool, error) { - // Circularly resolve dependencies, APIs, and required APIs until no new - // ones exist. - newDeps := false - for { - reprocess := false - for _, rpkg := range r.pkgMap { - newDeps, err := r.resolvePkg(rpkg) - if err != nil { - return false, err - } - - if newDeps { - // The new dependencies need to be processed. Iterate again - // after this iteration completes. - reprocess = true - } - } - - if !reprocess { - break - } - } - - return newDeps, nil -} - -func (r *Resolver) resolveDeps() ([]*ResolvePackage, error) { - if _, err := r.resolveDepsOnce(); err != nil { - return nil, err - } - - // Satisfy API requirements. - if err := r.resolveApiDeps(); err != nil { - return nil, err - } - - rpkgs := r.rpkgSlice() - return rpkgs, nil -} - -func (r *Resolver) resolveDepsAndCfg() error { - if _, err := r.resolveDepsOnce(); err != nil { - return err - } - - for { - cfgChanged, err := r.reloadCfg() - if err != nil { - return err - } - if cfgChanged { - // A new supported feature was discovered. It is impossible - // to determine what new dependency and API requirements are - // generated as a result. All packages need to be - // reprocessed. - for _, rpkg := range r.pkgMap { - rpkg.depsResolved = false - rpkg.apisSatisfied = false - } - } - - newDeps, err := r.resolveDepsOnce() - if err != nil { - return err - } - - if !newDeps && !cfgChanged { - break - } - } - - // Satisfy API requirements. - if err := r.resolveApiDeps(); err != nil { - return err - } - - // Log the final syscfg. - r.cfg.Log() - - return nil -} - -// Transforms each package's required APIs to hard dependencies. That is, this -// function determines which package supplies each required API, and adds the -// corresponding dependecy to each package which requires the API. -func (r *Resolver) resolveApiDeps() error { - for _, rpkg := range r.pkgMap { - for api, _ := range rpkg.reqApiMap { - apiPkg := r.apis[api] - if apiPkg != nil { - rpkg.AddDep(apiPkg, api) - } - } - } - - return nil -} - -func (r *Resolver) apiResolution() ( - map[string]*ResolvePackage, - map[string][]*ResolvePackage) { - - apiMap := make(map[string]*ResolvePackage, len(r.apis)) - anyUnsatisfied := false - for api, rpkg := range r.apis { - if rpkg == nil { - anyUnsatisfied = true - } else { - apiMap[api] = rpkg - } - } - - unsatisfied := map[string][]*ResolvePackage{} - if anyUnsatisfied { - for _, rpkg := range r.pkgMap { - for api, satisfied := range rpkg.reqApiMap { - if !satisfied { - slice := unsatisfied[api] - slice = append(slice, rpkg) - unsatisfied[api] = slice - } - } - } - } - - return apiMap, unsatisfied -} - -func ResolveFull( - loaderSeeds []*pkg.LocalPackage, - appSeeds []*pkg.LocalPackage, - injectedSettings map[string]string, - flashMap flash.FlashMap) (*Resolution, error) { - - // First, calculate syscfg and determine which package provides each - // required API. Syscfg and APIs are project-wide; that is, they are - // calculated across the aggregate of all app packages and loader packages - // (if any). The dependency graph for the entire set of packages gets - // calculated here as a byproduct. - - allSeeds := append(loaderSeeds, appSeeds...) - r := newResolver(allSeeds, injectedSettings, flashMap) - - if err := r.resolveDepsAndCfg(); err != nil { - return nil, err - } - - res := newResolution() - res.Cfg = r.cfg - if err := r.resolveApiDeps(); err != nil { - return nil, err - } - - // Determine which package satisfies each API and which APIs are - // unsatisfied. - apiMap := map[string]*ResolvePackage{} - apiMap, res.UnsatisfiedApis = r.apiResolution() - - res.LpkgRpkgMap = r.pkgMap - - res.MasterSet.Rpkgs = r.rpkgSlice() - - // If there is no loader, then the set of all packages is just the app - // packages. We already resolved the necessary dependency information when - // syscfg was calculated above. - if loaderSeeds == nil { - res.AppSet.Rpkgs = r.rpkgSlice() - res.LoaderSet = nil - return res, nil - } - - // Otherwise, we need to resolve dependencies separately for: - // 1. The set of loader pacakges, and - // 2. The set of app packages. - // - // These need to be resolved separately so that it is possible later to - // determine which packages need to be shared between loader and app. - - // It is OK if the app requires an API that is supplied by the loader. - // Ensure each set of packages has access to the API-providers. - for _, rpkg := range apiMap { - loaderSeeds = append(loaderSeeds, rpkg.Lpkg) - appSeeds = append(appSeeds, rpkg.Lpkg) - } - - // Resolve loader dependencies. - r = newResolver(loaderSeeds, injectedSettings, flashMap) - r.cfg = res.Cfg - - var err error - - res.LoaderSet.Rpkgs, err = r.resolveDeps() - if err != nil { - return nil, err - } - - // Resolve app dependencies. The app automtically gets all the packages - // from the loader except for the loader-app-package. - for _, rpkg := range res.LoaderSet.Rpkgs { - if rpkg.Lpkg.Type() != pkg.PACKAGE_TYPE_APP { - appSeeds = append(appSeeds, rpkg.Lpkg) - } - } - - r = newResolver(appSeeds, injectedSettings, flashMap) - r.cfg = res.Cfg - - res.AppSet.Rpkgs, err = r.resolveDeps() - if err != nil { - return nil, err - } - - return res, nil -} - -func (res *Resolution) ErrorText() string { - str := "" - - if len(res.UnsatisfiedApis) > 0 { - apiNames := make([]string, 0, len(res.UnsatisfiedApis)) - for api, _ := range res.UnsatisfiedApis { - apiNames = append(apiNames, api) - } - sort.Strings(apiNames) - - str += "Unsatisfied APIs detected:\n" - for _, api := range apiNames { - str += fmt.Sprintf(" * %s, required by: ", api) - - rpkgs := res.UnsatisfiedApis[api] - pkgNames := make([]string, len(rpkgs)) - for i, rpkg := range rpkgs { - pkgNames[i] = rpkg.Lpkg.Name() - } - sort.Strings(pkgNames) - - str += strings.Join(pkgNames, ", ") - str += "\n" - } - } - - str += res.Cfg.ErrorText() - - return strings.TrimSpace(str) -} - -func (res *Resolution) WarningText() string { - return res.Cfg.WarningText() -} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/e31a7d31/newt/resolve/resolveutil.go ---------------------------------------------------------------------- diff --git a/newt/resolve/resolveutil.go b/newt/resolve/resolveutil.go deleted file mode 100644 index 23884d3..0000000 --- a/newt/resolve/resolveutil.go +++ /dev/null @@ -1,92 +0,0 @@ -/** -* 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 resolve - -import ( - "sort" - - "mynewt.apache.org/newt/newt/pkg" -) - -type rpkgSorter struct { - pkgs []*ResolvePackage -} - -func (s rpkgSorter) Len() int { - return len(s.pkgs) -} -func (s rpkgSorter) Swap(i, j int) { - s.pkgs[i], s.pkgs[j] = s.pkgs[j], s.pkgs[i] -} -func (s rpkgSorter) Less(i, j int) bool { - return s.pkgs[i].Lpkg.FullName() < s.pkgs[j].Lpkg.FullName() -} - -func SortResolvePkgs(pkgs []*ResolvePackage) []*ResolvePackage { - sorter := rpkgSorter{ - pkgs: make([]*ResolvePackage, 0, len(pkgs)), - } - - for _, p := range pkgs { - sorter.pkgs = append(sorter.pkgs, p) - } - - sort.Sort(sorter) - return sorter.pkgs -} - -type rdepSorter struct { - deps []*ResolveDep -} - -func (s rdepSorter) Len() int { - return len(s.deps) -} -func (s rdepSorter) Swap(i, j int) { - s.deps[i], s.deps[j] = s.deps[j], s.deps[i] -} - -func (s rdepSorter) Less(i, j int) bool { - return s.deps[i].Rpkg.Lpkg.FullName() < s.deps[j].Rpkg.Lpkg.FullName() -} -func SortResolveDeps(deps []*ResolveDep) []*ResolveDep { - sorter := rdepSorter{ - deps: make([]*ResolveDep, 0, len(deps)), - } - - for _, d := range deps { - sorter.deps = append(sorter.deps, d) - } - - sort.Sort(sorter) - return sorter.deps -} - -func RpkgSliceToLpkgSlice(rpkgs []*ResolvePackage) []*pkg.LocalPackage { - lpkgs := make([]*pkg.LocalPackage, len(rpkgs)) - - i := 0 - for _, rpkg := range rpkgs { - lpkgs[i] = rpkg.Lpkg - i++ - } - - return lpkgs -}
