summaryrefslogtreecommitdiff
diff options
authorMichael Vogt <mvo@ubuntu.com>2020-08-13 12:32:15 +0200
committerMichael Vogt <mvo@ubuntu.com>2020-08-13 12:47:27 +0200
commit23715d465acafcebdc7b5b26415f215c6f7469b2 (patch)
tree6a4acd903aae074aae8ac1cc2d353e5f573f0c0f
parent61e7981d3b01635d1bff7a4401562d73ed979268 (diff)
gadget,kernel: add new "kernel" and "gadget/edition" packages
This commit moves the kernel.yaml parsing into the kernel package and extracts the gadget:editionNumber" helper into it's own gadget/editon packages so that it can be shared between the kernel and the gadget packages. Because meta/kernel.yaml is optional it is not an error if it is missing. Extra tests are also added.
-rw-r--r--gadget/edition/number.go42
-rw-r--r--gadget/edition/number_test.go69
-rw-r--r--gadget/gadget.go22
-rw-r--r--kernel/kernel.go (renamed from gadget/kernel.go)32
-rw-r--r--kernel/kernel_test.go (renamed from gadget/kernel_test.go)42
5 files changed, 162 insertions, 45 deletions
diff --git a/gadget/edition/number.go b/gadget/edition/number.go
new file mode 100644
index 0000000000..448b72cf3a
--- /dev/null
+++ b/gadget/edition/number.go
@@ -0,0 +1,42 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2020 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package edition
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+)
+
+type Number uint32
+
+func (e *Number) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var es string
+ if err := unmarshal(&es); err != nil {
+ return errors.New(`cannot unmarshal "edition"`)
+ }
+
+ u, err := strconv.ParseUint(es, 10, 32)
+ if err != nil {
+ return fmt.Errorf(`"edition" must be a positive number, not %q`, es)
+ }
+ *e = Number(u)
+ return nil
+}
diff --git a/gadget/edition/number_test.go b/gadget/edition/number_test.go
new file mode 100644
index 0000000000..30cfc184cb
--- /dev/null
+++ b/gadget/edition/number_test.go
@@ -0,0 +1,69 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2020 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package edition_test
+
+import (
+ "testing"
+
+ . "gopkg.in/check.v1"
+ "gopkg.in/yaml.v2"
+
+ "github.com/snapcore/snapd/gadget/edition"
+)
+
+type editionSuite struct{}
+
+var _ = Suite(&editionSuite{})
+
+func TestCommand(t *testing.T) { TestingT(t) }
+
+var mockEditionYaml = []byte(`
+foo:
+ edition: 1
+`)
+
+func (s *editionSuite) TestUnmarshalIntegration(c *C) {
+ type editionStruct struct {
+ Edition edition.Number `yaml:"edition"`
+ }
+
+ for _, tc := range []struct {
+ input string
+ expectedNumber edition.Number
+ expectedErr string
+ }{
+ {"edition: 1", edition.Number(1), ""},
+ {"edition: 0", edition.Number(0), ""},
+ {"edition: 9999999", edition.Number(9999999), ""},
+ {"edition: -1", edition.Number(0), `"edition" must be a positive number, not "-1"`},
+ {"edition: random-string", edition.Number(0), `"edition" must be a positive number, not "random-string"`},
+ {"edition: NaN", edition.Number(0), `"edition" must be a positive number, not "NaN"`},
+ {"edition: 3.14", edition.Number(0), `"edition" must be a positive number, not "3.14"`},
+ } {
+ var en editionStruct
+ err := yaml.Unmarshal([]byte(tc.input), &en)
+ if tc.expectedErr != "" {
+ c.Assert(err, ErrorMatches, tc.expectedErr, Commentf(tc.input))
+ } else {
+ c.Assert(err, IsNil, Commentf(tc.input))
+ c.Check(en.Edition, Equals, tc.expectedNumber, Commentf(tc.input))
+ }
+ }
+}
diff --git a/gadget/gadget.go b/gadget/gadget.go
index 54415a0fff..f860f2cfa3 100644
--- a/gadget/gadget.go
+++ b/gadget/gadget.go
@@ -28,12 +28,12 @@ import (
"path/filepath"
"regexp"
"sort"
- "strconv"
"strings"
"gopkg.in/yaml.v2"
"github.com/snapcore/snapd/asserts"
+ "github.com/snapcore/snapd/gadget/edition"
"github.com/snapcore/snapd/metautil"
"github.com/snapcore/snapd/snap"
"github.com/snapcore/snapd/snap/naming"
@@ -206,8 +206,8 @@ func (vc VolumeContent) String() string {
}
type VolumeUpdate struct {
- Edition editionNumber `yaml:"edition"`
- Preserve []string `yaml:"preserve"`
+ Edition edition.Number `yaml:"edition"`
+ Preserve []string `yaml:"preserve"`
}
// GadgetConnect describes an interface connection requested by the gadget
@@ -787,22 +787,6 @@ func validateStructureUpdate(up *VolumeUpdate, vs *VolumeStructure) error {
return nil
}
-type editionNumber uint32
-
-func (e *editionNumber) UnmarshalYAML(unmarshal func(interface{}) error) error {
- var es string
- if err := unmarshal(&es); err != nil {
- return errors.New(`cannot unmarshal "edition"`)
- }
-
- u, err := strconv.ParseUint(es, 10, 32)
- if err != nil {
- return fmt.Errorf(`"edition" must be a positive number, not %q`, es)
- }
- *e = editionNumber(u)
- return nil
-}
-
// Size describes the size of a structure item or an offset within the
// structure.
type Size uint64
diff --git a/gadget/kernel.go b/kernel/kernel.go
index e22744371f..0a9a9f95f5 100644
--- a/gadget/kernel.go
+++ b/kernel/kernel.go
@@ -17,30 +17,31 @@
*
*/
-package gadget
+package kernel
import (
"fmt"
"io/ioutil"
+ "os"
"path/filepath"
"gopkg.in/yaml.v2"
-)
-// XXX: should this be in a "gadget/kernel" or "kernel" package?
+ "github.com/snapcore/snapd/gadget/edition"
+)
-type KernelAsset struct {
- Edition editionNumber `yaml:"edition,omitempty"`
- Content []string `yaml:"content,omitempty"`
+type Asset struct {
+ Edition edition.Number `yaml:"edition,omitempty"`
+ Content []string `yaml:"content,omitempty"`
}
-type KernelInfo struct {
- Assets map[string]*KernelAsset `yaml:"assets,omitempty"`
+type Info struct {
+ Assets map[string]*Asset `yaml:"assets,omitempty"`
}
-// KernelInfoFromKernelYaml reads the provided kernel metadata.
-func KernelInfoFromKernelYaml(kernelYaml []byte) (*KernelInfo, error) {
- var ki KernelInfo
+// InfoFromKernelYaml reads the provided kernel metadata.
+func InfoFromKernelYaml(kernelYaml []byte) (*Info, error) {
+ var ki Info
if err := yaml.Unmarshal(kernelYaml, &ki); err != nil {
return nil, fmt.Errorf("cannot parse kernel metadata: %v", err)
@@ -51,11 +52,16 @@ func KernelInfoFromKernelYaml(kernelYaml []byte) (*KernelInfo, error) {
// ReadInfo reads the kernel specific metadata from meta/kernel.yaml
// in the snap root directory.
-func ReadKernelInfo(kernelSnapRootDir string) (*KernelInfo, error) {
+func ReadInfo(kernelSnapRootDir string) (*Info, error) {
p := filepath.Join(kernelSnapRootDir, "meta", "kernel.yaml")
content, err := ioutil.ReadFile(p)
+ // meta/kernel.yaml is optional so we should not error here if
+ // it is missing
+ if os.IsNotExist(err) {
+ return &Info{}, nil
+ }
if err != nil {
return nil, fmt.Errorf("cannot read kernel info: %v", err)
}
- return KernelInfoFromKernelYaml(content)
+ return InfoFromKernelYaml(content)
}
diff --git a/gadget/kernel_test.go b/kernel/kernel_test.go
index f606f0aa61..aef51ee600 100644
--- a/gadget/kernel_test.go
+++ b/kernel/kernel_test.go
@@ -17,22 +17,25 @@
*
*/
-package gadget_test
+package kernel_test
import (
"io/ioutil"
"os"
"path/filepath"
+ "testing"
. "gopkg.in/check.v1"
- "github.com/snapcore/snapd/gadget"
+ "github.com/snapcore/snapd/kernel"
)
type kernelYamlTestSuite struct{}
var _ = Suite(&kernelYamlTestSuite{})
+func TestCommand(t *testing.T) { TestingT(t) }
+
var mockKernelYaml = []byte(`
assets:
dtbs:
@@ -43,17 +46,17 @@ assets:
`)
func (s *kernelYamlTestSuite) TestInfoFromKernelYamlSad(c *C) {
- ki, err := gadget.KernelInfoFromKernelYaml([]byte("foo"))
+ ki, err := kernel.InfoFromKernelYaml([]byte("foo"))
c.Check(err, ErrorMatches, "(?m)cannot parse kernel metadata: .*")
c.Check(ki, IsNil)
}
func (s *kernelYamlTestSuite) TestInfoFromKernelYamlHappy(c *C) {
- ki, err := gadget.KernelInfoFromKernelYaml(mockKernelYaml)
+ ki, err := kernel.InfoFromKernelYaml(mockKernelYaml)
c.Check(err, IsNil)
- c.Check(ki, DeepEquals, &gadget.KernelInfo{
- Assets: map[string]*gadget.KernelAsset{
- "dtbs": &gadget.KernelAsset{
+ c.Check(ki, DeepEquals, &kernel.Info{
+ Assets: map[string]*kernel.Asset{
+ "dtbs": &kernel.Asset{
Edition: 1,
Content: []string{
"dtbs/bcm2711-rpi-4-b.dtb",
@@ -64,9 +67,22 @@ func (s *kernelYamlTestSuite) TestInfoFromKernelYamlHappy(c *C) {
})
}
+func (s *kernelYamlTestSuite) TestReadKernelYamlOptional(c *C) {
+ ki, err := kernel.ReadInfo("this-path-does-not-exist")
+ c.Check(err, IsNil)
+ c.Check(ki, DeepEquals, &kernel.Info{})
+}
+
func (s *kernelYamlTestSuite) TestReadKernelYamlSad(c *C) {
- ki, err := gadget.ReadKernelInfo("this-path-does-not-exist")
- c.Check(err, ErrorMatches, `cannot read kernel info: open this-path-does-not-exist/meta/kernel.yaml: no such file or directory`)
+ mockKernelSnapRoot := c.MkDir()
+ kernelYamlPath := filepath.Join(mockKernelSnapRoot, "meta/kernel.yaml")
+ err := os.MkdirAll(filepath.Dir(kernelYamlPath), 0755)
+ c.Assert(err, IsNil)
+ err = ioutil.WriteFile(kernelYamlPath, []byte(`invalid-kernel-yaml`), 0644)
+ c.Assert(err, IsNil)
+
+ ki, err := kernel.ReadInfo(mockKernelSnapRoot)
+ c.Check(err, ErrorMatches, `(?m)cannot parse kernel metadata: yaml: unmarshal errors:.*`)
c.Check(ki, IsNil)
}
@@ -78,11 +94,11 @@ func (s *kernelYamlTestSuite) TestReadKernelYamlHappy(c *C) {
err = ioutil.WriteFile(kernelYamlPath, mockKernelYaml, 0644)
c.Assert(err, IsNil)
- ki, err := gadget.ReadKernelInfo(mockKernelSnapRoot)
+ ki, err := kernel.ReadInfo(mockKernelSnapRoot)
c.Assert(err, IsNil)
- c.Check(ki, DeepEquals, &gadget.KernelInfo{
- Assets: map[string]*gadget.KernelAsset{
- "dtbs": &gadget.KernelAsset{
+ c.Check(ki, DeepEquals, &kernel.Info{
+ Assets: map[string]*kernel.Asset{
+ "dtbs": &kernel.Asset{
Edition: 1,
Content: []string{
"dtbs/bcm2711-rpi-4-b.dtb",