newt/manifest/manifest.go (253 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. */ // imgprod - Manifest generation. package manifest import ( "fmt" "os" "sort" "strings" "time" log "github.com/sirupsen/logrus" "github.com/apache/mynewt-artifact/image" "github.com/apache/mynewt-artifact/manifest" "mynewt.apache.org/newt/newt/builder" "mynewt.apache.org/newt/newt/pkg" "mynewt.apache.org/newt/newt/syscfg" "mynewt.apache.org/newt/util" ) type ManifestSizeCollector struct { Pkgs []*manifest.ManifestSizePkg } type ManifestCreateOpts struct { TgtBldr *builder.TargetBuilder LoaderHash []byte AppHash []byte Version image.ImageVersion BuildID string Syscfg map[string]string } type RepoManager struct { repos map[string]manifest.ManifestRepo } func NewRepoManager() *RepoManager { return &RepoManager{ repos: make(map[string]manifest.ManifestRepo), } } func (r *RepoManager) AllRepos() []*manifest.ManifestRepo { keys := make([]string, 0, len(r.repos)) for k := range r.repos { keys = append(keys, k) } sort.Strings(keys) repos := make([]*manifest.ManifestRepo, 0, len(keys)) for _, key := range keys { r := r.repos[key] repos = append(repos, &r) } return repos } func (c *ManifestSizeCollector) AddPkg(pkg string) *manifest.ManifestSizePkg { p := &manifest.ManifestSizePkg{ Name: pkg, } c.Pkgs = append(c.Pkgs, p) return p } func AddSymbol(p *manifest.ManifestSizePkg, file string, sym string, area string, symSz uint32) { f := addFile(p, file) s := addSym(f, sym) addArea(s, area, symSz) } func addFile(p *manifest.ManifestSizePkg, file string) *manifest.ManifestSizeFile { for _, f := range p.Files { if f.Name == file { return f } } f := &manifest.ManifestSizeFile{ Name: file, } p.Files = append(p.Files, f) return f } func addSym(f *manifest.ManifestSizeFile, sym string) *manifest.ManifestSizeSym { s := &manifest.ManifestSizeSym{ Name: sym, } f.Syms = append(f.Syms, s) return s } func addArea(s *manifest.ManifestSizeSym, area string, areaSz uint32) { a := &manifest.ManifestSizeArea{ Name: area, Size: areaSz, } s.Areas = append(s.Areas, a) } func (r *RepoManager) GetManifestPkg( lpkg *pkg.LocalPackage) *manifest.ManifestPkg { ip := &manifest.ManifestPkg{ Name: lpkg.FullName(), } ip.Repo = lpkg.Repo().Name() path := lpkg.BasePath() if _, present := r.repos[ip.Repo]; present { return ip } repo := manifest.ManifestRepo{ Name: ip.Repo, } // Make sure we restore the current working dir to whatever it was when // this function was called cwd, err := os.Getwd() if err != nil { log.Debugf("Unable to determine current working directory: %v", err) return ip } defer os.Chdir(cwd) if err := os.Chdir(path); err != nil { return ip } var res []byte res, err = util.ShellCommand([]string{ "git", "rev-parse", "HEAD", }, nil) if err != nil { log.Debugf("Unable to determine commit hash for %s: %v", path, err) repo.Commit = "UNKNOWN" } else { repo.Commit = strings.TrimSpace(string(res)) res, err = util.ShellCommand([]string{ "git", "status", "--porcelain", }, nil) if err != nil { log.Debugf("Unable to determine dirty state for %s: %v", path, err) } else { if len(res) > 0 { repo.Dirty = true } } res, err = util.ShellCommand([]string{ "git", "config", "--get", "remote.origin.url", }, nil) if err != nil { log.Debugf("Unable to determine URL for %s: %v", path, err) } else { repo.URL = strings.TrimSpace(string(res)) } } r.repos[ip.Repo] = repo return ip } func ManifestPkgSizes(b *builder.Builder) (ManifestSizeCollector, error) { msc := ManifestSizeCollector{} libs, err := builder.ParseMapFileSizes(b.AppMapPath()) if err != nil { return msc, err } // Order libraries by name. pkgSizes := make(builder.PkgSizeArray, len(libs)) i := 0 for _, es := range libs { pkgSizes[i] = es i++ } sort.Sort(pkgSizes) for _, es := range pkgSizes { p := msc.AddPkg(b.FindPkgNameByArName(es.Name)) // Order symbols by name. symbols := make(builder.SymbolDataArray, len(es.Syms)) i := 0 for _, sym := range es.Syms { symbols[i] = sym i++ } sort.Sort(symbols) for _, sym := range symbols { for area, areaSz := range sym.Sizes { if areaSz != 0 { AddSymbol(p, sym.ObjName, sym.Name, area, areaSz) } } } } return msc, nil } func OptsForNonImage(t *builder.TargetBuilder) (ManifestCreateOpts, error) { res, err := t.Resolve() if err != nil { return ManifestCreateOpts{}, err } return ManifestCreateOpts{ TgtBldr: t, Syscfg: res.Cfg.SettingValues().ToMap(), }, nil } func OptsForImage(t *builder.TargetBuilder, ver image.ImageVersion, appHash []byte, loaderHash []byte) (ManifestCreateOpts, error) { res, err := t.Resolve() if err != nil { return ManifestCreateOpts{}, err } return ManifestCreateOpts{ TgtBldr: t, AppHash: appHash, LoaderHash: loaderHash, Version: ver, BuildID: fmt.Sprintf("%x", appHash), Syscfg: res.Cfg.SettingValues().ToMap(), }, nil } func CreateManifest(opts ManifestCreateOpts) (manifest.Manifest, error) { t := opts.TgtBldr m := manifest.Manifest{ Name: t.GetTarget().FullName(), Date: time.Now().Format(time.RFC3339), Version: opts.Version.String(), BuildID: opts.BuildID, Image: t.AppBuilder.AppImgPath(), ImageHash: fmt.Sprintf("%x", opts.AppHash), Syscfg: opts.Syscfg, } rm := NewRepoManager() for _, rpkg := range t.AppBuilder.SortedRpkgs() { m.Pkgs = append(m.Pkgs, rm.GetManifestPkg(rpkg.Lpkg)) } m.Repos = rm.AllRepos() vars := t.GetTarget().TargetY.AllSettingsAsStrings() keys := make([]string, 0, len(vars)) for k := range vars { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { m.TgtVars = append(m.TgtVars, k+"="+vars[k]) } syscfgKV, err := t.GetTarget().Package().SyscfgY.GetValStringMapString( "syscfg.vals", nil) util.OneTimeWarningError(err) if len(syscfgKV) > 0 { tgtSyscfg := fmt.Sprintf("target.syscfg=%s", syscfg.KeyValueToStr(syscfgKV)) m.TgtVars = append(m.TgtVars, tgtSyscfg) } c, err := ManifestPkgSizes(t.AppBuilder) if err == nil { m.PkgSizes = c.Pkgs } if t.LoaderBuilder != nil { m.Loader = t.LoaderBuilder.AppImgPath() m.LoaderHash = fmt.Sprintf("%x", opts.LoaderHash) for _, rpkg := range t.LoaderBuilder.SortedRpkgs() { m.LoaderPkgs = append(m.LoaderPkgs, rm.GetManifestPkg(rpkg.Lpkg)) } c, err = ManifestPkgSizes(t.LoaderBuilder) if err == nil { m.LoaderPkgSizes = c.Pkgs } } return m, nil }