diff options
| author | Michael Vogt <mvo@ubuntu.com> | 2020-08-13 12:32:15 +0200 |
|---|---|---|
| committer | Michael Vogt <mvo@ubuntu.com> | 2020-08-13 12:47:27 +0200 |
| commit | 23715d465acafcebdc7b5b26415f215c6f7469b2 (patch) | |
| tree | 6a4acd903aae074aae8ac1cc2d353e5f573f0c0f | |
| parent | 61e7981d3b01635d1bff7a4401562d73ed979268 (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.go | 42 | ||||
| -rw-r--r-- | gadget/edition/number_test.go | 69 | ||||
| -rw-r--r-- | gadget/gadget.go | 22 | ||||
| -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", |
