You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/01/04 18:21:12 UTC

[mynewt-newt] 07/17: Add `manifest` package - manifest generation

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 8e570b87e88c3d4888ebf69b9b6ff6da2cf354b7
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Tue Nov 20 17:52:09 2018 -0800

    Add `manifest` package - manifest generation
---
 newt/manifest/manifest.go | 305 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 305 insertions(+)

diff --git a/newt/manifest/manifest.go b/newt/manifest/manifest.go
new file mode 100644
index 0000000..7c9eaff
--- /dev/null
+++ b/newt/manifest/manifest.go
@@ -0,0 +1,305 @@
+/**
+ * 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"
+
+	"mynewt.apache.org/newt/artifact/flash"
+	"mynewt.apache.org/newt/artifact/image"
+	"mynewt.apache.org/newt/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
+	FlashAreas []flash.FlashArea
+}
+
+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(),
+	}
+
+	var path string
+	if lpkg.Repo().IsLocal() {
+		ip.Repo = lpkg.Repo().Name()
+		path = lpkg.BasePath()
+	} else {
+		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 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),
+		FlashAreas: opts.FlashAreas,
+	}
+
+	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 := t.GetTarget().Package().SyscfgY.GetValStringMapString(
+		"syscfg.vals", nil)
+	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
+}