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 484bbb4729ea39ff616f0758358d6fe833d7fb50
Author: Christopher Collins <ccoll...@apache.org>
AuthorDate: Thu Sep 27 15:18:51 2018 -0700

    Genericize sysinit functionality
    
    Create a `stage` package.  This package emits C code consisting of
    a sequence of function calls.
---
 newt/stage/stage.go     | 204 ++++++++++++++++++++++++++++++++++++++++++++++++
 newt/sysinit/sysinit.go | 163 +++++---------------------------------
 util/util.go            |  17 ++++
 3 files changed, 240 insertions(+), 144 deletions(-)

diff --git a/newt/stage/stage.go b/newt/stage/stage.go
new file mode 100644
index 0000000..ee2dead
--- /dev/null
+++ b/newt/stage/stage.go
@@ -0,0 +1,204 @@
+/**
+ * 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.
+ */
+
+// stage - utility for generating C code consisting of a sequence of function
+// calls ordered by stage number.
+//
+// This package is used by sysinit and sysdown.
+
+package stage
+
+import (
+       "fmt"
+       "io"
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "sort"
+       "strings"
+
+       log "github.com/Sirupsen/logrus"
+
+       "mynewt.apache.org/newt/newt/pkg"
+       "mynewt.apache.org/newt/util"
+)
+
+type StageFunc struct {
+       Stage      int
+       Name       string
+       ReturnType string
+       ArgList    string
+       Pkg        *pkg.LocalPackage
+}
+
+type stageFuncSorter struct {
+       // Used in logging; either "sysinit" or "sysdown".
+       funcType string
+       // Array of functions to be sorted.
+       fns []StageFunc
+}
+
+func (s stageFuncSorter) Len() int {
+       return len(s.fns)
+}
+
+func (s stageFuncSorter) Swap(i, j int) {
+       s.fns[i], s.fns[j] = s.fns[j], s.fns[i]
+}
+
+func (s stageFuncSorter) Less(i, j int) bool {
+       a := s.fns[i]
+       b := s.fns[j]
+
+       // 1: Sort by stage number.
+       if a.Stage < b.Stage {
+               return true
+       } else if b.Stage < a.Stage {
+               return false
+       }
+
+       // 2: Sort by function name.
+       switch strings.Compare(a.Name, b.Name) {
+       case -1:
+               return true
+       case 1:
+               return false
+       }
+
+       // Same stage and function name?
+       log.Warnf("Warning: Identical %s functions detected: %s",
+               s.funcType, a.Name)
+
+       return true
+}
+
+// SortStageFuncs performs an in-place sort of the provided StageFunc slice.
+func SortStageFuncs(unsorted []StageFunc, funcType string) {
+       s := stageFuncSorter{
+               funcType: funcType,
+               fns:      unsorted,
+       }
+
+       sort.Sort(s)
+}
+
+func (f *StageFunc) ReturnTypeString() string {
+       if f.ReturnType == "" {
+               return "void"
+       } else {
+               return f.ReturnType
+       }
+}
+
+func (f *StageFunc) ArgListString() string {
+       if f.ArgList == "" {
+               return "void"
+       } else {
+               return f.ArgList
+       }
+}
+
+// WriteCalls emits C code: a list of function prototypes corresponding to the
+// provided slice of stage functions.
+func WritePrototypes(sortedFns []StageFunc, w io.Writer) {
+       for _, f := range sortedFns {
+               fmt.Fprintf(w, "%s %s(%s);\n",
+                       f.ReturnTypeString(), f.Name, f.ArgListString())
+       }
+}
+
+// WriteCalls emits C code: a sequence of function calls corresponding to the
+// provided slice of stage functions.
+func WriteCalls(sortedFuncs []StageFunc, argList string, w io.Writer) {
+       prevStage := -1
+       dupCount := 0
+
+       for i, f := range sortedFuncs {
+               if f.Stage != prevStage {
+                       prevStage = f.Stage
+                       dupCount = 0
+
+                       if i != 0 {
+                               fmt.Fprintf(w, "\n")
+                       }
+                       fmt.Fprintf(w, "    /*** Stage %d */\n", f.Stage)
+               } else {
+                       dupCount += 1
+               }
+
+               fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
+                       f.Stage, dupCount, f.Name, f.Pkg.Name())
+               fmt.Fprintf(w, "    %s(%s);\n", f.Name, argList)
+       }
+}
+
+// WriteArr emits C code: an array body of function pointers represented by the
+// supplied slice.  The caller must 1) write the array declaration before
+// calling this function, and 2) write "};" afterwards.
+func WriteArr(sortedFuncs []StageFunc, w io.Writer) {
+       prevStage := -1
+       dupCount := 0
+
+       for i, f := range sortedFuncs {
+               if f.Stage != prevStage {
+                       prevStage = f.Stage
+                       dupCount = 0
+
+                       if i != 0 {
+                               fmt.Fprintf(w, "\n")
+                       }
+                       fmt.Fprintf(w, "    /*** Stage %d */\n", f.Stage)
+               } else {
+                       dupCount += 1
+               }
+
+               fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
+                       f.Stage, dupCount, f.Name, f.Pkg.Name())
+               fmt.Fprintf(w, "    %s,\n", f.Name)
+       }
+       fmt.Fprintf(w, "\n")
+       fmt.Fprintf(w, "    /*** Array terminator. */\n")
+       fmt.Fprintf(w, "    0\n")
+}
+
+// EnsureWritten writes the specified file if its contents differ from those of
+// the supplied byte slice.
+func EnsureWritten(path string, contents []byte) error {
+       unchanged, err := util.FileContains(contents, path)
+       if err != nil {
+               return err
+       }
+
+       if unchanged {
+               log.Debugf("file unchanged; not writing src file (%s).", path)
+               return nil
+       }
+
+       log.Debugf("file changed; writing src file (%s).", path)
+
+       if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+               return util.NewNewtError(err.Error())
+       }
+
+       if err := ioutil.WriteFile(path, contents, 0644); err != nil {
+               return util.NewNewtError(err.Error())
+       }
+
+       return nil
+}
diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go
index 4071a09..98e7fc6 100644
--- a/newt/sysinit/sysinit.go
+++ b/newt/sysinit/sysinit.go
@@ -23,125 +23,33 @@ import (
        "bytes"
        "fmt"
        "io"
-       "io/ioutil"
-       "os"
-       "path/filepath"
-       "sort"
-       "strings"
-
-       log "github.com/Sirupsen/logrus"
 
        "mynewt.apache.org/newt/newt/newtutil"
        "mynewt.apache.org/newt/newt/pkg"
-       "mynewt.apache.org/newt/util"
+       "mynewt.apache.org/newt/newt/stage"
 )
 
-type initFunc struct {
-       stage int
-       name  string
-       pkg   *pkg.LocalPackage
-}
-
-func buildStageMap(pkgs []*pkg.LocalPackage) map[int][]*initFunc {
-       sm := map[int][]*initFunc{}
-
-       for _, p := range pkgs {
-               for name, stage := range p.Init() {
-                       initFunc := &initFunc{
-                               stage: stage,
-                               name:  name,
-                               pkg:   p,
-                       }
-                       sm[stage] = append(sm[stage], initFunc)
-               }
-       }
-
-       return sm
-}
-
-type initFuncSorter struct {
-       fns []*initFunc
-}
-
-func (s initFuncSorter) Len() int {
-       return len(s.fns)
-}
-func (s initFuncSorter) Swap(i, j int) {
-       s.fns[i], s.fns[j] = s.fns[j], s.fns[i]
-}
-func (s initFuncSorter) Less(i, j int) bool {
-       a := s.fns[i]
-       b := s.fns[j]
-
-       // 1: Sort by stage number.
-       if a.stage < b.stage {
-               return true
-       } else if b.stage < a.stage {
-               return false
-       }
-
-       // 2: Sort by function name.
-       switch strings.Compare(a.name, b.name) {
-       case -1:
-               return true
-       case 1:
-               return false
-       }
-
-       // Same stage and function name?
-       log.Warnf("Warning: Identical sysinit functions detected: %s", a.name)
-       return true
-}
-
-func sortedInitFuncs(pkgs []*pkg.LocalPackage) []*initFunc {
-       sorter := initFuncSorter{
-               fns: make([]*initFunc, 0, len(pkgs)),
-       }
-
+func initFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
+       fns := make([]stage.StageFunc, 0, len(pkgs))
        for _, p := range pkgs {
                initMap := p.Init()
-               for name, stage := range initMap {
-                       fn := &initFunc{
-                               name:  name,
-                               stage: stage,
-                               pkg:   p,
+               for name, stageNum := range initMap {
+                       fn := stage.StageFunc{
+                               Name:  name,
+                               Stage: stageNum,
+                               Pkg:   p,
                        }
-                       sorter.fns = append(sorter.fns, fn)
+                       fns = append(fns, fn)
                }
        }
 
-       sort.Sort(sorter)
-       return sorter.fns
-}
-
-func writePrototypes(pkgs []*pkg.LocalPackage, w io.Writer) {
-       sortedFns := sortedInitFuncs(pkgs)
-       for _, f := range sortedFns {
-               fmt.Fprintf(w, "void %s(void);\n", f.name)
-       }
+       return fns
 }
 
-func writeCalls(sortedInitFuncs []*initFunc, w io.Writer) {
-       prevStage := -1
-       dupCount := 0
-
-       for i, f := range sortedInitFuncs {
-               if f.stage != prevStage {
-                       prevStage = f.stage
-                       dupCount = 0
-
-                       if i != 0 {
-                               fmt.Fprintf(w, "\n")
-                       }
-                       fmt.Fprintf(w, "    /*** Stage %d */\n", f.stage)
-               } else {
-                       dupCount += 1
-               }
-
-               fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
-                       f.stage, dupCount, f.name, f.pkg.Name())
-               fmt.Fprintf(w, "    %s();\n", f.name)
-       }
+func sortedInitFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
+       fns := initFuncs(pkgs)
+       stage.SortStageFuncs(fns, "sysinit")
+       return fns
 }
 
 func write(pkgs []*pkg.LocalPackage, isLoader bool,
@@ -155,7 +63,9 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
                fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n")
        }
 
-       writePrototypes(pkgs, w)
+       fns := sortedInitFuncs(pkgs)
+
+       stage.WritePrototypes(fns, w)
 
        var fnName string
        if isLoader {
@@ -167,27 +77,12 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
        fmt.Fprintf(w, "\n")
        fmt.Fprintf(w, "void\n%s(void)\n{\n", fnName)
 
-       writeCalls(sortedInitFuncs(pkgs), w)
+       stage.WriteCalls(fns, "", w)
 
        fmt.Fprintf(w, "}\n\n")
        fmt.Fprintf(w, "#endif\n")
 }
 
-func writeRequired(contents []byte, path string) (bool, error) {
-       oldSrc, err := ioutil.ReadFile(path)
-       if err != nil {
-               if os.IsNotExist(err) {
-                       // File doesn't exist; write required.
-                       return true, nil
-               }
-
-               return true, util.NewNewtError(err.Error())
-       }
-
-       rc := bytes.Compare(oldSrc, contents)
-       return rc != 0, nil
-}
-
 func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
        isLoader bool) error {
 
@@ -201,25 +96,5 @@ func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, 
targetName string,
                path = fmt.Sprintf("%s/%s-sysinit-app.c", srcDir, targetName)
        }
 
-       writeReqd, err := writeRequired(buf.Bytes(), path)
-       if err != nil {
-               return err
-       }
-
-       if !writeReqd {
-               log.Debugf("sysinit unchanged; not writing src file (%s).", 
path)
-               return nil
-       }
-
-       log.Debugf("sysinit changed; writing src file (%s).", path)
-
-       if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
-               return util.NewNewtError(err.Error())
-       }
-
-       if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
-               return util.NewNewtError(err.Error())
-       }
-
-       return nil
+       return stage.EnsureWritten(path, buf.Bytes())
 }
diff --git a/util/util.go b/util/util.go
index e848642..d3abfc3 100644
--- a/util/util.go
+++ b/util/util.go
@@ -696,3 +696,20 @@ func StringMapStringToItfMapItf(
 
        return imi
 }
+
+// FileContains indicates whether the specified file's contents are equal to
+// the provided byte slice.
+func FileContains(contents []byte, path string) (bool, error) {
+       oldSrc, err := ioutil.ReadFile(path)
+       if err != nil {
+               if os.IsNotExist(err) {
+                       // File doesn't exist; contents aren't equal.
+                       return false, nil
+               }
+
+               return false, NewNewtError(err.Error())
+       }
+
+       rc := bytes.Compare(oldSrc, contents)
+       return rc == 0, nil
+}

Reply via email to