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 7cdcc26257367cd40590e59f3440e3058f82261f
Author: Christopher Collins <ccoll...@apache.org>
AuthorDate: Tue Nov 20 17:51:53 2018 -0800

    Add `imgprod` package - image production
---
 newt/imgprod/imgprod.go | 286 ++++++++++++++++++++++++++++++++++++++++++++++++
 newt/imgprod/v1.go      | 218 ++++++++++++++++++++++++++++++++++++
 2 files changed, 504 insertions(+)

diff --git a/newt/imgprod/imgprod.go b/newt/imgprod/imgprod.go
new file mode 100644
index 0000000..a858c49
--- /dev/null
+++ b/newt/imgprod/imgprod.go
@@ -0,0 +1,286 @@
+/**
+ * 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 - Image production.
+
+package imgprod
+
+import (
+       "fmt"
+       "os"
+       "strings"
+
+       "mynewt.apache.org/newt/artifact/image"
+       "mynewt.apache.org/newt/newt/builder"
+       "mynewt.apache.org/newt/newt/manifest"
+       "mynewt.apache.org/newt/newt/newtutil"
+       "mynewt.apache.org/newt/util"
+)
+
+type ImageProdOpts struct {
+       LoaderSrcFilename string
+       LoaderDstFilename string
+       AppSrcFilename    string
+       AppDstFilename    string
+       EncKeyFilename    string
+       Version           image.ImageVersion
+       SigKeys           []image.ImageSigKey
+}
+
+type ProducedImage struct {
+       Filename string
+       Image    image.Image
+       Hash     []byte
+       FileSize int
+}
+
+type ProducedImageSet struct {
+       Loader *ProducedImage
+       App    ProducedImage
+}
+
+func produceLoader(opts ImageProdOpts) (ProducedImage, error) {
+       pi := ProducedImage{}
+
+       igo := image.ImageCreateOpts{
+               SrcBinFilename:    opts.LoaderSrcFilename,
+               SrcEncKeyFilename: opts.EncKeyFilename,
+               Version:           opts.Version,
+               SigKeys:           opts.SigKeys,
+       }
+
+       ri, err := image.GenerateImage(igo)
+       if err != nil {
+               return pi, err
+       }
+
+       hash, err := ri.Hash()
+       if err != nil {
+               return pi, err
+       }
+
+       fileSize, err := ri.TotalSize()
+       if err != nil {
+               return pi, err
+       }
+
+       imgFile, err := os.OpenFile(opts.LoaderDstFilename,
+               os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+       if err != nil {
+               return pi, util.FmtNewtError(
+                       "Can't open target image %s: %s",
+                       opts.LoaderDstFilename, err.Error())
+       }
+       defer imgFile.Close()
+
+       if _, err := ri.Write(imgFile); err != nil {
+               return pi, err
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT,
+               "Loader image successfully generated: %s\n", 
opts.LoaderDstFilename)
+
+       pi.Filename = opts.LoaderDstFilename
+       pi.Image = ri
+       pi.Hash = hash
+       pi.FileSize = fileSize
+
+       return pi, nil
+}
+
+func produceApp(opts ImageProdOpts, loaderHash []byte) (ProducedImage, error) {
+       pi := ProducedImage{}
+
+       igo := image.ImageCreateOpts{
+               SrcBinFilename:    opts.AppSrcFilename,
+               SrcEncKeyFilename: opts.EncKeyFilename,
+               Version:           opts.Version,
+               SigKeys:           opts.SigKeys,
+               LoaderHash:        loaderHash,
+       }
+
+       ri, err := image.GenerateImage(igo)
+       if err != nil {
+               return pi, err
+       }
+
+       hash, err := ri.Hash()
+       if err != nil {
+               return pi, err
+       }
+
+       fileSize, err := ri.TotalSize()
+       if err != nil {
+               return pi, err
+       }
+
+       imgFile, err := os.OpenFile(opts.AppDstFilename,
+               os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+       if err != nil {
+               return pi, util.FmtNewtError(
+                       "Can't open target image %s: %s", opts.AppDstFilename, 
err.Error())
+       }
+       defer imgFile.Close()
+
+       if _, err := ri.Write(imgFile); err != nil {
+               return pi, err
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT,
+               "App image successfully generated: %s\n", opts.AppDstFilename)
+
+       pi.Filename = opts.AppDstFilename
+       pi.Image = ri
+       pi.Hash = hash
+       pi.FileSize = fileSize
+
+       return pi, nil
+}
+
+// Verifies that each already-built image leaves enough room for a boot trailer
+// a the end of its slot.
+func verifyImgSizes(pset ProducedImageSet, maxSizes []int) error {
+       errLines := []string{}
+       slot := 0
+
+       if pset.Loader != nil {
+               if overflow := int(pset.Loader.FileSize) - maxSizes[0]; 
overflow > 0 {
+                       errLines = append(errLines,
+                               fmt.Sprintf("loader overflows slot-0 by %d 
bytes "+
+                                       "(image=%d max=%d)",
+                                       overflow, pset.Loader.FileSize, 
maxSizes[0]))
+               }
+               slot++
+       }
+
+       if overflow := int(pset.App.FileSize) - maxSizes[slot]; overflow > 0 {
+               errLines = append(errLines,
+                       fmt.Sprintf("app overflows slot-%d by %d bytes "+
+                               "(image=%d max=%d)",
+                               slot, overflow, pset.App.FileSize, 
maxSizes[slot]))
+
+       }
+
+       if len(errLines) > 0 {
+               if !newtutil.NewtForce {
+                       return util.NewNewtError(strings.Join(errLines, "; "))
+               } else {
+                       for _, e := range errLines {
+                               util.StatusMessage(util.VERBOSITY_QUIET,
+                                       "* Warning: %s (ignoring due to force 
flag)\n", e)
+                       }
+               }
+       }
+
+       return nil
+}
+
+func ProduceImages(opts ImageProdOpts) (ProducedImageSet, error) {
+       pset := ProducedImageSet{}
+
+       var loaderHash []byte
+       if opts.LoaderSrcFilename != "" {
+               pi, err := produceLoader(opts)
+               if err != nil {
+                       return pset, err
+               }
+               loaderHash = pi.Hash
+
+               pset.Loader = &pi
+       }
+
+       pi, err := produceApp(opts, loaderHash)
+       if err != nil {
+               return pset, err
+       }
+       pset.App = pi
+
+       return pset, nil
+}
+
+func ProduceManifest(opts manifest.ManifestCreateOpts) error {
+       m, err := manifest.CreateManifest(opts)
+       if err != nil {
+               return err
+       }
+
+       file, err := os.Create(opts.TgtBldr.AppBuilder.ManifestPath())
+       if err != nil {
+               return util.FmtNewtError("Cannot create manifest file %s: %s",
+                       opts.TgtBldr.AppBuilder.ManifestPath(), err.Error())
+       }
+       defer file.Close()
+
+       if _, err := m.Write(file); err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func OptsFromTgtBldr(b *builder.TargetBuilder, ver image.ImageVersion,
+       sigKeys []image.ImageSigKey, encKeyFilename string) ImageProdOpts {
+
+       opts := ImageProdOpts{
+               AppSrcFilename: b.AppBuilder.AppBinPath(),
+               AppDstFilename: b.AppBuilder.AppImgPath(),
+               EncKeyFilename: encKeyFilename,
+               Version:        ver,
+               SigKeys:        sigKeys,
+       }
+
+       if b.LoaderBuilder != nil {
+               opts.LoaderSrcFilename = b.LoaderBuilder.AppBinPath()
+               opts.LoaderDstFilename = b.LoaderBuilder.AppImgPath()
+       }
+
+       return opts
+}
+
+func ProduceAll(t *builder.TargetBuilder, ver image.ImageVersion,
+       sigKeys []image.ImageSigKey, encKeyFilename string) error {
+
+       popts := OptsFromTgtBldr(t, ver, sigKeys, encKeyFilename)
+       pset, err := ProduceImages(popts)
+       if err != nil {
+               return err
+       }
+
+       mopts := manifest.ManifestCreateOpts{
+               TgtBldr:    t,
+               AppHash:    pset.App.Hash,
+               Version:    ver,
+               BuildID:    fmt.Sprintf("%x", pset.App.Hash),
+               FlashAreas: t.BspPkg().FlashMap.SortedAreas(),
+       }
+
+       if pset.Loader != nil {
+               mopts.LoaderHash = pset.Loader.Hash
+       }
+
+       if err := ProduceManifest(mopts); err != nil {
+               return err
+       }
+
+       if err := verifyImgSizes(pset, mopts.TgtBldr.MaxImgSizes()); err != nil 
{
+               return err
+       }
+
+       return nil
+}
diff --git a/newt/imgprod/v1.go b/newt/imgprod/v1.go
new file mode 100644
index 0000000..37067d4
--- /dev/null
+++ b/newt/imgprod/v1.go
@@ -0,0 +1,218 @@
+package imgprod
+
+import (
+       "fmt"
+       "os"
+       "strings"
+
+       "mynewt.apache.org/newt/artifact/image"
+       "mynewt.apache.org/newt/newt/builder"
+       "mynewt.apache.org/newt/newt/manifest"
+       "mynewt.apache.org/newt/newt/newtutil"
+       "mynewt.apache.org/newt/util"
+)
+
+type ProducedImageV1 struct {
+       Filename string
+       Image    image.ImageV1
+       Hash     []byte
+       FileSize int
+}
+
+type ProducedImageSetV1 struct {
+       Loader *ProducedImageV1
+       App    ProducedImageV1
+}
+
+func produceLoaderV1(opts ImageProdOpts) (ProducedImageV1, error) {
+       pi := ProducedImageV1{}
+
+       igo := image.ImageCreateOpts{
+               SrcBinFilename:    opts.LoaderSrcFilename,
+               SrcEncKeyFilename: opts.EncKeyFilename,
+               Version:           opts.Version,
+               SigKeys:           opts.SigKeys,
+       }
+
+       img, err := image.GenerateV1Image(igo)
+       if err != nil {
+               return pi, err
+       }
+
+       hash, err := img.Hash()
+       if err != nil {
+               return pi, err
+       }
+
+       fileSize, err := img.TotalSize()
+       if err != nil {
+               return pi, err
+       }
+
+       imgFile, err := os.OpenFile(opts.LoaderDstFilename,
+               os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+       if err != nil {
+               return pi, util.FmtNewtError(
+                       "Can't open target image %s: %s",
+                       opts.LoaderDstFilename, err.Error())
+       }
+       defer imgFile.Close()
+
+       if _, err := img.Write(imgFile); err != nil {
+               return pi, err
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT,
+               "V1 loader image successfully generated: %s\n", 
opts.LoaderDstFilename)
+
+       pi.Filename = opts.LoaderDstFilename
+       pi.Image = img
+       pi.Hash = hash
+       pi.FileSize = fileSize
+
+       return pi, nil
+}
+
+func produceAppV1(opts ImageProdOpts,
+       loaderHash []byte) (ProducedImageV1, error) {
+
+       pi := ProducedImageV1{}
+
+       igo := image.ImageCreateOpts{
+               SrcBinFilename:    opts.AppSrcFilename,
+               SrcEncKeyFilename: opts.EncKeyFilename,
+               Version:           opts.Version,
+               SigKeys:           opts.SigKeys,
+               LoaderHash:        loaderHash,
+       }
+
+       img, err := image.GenerateV1Image(igo)
+       if err != nil {
+               return pi, err
+       }
+
+       hash, err := img.Hash()
+       if err != nil {
+               return pi, err
+       }
+
+       fileSize, err := img.TotalSize()
+       if err != nil {
+               return pi, err
+       }
+
+       imgFile, err := os.OpenFile(opts.AppDstFilename,
+               os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
+       if err != nil {
+               return pi, util.FmtNewtError(
+                       "Can't open target image %s: %s", opts.AppDstFilename, 
err.Error())
+       }
+       defer imgFile.Close()
+
+       if _, err := img.Write(imgFile); err != nil {
+               return pi, err
+       }
+
+       util.StatusMessage(util.VERBOSITY_DEFAULT,
+               "App image successfully generated: %s\n", opts.AppDstFilename)
+
+       pi.Filename = opts.AppDstFilename
+       pi.Image = img
+       pi.Hash = hash
+       pi.FileSize = fileSize
+
+       return pi, nil
+}
+
+// Verifies that each already-built image leaves enough room for a boot trailer
+// a the end of its slot.
+func verifyImgSizesV1(pset ProducedImageSetV1, maxSizes []int) error {
+       errLines := []string{}
+       slot := 0
+
+       if pset.Loader != nil {
+               if overflow := int(pset.Loader.FileSize) - maxSizes[0]; 
overflow > 0 {
+                       errLines = append(errLines,
+                               fmt.Sprintf("loader overflows slot-0 by %d 
bytes "+
+                                       "(image=%d max=%d)",
+                                       overflow, pset.Loader.FileSize, 
maxSizes[0]))
+               }
+               slot++
+       }
+
+       if overflow := int(pset.App.FileSize) - maxSizes[slot]; overflow > 0 {
+               errLines = append(errLines,
+                       fmt.Sprintf("app overflows slot-%d by %d bytes "+
+                               "(image=%d max=%d)",
+                               slot, overflow, pset.App.FileSize, 
maxSizes[slot]))
+
+       }
+
+       if len(errLines) > 0 {
+               if !newtutil.NewtForce {
+                       return util.NewNewtError(strings.Join(errLines, "; "))
+               } else {
+                       for _, e := range errLines {
+                               util.StatusMessage(util.VERBOSITY_QUIET,
+                                       "* Warning: %s (ignoring due to force 
flag)\n", e)
+                       }
+               }
+       }
+
+       return nil
+}
+
+func ProduceImagesV1(opts ImageProdOpts) (ProducedImageSetV1, error) {
+       pset := ProducedImageSetV1{}
+
+       var loaderHash []byte
+       if opts.LoaderSrcFilename != "" {
+               pi, err := produceLoaderV1(opts)
+               if err != nil {
+                       return pset, err
+               }
+               loaderHash = pi.Hash
+
+               pset.Loader = &pi
+       }
+
+       pi, err := produceAppV1(opts, loaderHash)
+       if err != nil {
+               return pset, err
+       }
+       pset.App = pi
+
+       return pset, nil
+}
+
+func ProduceAllV1(t *builder.TargetBuilder, ver image.ImageVersion,
+       sigKeys []image.ImageSigKey, encKeyFilename string) error {
+
+       popts := OptsFromTgtBldr(t, ver, sigKeys, encKeyFilename)
+       pset, err := ProduceImagesV1(popts)
+       if err != nil {
+               return err
+       }
+
+       mopts := manifest.ManifestCreateOpts{
+               TgtBldr:    t,
+               AppHash:    pset.App.Hash,
+               Version:    ver,
+               BuildID:    fmt.Sprintf("%x", pset.App.Hash),
+               FlashAreas: t.BspPkg().FlashMap.SortedAreas(),
+       }
+
+       if pset.Loader != nil {
+               mopts.LoaderHash = pset.Loader.Hash
+       }
+
+       if err := ProduceManifest(mopts); err != nil {
+               return err
+       }
+
+       if err := verifyImgSizesV1(pset, mopts.TgtBldr.MaxImgSizes()); err != 
nil {
+               return err
+       }
+
+       return nil
+}

Reply via email to