Merge lp:~snappy-dev/goget-ubuntu-touch/all-snaps into lp:goget-ubuntu-touch

Proposed by Michael Vogt on 2015-10-22
Status: Needs review
Proposed branch: lp:~snappy-dev/goget-ubuntu-touch/all-snaps
Merge into: lp:goget-ubuntu-touch
Diff against target: 1882 lines (+1243/-150) (has conflicts)
14 files modified
debian/changelog (+15/-0)
debian/control (+14/-0)
dependencies.tsv (+6/-1)
diskimage/bootloader.go (+21/-12)
diskimage/common.go (+99/-69)
diskimage/common_test.go (+14/-14)
diskimage/core_grub.go (+31/-27)
diskimage/core_uboot.go (+32/-16)
diskimage/partition.go (+1/-0)
ubuntu-device-flash/common.go (+3/-3)
ubuntu-device-flash/core.go (+12/-5)
ubuntu-device-flash/helpers.go (+89/-0)
ubuntu-device-flash/helpers_test.go (+135/-0)
ubuntu-device-flash/snappy.go (+771/-3)
Text conflict in debian/changelog
Text conflict in debian/control
Text conflict in dependencies.tsv
Text conflict in diskimage/bootloader.go
Text conflict in diskimage/common.go
Text conflict in diskimage/core_grub.go
Text conflict in diskimage/core_uboot.go
Text conflict in ubuntu-device-flash/core.go
Text conflict in ubuntu-device-flash/snappy.go
To merge this branch: bzr merge lp:~snappy-dev/goget-ubuntu-touch/all-snaps
Reviewer Review Type Date Requested Status
Sergio Schvezov 2015-10-22 Approve on 2016-03-30
Review via email: mp+275273@code.launchpad.net

Commit message

Add support to build all-snaps images.

Description of the change

Add support to build all-snaps images.

To post a comment you must log in.
Michael Vogt (mvo) wrote :

Just added some comments so that we don't forget them :)

Sergio Schvezov (sergiusens) wrote :
Download full text (7.0 KiB)

On Oct 22, 2015 4:28 AM, "Michael Vogt" <email address hidden> wrote:
>
> Just added some comments so that we don't forget them :)
>
> Diff comments:
>
> > === modified file 'diskimage/common.go'
> > --- diskimage/common.go 2015-09-09 14:36:46 +0000
> > +++ diskimage/common.go 2015-10-22 07:16:55 +0000
> > @@ -190,16 +190,19 @@
> >
> > // BaseImage implements the basic primitives to manage images.
> > type BaseImage struct {
> > - baseMount string
> > - hardware HardwareDescription
> > - location string
> > - oem OemDescription
> > - parts []partition
> > - partCount int
> > - size int64
> > - rootSize int
> > + baseMount string
> > + bindMounts []string
> > + hardware HardwareDescription
> > + location string
> > + oem OemDescription
> > + parts []partition
> > + partCount int
> > + size int64
> > + rootSize int
> > }
> >
> > +var bindMounts = []string{"dev", "sys", "proc", filepath.Join("sys",
"firmware")}
>
> It looks like we are doing this twice (once here, once in snappy).

You will see a bunch of these little things which could go away when
migrating the provisioner into snappy itself.
>
> > +
> > // Mount mounts the image. This also maps the loop device.
> > func (img *BaseImage) Mount() error {
> > if err := img.doMap(); err != nil {
> >
> > === modified file 'ubuntu-device-flash/snappy.go'
> > --- ubuntu-device-flash/snappy.go 2015-09-16 11:13:20 +0000
> > +++ ubuntu-device-flash/snappy.go 2015-10-22 07:16:55 +0000
> > @@ -339,7 +343,21 @@
> > return hw, err
> > }
> >
> > -func (s *Snapper) setup(filePathChan <-chan string, fileCount int)
error {
> > +func (s *Snapper) bindMount(d string) (string, error) {
>
> I gues the name could be better, something like bindMountInWritable or so
>
> > + src := filepath.Join(s.img.Writable(), "system-data", d)
> > + dst := filepath.Join(s.img.System(), d)
> > +
> > + if err := os.MkdirAll(src, 0755); err != nil {
> > + return "", err
> > + }
> > + cmd := exec.Command("mount", "--bind", src, dst)
> > + if o, err := cmd.CombinedOutput(); err != nil {
> > + return "", fmt.Errorf("os snap mount failed with: %s %v
", err, string(o))
> > + }
> > + return dst, nil
> > +}
> > +
> > +func (s *Snapper) setup(systemImageFiles []Files) error {
> > printOut("Mounting...")
> > if err := s.img.Mount(); err != nil {
> > return err
> > @@ -362,14 +379,82 @@
> >
> > systemPath := s.img.System()
> >
> > + // setup a fake system
> > + if s.oem.PartitionLayout() == "minimal" {
> > + if err := os.MkdirAll(systemPath, 0755); err != nil {
> > + return err
> > + }
> > + // mount os snap
> > + cmd := exec.Command("mount", s.OS, systemPath)
> > + if o, err := cmd.CombinedOutput(); err != nil {
> > + return fmt.Errorf("os snap mount failed with: %s
%v ", err, string(o))
> > + }
> > + defer exec.Command("umount", systemPath).Run()
> > +
> > + //...

Read more...

Sergio Schvezov (sergiusens) wrote :

Thanks for this, it removes a bunch of legacy. I added a couple of inline comments, nothing major.

MPs like this https://code.launchpad.net/~sil2100/goget-ubuntu-touch/touch-devel-warning/+merge/282045 make me think we need to fork though since this will be expected to go all the way to trusty.

review: Needs Fixing
Michael Vogt (mvo) wrote :

This is updated and all comments are addressed now.

review: Approve
Snappy Tarmac (snappydevtarmac) wrote :
Download full text (3.6 KiB)

The attempt to merge lp:~snappy-dev/goget-ubuntu-touch/all-snaps into lp:goget-ubuntu-touch failed. Below is the output from the failed tests.

Checking formatting
Installing godeps
Install golint
Obtaining dependencies
update launchpad.net/gocheck failed; trying to fetch newer version
launchpad.net/gocheck now at <email address hidden>
update github.com/mvo5/goconfigparser failed; trying to fetch newer version
github.com/mvo5/goconfigparser now at 26426272dda20cc76aa1fa44286dc743d2972fe8
update github.com/cheggaaa/pb failed; trying to fetch newer version
github.com/cheggaaa/pb now at da1f27ad1d9509b16f65f52fd9d8138b0f2dc7b2
update github.com/gosexy/gettext failed; trying to fetch newer version
github.com/gosexy/gettext now at 98b7b91596d20b96909e6b60d57411547dd9959c
update github.com/jessevdk/go-flags failed; trying to fetch newer version
github.com/jessevdk/go-flags now at 4047bd797dd935ae2b557a79cc43f223066c9659
update github.com/ubuntu-core/snappy failed; trying to fetch newer version
github.com/ubuntu-core/snappy now at a6e683cb4eca7027b331713c2f10e26a31050f20
update github.com/mvo5/uboot-go failed; trying to fetch newer version
github.com/mvo5/uboot-go now at 69978a3e4b05cca9d7cfee489b3453dfed45e72c
update gopkg.in/yaml.v2 failed; trying to fetch newer version
gopkg.in/yaml.v2 now at 7ad95dd0798a40da1ccdff6dff35fd177b5edf40
Building

# we always run in a fresh dir in tarmac
export GOPATH=$(mktemp -d)
trap 'rm -rf "$GOPATH"' EXIT

# this is a hack, but not sure tarmac is golang friendly
mkdir -p $GOPATH/src/launchpad.net/goget-ubuntu-touch
cp -a . $GOPATH/src/launchpad.net/goget-ubuntu-touch
cd $GOPATH/src/launchpad.net/goget-ubuntu-touch

./run-checks
launchpad.net/goget-ubuntu-touch/bootimg
launchpad.net/goget-ubuntu-touch/devices
launchpad.net/goget-ubuntu-touch/bootimg/example/abootimg-extract
launchpad.net/goget-ubuntu-touch/sysutils
launchpad.net/goget-ubuntu-touch/diskimage
github.com/jessevdk/go-flags
github.com/cheggaaa/pb
launchpad.net/goget-ubuntu-touch/ubuntuimage
github.com/ubuntu-core/snappy/arch
github.com/ubuntu-core/snappy/dirs
launchpad.net/goget-ubuntu-touch/ubuntu-device-do
github.com/ubuntu-core/snappy/osutil
github.com/mvo5/goconfigparser
github.com/mvo5/uboot-go/uenv
github.com/ubuntu-core/snappy/logger
github.com/ubuntu-core/snappy/helpers
github.com/ubuntu-core/snappy/partition
github.com/ubuntu-core/snappy/progress
gopkg.in/yaml.v2
github.com/ubuntu-core/snappy/release
github.com/ubuntu-core/snappy/systemd
github.com/gosexy/gettext
github.com/ubuntu-core/snappy/i18n
github.com/ubuntu-core/snappy/oauth
github.com/ubuntu-core/snappy/policy
github.com/ubuntu-core/snappy/timeout
launchpad.net/goget-ubuntu-touch/ubuntu-emulator
github.com/ubuntu-core/snappy/provisioning
github.com/ubuntu-core/snappy/snap
github.com/ubuntu-core/snappy/coreconfig
github.com/ubuntu-core/snappy/snap/remote
github.com/ubuntu-core/snappy/snap/squashfs
github.com/ubuntu-core/snappy/snappy
launchpad.net/goget-ubuntu-touch/ubuntu-device-flash
# launchpad.net/goget-ubuntu-touch/ubuntu-device-flash
ubuntu-device-flash/helpers.go:42: undefined: osutil.FileExists
ubuntu-device-flash/helpers.go:76: undefined: osutil....

Read more...

264. By Sergio Schvezov on 2016-04-01

Update to latest snappy code

265. By Michael Vogt on 2016-04-06

ppa uploads

266. By Michael Vogt on 2016-04-09

fix bind mounts

267. By Michael Vogt on 2016-04-15

update to the latest api

268. By Michael Vogt on 2016-04-18

manually enable all snaps on the system

269. By Michael Vogt on 2016-04-19

remove debug code

270. By Michael Vogt on 2016-04-19

update for latest snappy

271. By Michael Vogt on 2016-04-26

add check for having systemctl

272. By Michael Vogt on 2016-04-27

set snappy_{,good}_{kernel,os} to fix LP:#1534137

273. By Michael Vogt on 2016-05-02

fix squashfs format issue

274. By Michael Vogt on 2016-05-04

use gadget snap whitelist in preparation for the rework of the gadget yaml

275. By Michael Vogt on 2016-05-04

merged lp:~pedronis/goget-ubuntu-touch/use-read-info-from-snapfile

276. By Michael Vogt on 2016-05-10

fix for latest api change

Unmerged revisions

276. By Michael Vogt on 2016-05-10

fix for latest api change

275. By Michael Vogt on 2016-05-04

merged lp:~pedronis/goget-ubuntu-touch/use-read-info-from-snapfile

274. By Michael Vogt on 2016-05-04

use gadget snap whitelist in preparation for the rework of the gadget yaml

273. By Michael Vogt on 2016-05-02

fix squashfs format issue

272. By Michael Vogt on 2016-04-27

set snappy_{,good}_{kernel,os} to fix LP:#1534137

271. By Michael Vogt on 2016-04-26

add check for having systemctl

270. By Michael Vogt on 2016-04-19

update for latest snappy

269. By Michael Vogt on 2016-04-19

remove debug code

268. By Michael Vogt on 2016-04-18

manually enable all snaps on the system

267. By Michael Vogt on 2016-04-15

update to the latest api

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2016-04-05 10:22:02 +0000
3+++ debian/changelog 2016-05-10 18:32:26 +0000
4@@ -1,3 +1,4 @@
5+<<<<<<< TREE
6 goget-ubuntu-touch (0.34-0ubuntu1) xenial; urgency=medium
7
8 [ Ondrej Kubik ]
9@@ -19,6 +20,20 @@
10
11 -- Sergio Schvezov <sergio.schvezov@canonical.com> Wed, 18 Nov 2015 09:32:39 -0300
12
13+=======
14+goget-ubuntu-touch (0.34-0ubuntu1+ppa2) xenial; urgency=medium
15+
16+ * add missing golang-golang-x-crypto-dev b-d
17+
18+ -- Michael Vogt <michael.vogt@ubuntu.com> Wed, 06 Apr 2016 18:06:31 +0200
19+
20+goget-ubuntu-touch (0.34-0ubuntu1+ppa1) xenial; urgency=medium
21+
22+ * ppa upload of the all-snaps branch
23+
24+ -- Michael Vogt <michael.vogt@ubuntu.com> Wed, 06 Apr 2016 17:58:42 +0200
25+
26+>>>>>>> MERGE-SOURCE
27 goget-ubuntu-touch (0.33-0ubuntu1) xenial; urgency=medium
28
29 * Exit 1 on parameter errors (LP: #1473333)
30
31=== modified file 'debian/control'
32--- debian/control 2016-04-05 07:51:47 +0000
33+++ debian/control 2016-05-10 18:32:26 +0000
34@@ -9,9 +9,23 @@
35 golang-gettext-dev,
36 golang-go-flags-dev,
37 golang-gocheck-dev,
38+<<<<<<< TREE
39+=======
40+ golang-github-mvo5-goconfigparser-dev,
41+>>>>>>> MERGE-SOURCE
42 golang-juju-loggo-dev,
43 golang-pb-dev,
44+<<<<<<< TREE
45+=======
46+ golang-github-ubuntu-core-snappy-dev,
47+ golang-github-mvo5-uboot-go-dev,
48+>>>>>>> MERGE-SOURCE
49 golang-yaml.v2-dev,
50+<<<<<<< TREE
51+=======
52+ golang-golang-x-crypto-dev,
53+ ubuntu-snappy-cli,
54+>>>>>>> MERGE-SOURCE
55 Standards-Version: 3.9.5
56 Homepage: https://launchpad.net/goget-ubuntu-touch
57 Vcs-Browser: http://bazaar.launchpad.net/~phablet-team/goget-ubuntu-touch/trunk/files
58
59=== modified file 'dependencies.tsv'
60--- dependencies.tsv 2016-04-04 15:54:40 +0000
61+++ dependencies.tsv 2016-05-10 18:32:26 +0000
62@@ -1,6 +1,11 @@
63-github.com/blakesmith/ar git 8bd4349a67f2533b078dbc524689d15dba0f4659 2015-03-11T14:59:44Z
64 github.com/cheggaaa/pb git da1f27ad1d9509b16f65f52fd9d8138b0f2dc7b2 2015-08-13T11:06:09Z
65 github.com/gosexy/gettext git 98b7b91596d20b96909e6b60d57411547dd9959c 2013-02-21T11:21:43Z
66 github.com/jessevdk/go-flags git 4047bd797dd935ae2b557a79cc43f223066c9659 2015-10-18T21:15:10Z
67+<<<<<<< TREE
68+=======
69+github.com/mvo5/goconfigparser git 26426272dda20cc76aa1fa44286dc743d2972fe8 2015-02-12T09:37:50Z
70+github.com/mvo5/uboot-go git 69978a3e4b05cca9d7cfee489b3453dfed45e72c 2015-07-23T08:17:10Z
71+github.com/ubuntu-core/snappy git a6e683cb4eca7027b331713c2f10e26a31050f20 2016-01-14T16:39:06Z
72+>>>>>>> MERGE-SOURCE
73 gopkg.in/yaml.v2 git 7ad95dd0798a40da1ccdff6dff35fd177b5edf40 2015-06-24T10:29:02Z
74 launchpad.net/gocheck bzr gustavo@niemeyer.net-20140225173054-xu9zlkf9kxhvow02 87
75
76=== modified file 'diskimage/bootloader.go'
77--- diskimage/bootloader.go 2016-04-05 09:32:48 +0000
78+++ diskimage/bootloader.go 2016-05-10 18:32:26 +0000
79@@ -89,21 +89,31 @@
80 printOut("Setting up raw boot asset partitions for", imagePath, "...")
81 var part int = partCount
82
83- for _, asset := range rawPartitions {
84+<<<<<<< TREE
85+ for _, asset := range rawPartitions {
86+=======
87+ pos := 0
88+ for _, asset := range rawPartitions {
89+>>>>>>> MERGE-SOURCE
90 part += 1
91
92- size, err := strconv.Atoi(asset.Size)
93- if err != nil {
94- return err
95- }
96- size = size * 2
97-
98 printOut("creating partition:", asset.Name)
99-
100- opts := fmt.Sprintf("0:0:+%d", size)
101- if err := exec.Command("sgdisk", "-a", "1", "-n", opts, imagePath).Run(); err != nil {
102+ // override position if specified, otherwise use the
103+ // previous position
104+ if asset.Pos > 0 {
105+ pos = asset.Pos
106+ }
107+
108+ // why * 2?
109+ size := asset.Size * 2
110+
111+ opts := fmt.Sprintf("%d:%d:+%d", part, pos, size)
112+ if output, err := exec.Command("sgdisk", "-a", "1", "-n", opts, imagePath).CombinedOutput(); err != nil {
113+ println(string(output))
114 return err
115 }
116+ // move postition forward
117+ pos += size
118
119 opts = fmt.Sprintf("%d:%s", part, asset.Name)
120 if err := exec.Command("sgdisk", "-c", opts, imagePath).Run(); err != nil {
121@@ -114,10 +124,9 @@
122 if err := exec.Command("sgdisk", "-t", opts, imagePath).Run(); err != nil {
123 return err
124 }
125-
126 }
127
128- printOut("sorting partitions")
129+ printOut("aligning partitions")
130 if err := exec.Command("sgdisk", "-s", imagePath).Run(); err != nil {
131 return err
132 }
133
134=== modified file 'diskimage/common.go'
135--- diskimage/common.go 2016-04-05 09:32:48 +0000
136+++ diskimage/common.go 2016-05-10 18:32:26 +0000
137@@ -17,8 +17,6 @@
138 "path/filepath"
139 "strings"
140 "syscall"
141-
142- "launchpad.net/goget-ubuntu-touch/sysutils"
143 )
144
145 // This program is free software: you can redistribute it and/or modify it
146@@ -47,10 +45,6 @@
147 initrdFileName = "initrd.img"
148 )
149
150-const (
151- partLayoutSystemAB = "system-AB"
152-)
153-
154 var (
155 syscallSync = syscall.Sync
156 )
157@@ -88,9 +82,16 @@
158 }
159
160 type BootAssetRawPartitions struct {
161+<<<<<<< TREE
162 Name string `yaml:"name"`
163 Size string `yaml:"size"`
164 Type string `yaml:"type"`
165+=======
166+ Name string `yaml:"name"`
167+ Size int `yaml:"size"`
168+ Pos int `yaml:"pos"`
169+ Type string `yaml:"type"`
170+>>>>>>> MERGE-SOURCE
171 }
172
173 type BootAssetFiles struct {
174@@ -107,11 +108,11 @@
175 RawPartitions []BootAssetRawPartitions `yaml:"raw-partitions,omitempty"`
176 }
177
178-type OemDescription struct {
179+type GadgetDescription struct {
180 Name string `yaml:"name"`
181 Version string `yaml:"version"`
182
183- OEM struct {
184+ Gadget struct {
185 Hardware struct {
186 Bootloader string `yaml:"bootloader"`
187 PartitionLayout string `yaml:"partition-layout"`
188@@ -129,7 +130,7 @@
189 Store *struct {
190 ID string `yaml:"id,omitempty"`
191 }
192- } `yaml:"oem,omitempty"`
193+ } `yaml:"gadget,omitempty"`
194
195 Config struct {
196 UbuntuCore struct {
197@@ -140,53 +141,52 @@
198 rootDir string
199 }
200
201-func (o *OemDescription) SetRoot(rootDir string) {
202+func (o *GadgetDescription) SetRoot(rootDir string) {
203 o.rootDir = rootDir
204 }
205
206 // SystemParts returns the system labels depending on the partition layout.
207 //
208 // The default is to return a flat structure for any unknown layout.
209-func (o *OemDescription) SystemParts() []string {
210- switch o.OEM.Hardware.PartitionLayout {
211- case partLayoutSystemAB:
212- return []string{"a", "b"}
213+func (o *GadgetDescription) SystemParts() []string {
214+ switch o.Gadget.Hardware.PartitionLayout {
215 default:
216 return []string{""}
217 }
218 }
219
220-func (o OemDescription) InstallPath() (string, error) {
221- glob, err := filepath.Glob(fmt.Sprintf("%s/oem/%s/current", o.rootDir, o.Name))
222+func (o GadgetDescription) InstallPath() (string, error) {
223+
224+ glob, err := filepath.Glob(fmt.Sprintf("%s/gadget/*/*", o.rootDir))
225 if err != nil {
226 return "", err
227 }
228
229 if len(glob) != 1 {
230- return "", errors.New("oem package not installed")
231+ return "", errors.New("gadget package not installed")
232 }
233
234 return glob[0], nil
235 }
236
237-func (o OemDescription) Architecture() string {
238- return o.OEM.Hardware.Architecture
239-}
240-
241-func (o *OemDescription) SetArchitecture(architecture string) {
242- o.OEM.Hardware.Architecture = architecture
243-}
244-
245-func (o OemDescription) PartitionLayout() string {
246- return o.OEM.Hardware.PartitionLayout
247-}
248-
249-func (o OemDescription) Platform() string {
250- return o.OEM.Hardware.Platform
251-}
252-
253-func (o *OemDescription) SetPlatform(platform string) {
254- o.OEM.Hardware.Platform = platform
255+func (o GadgetDescription) Architecture() string {
256+ return o.Gadget.Hardware.Architecture
257+}
258+
259+func (o *GadgetDescription) SetArchitecture(architecture string) {
260+ o.Gadget.Hardware.Architecture = architecture
261+}
262+
263+func (o GadgetDescription) PartitionLayout() string {
264+ return o.Gadget.Hardware.PartitionLayout
265+}
266+
267+func (o GadgetDescription) Platform() string {
268+ return o.Gadget.Hardware.Platform
269+}
270+
271+func (o *GadgetDescription) SetPlatform(platform string) {
272+ o.Gadget.Hardware.Platform = platform
273 }
274
275 func sectorSize(dev string) (string, error) {
276@@ -200,6 +200,7 @@
277
278 // BaseImage implements the basic primitives to manage images.
279 type BaseImage struct {
280+<<<<<<< TREE
281 baseMount string
282 hardware HardwareDescription
283 location string
284@@ -209,8 +210,22 @@
285 size int64
286 rootSize int
287 label string
288+=======
289+ baseMount string
290+ bindMounts []string
291+ hardware HardwareDescription
292+ location string
293+ gadget GadgetDescription
294+ parts []partition
295+ partCount int
296+ size int64
297+ rootSize int
298+ label string
299+>>>>>>> MERGE-SOURCE
300 }
301
302+var bindMounts = []string{"dev", "sys", "proc", filepath.Join("sys", "firmware")}
303+
304 // Mount mounts the image. This also maps the loop device.
305 func (img *BaseImage) Mount() error {
306 if err := img.doMap(); err != nil {
307@@ -267,8 +282,27 @@
308 }
309 img.baseMount = baseMount
310
311+ mountpoints := make([]string, 0, len(bindMounts))
312+ if img.gadget.PartitionLayout() == "minimal" {
313+ mountpoints = bindMounts
314+
315+ for _, d := range mountpoints {
316+ p := filepath.Join(baseMount, d)
317+
318+ if err := os.MkdirAll(p, 0755); err != nil {
319+ return err
320+ }
321+
322+ printOut("Bind mounting", d, "to", p)
323+ if err := bindMount(filepath.Join("/", d), p); err != nil {
324+ return err
325+ }
326+
327+ img.bindMounts = append(img.bindMounts, p)
328+ }
329+ }
330+
331 return nil
332-
333 }
334
335 // Unmount unmounts the image. This also unmaps the loop device.
336@@ -283,6 +317,13 @@
337 panic("No base mountpoint set")
338 }
339
340+ for i := len(img.bindMounts) - 1; i >= 0; i-- {
341+ if err := unmount(img.bindMounts[i]); err != nil {
342+ return err
343+ }
344+ }
345+ img.bindMounts = nil
346+
347 syscallSync()
348
349 for _, part := range img.parts {
350@@ -466,55 +507,28 @@
351 }
352
353 func (img *BaseImage) GenericBootSetup(bootPath string) error {
354- // origins
355- hardwareYamlPath := filepath.Join(img.baseMount, hardwareFileName)
356- kernelPath := filepath.Join(img.baseMount, img.hardware.Kernel)
357- initrdPath := filepath.Join(img.baseMount, img.hardware.Initrd)
358-
359- // populate both A/B
360- for _, part := range img.oem.SystemParts() {
361- path := filepath.Join(bootPath, part)
362-
363- printOut("Setting up", path)
364-
365- if err := os.MkdirAll(path, 0755); err != nil {
366- return err
367- }
368-
369- if err := sysutils.CopyFile(hardwareYamlPath, filepath.Join(path, hardwareFileName)); err != nil {
370- return err
371- }
372-
373- if err := sysutils.CopyFile(kernelPath, filepath.Join(path, kernelFileName)); err != nil {
374- return err
375- }
376-
377- if err := sysutils.CopyFile(initrdPath, filepath.Join(path, initrdFileName)); err != nil {
378- return err
379- }
380- }
381-
382- oemRoot, err := img.oem.InstallPath()
383+ gadgetRoot, err := img.gadget.InstallPath()
384 if err != nil {
385 return err
386 }
387
388- return setupBootAssetFiles(img.Boot(), bootPath, oemRoot, img.oem.OEM.Hardware.BootAssets.Files)
389+ return setupBootAssetFiles(img.Boot(), bootPath, gadgetRoot, img.gadget.Gadget.Hardware.BootAssets.Files)
390 }
391
392 func (img *BaseImage) FlashExtra() error {
393- oemRoot, err := img.oem.InstallPath()
394+ gadgetRoot, err := img.gadget.InstallPath()
395 if err != nil {
396 return err
397 }
398
399- if bootAssets := img.oem.OEM.Hardware.BootAssets; bootAssets != nil {
400+ if bootAssets := img.gadget.Gadget.Hardware.BootAssets; bootAssets != nil {
401 if bootAssets.RawPartitions != nil {
402 if err := setupBootAssetRawPartitions(img.location, img.partCount, bootAssets.RawPartitions); err != nil {
403 return err
404 }
405 }
406- return setupBootAssetRawFiles(img.location, oemRoot, bootAssets.RawFiles)
407+
408+ return setupBootAssetRawFiles(img.location, gadgetRoot, bootAssets.RawFiles)
409 }
410
411 return nil
412@@ -525,3 +539,19 @@
413 fmt.Println(args...)
414 }
415 }
416+
417+func bindMount(src, dst string) error {
418+ if out, err := exec.Command("mount", "--bind", src, dst).CombinedOutput(); err != nil {
419+ return fmt.Errorf("issues while bind mounting: %s", out)
420+ }
421+
422+ return nil
423+}
424+
425+func unmount(dst string) error {
426+ if out, err := exec.Command("umount", dst).CombinedOutput(); err != nil {
427+ return fmt.Errorf("issues while unmounting: %s", out)
428+ }
429+
430+ return nil
431+}
432
433=== modified file 'diskimage/common_test.go'
434--- diskimage/common_test.go 2015-09-09 16:00:01 +0000
435+++ diskimage/common_test.go 2016-05-10 18:32:26 +0000
436@@ -28,7 +28,7 @@
437
438 type CommonTestSuite struct {
439 tmpdir string
440- oem OemDescription
441+ gadget GadgetDescription
442 packageInst string
443 }
444
445@@ -36,27 +36,27 @@
446
447 func (s *CommonTestSuite) SetUpTest(c *C) {
448 s.tmpdir = c.MkDir()
449- s.oem = OemDescription{Name: "packagename", Version: "42"}
450- s.packageInst = s.oem.Name
451+ s.gadget = GadgetDescription{Name: "packagename", Version: "42"}
452+ s.packageInst = s.gadget.Name
453 }
454
455 func (s *CommonTestSuite) TestOemInstallPath(c *C) {
456- err := os.MkdirAll(filepath.Join(s.tmpdir, "oem", s.packageInst, "current"), 0755)
457- c.Assert(err, IsNil)
458-
459- s.oem.SetRoot(s.tmpdir)
460- installPath, err := s.oem.InstallPath()
461-
462- c.Assert(err, IsNil)
463- c.Assert(installPath, Equals, filepath.Join(s.tmpdir, "oem/packagename/current"))
464+ err := os.MkdirAll(filepath.Join(s.tmpdir, "gadget", s.packageInst, "current"), 0755)
465+ c.Assert(err, IsNil)
466+
467+ s.gadget.SetRoot(s.tmpdir)
468+ installPath, err := s.gadget.InstallPath()
469+
470+ c.Assert(err, IsNil)
471+ c.Assert(installPath, Equals, filepath.Join(s.tmpdir, "gadget/packagename/current"))
472 }
473
474 func (s *CommonTestSuite) TestOemInstallPathNoOem(c *C) {
475- err := os.MkdirAll(filepath.Join(s.tmpdir, "oem", s.packageInst), 0755)
476+ err := os.MkdirAll(filepath.Join(s.tmpdir, "gadget", s.packageInst), 0755)
477 c.Assert(err, IsNil)
478
479- s.oem.SetRoot(s.tmpdir)
480- installPath, err := s.oem.InstallPath()
481+ s.gadget.SetRoot(s.tmpdir)
482+ installPath, err := s.gadget.InstallPath()
483
484 c.Assert(err, NotNil)
485 c.Assert(installPath, Equals, "")
486
487=== modified file 'diskimage/core_grub.go'
488--- diskimage/core_grub.go 2016-04-05 09:32:48 +0000
489+++ diskimage/core_grub.go 2016-05-10 18:32:26 +0000
490@@ -5,6 +5,7 @@
491 //
492 // Written by Sergio Schvezov <sergio.schvezov@canonical.com>
493 //
494+
495 package diskimage
496
497 import (
498@@ -31,25 +32,40 @@
499 // You should have received a copy of the GNU General Public License along
500 // with this program. If not, see <http://www.gnu.org/licenses/>.
501
502+// CoreGrubImage holds the logic to create a core image using grub.
503 type CoreGrubImage struct {
504 BaseImage
505
506 legacyGrub bool
507 }
508
509-func NewCoreGrubImage(location string, size int64, rootSize int, hw HardwareDescription, oem OemDescription, updateGrub bool, label string) *CoreGrubImage {
510+// NewCoreGrubImage creates a new instance of CoreGrubImage
511+func NewCoreGrubImage(location string, size int64, rootSize int, hw HardwareDescription, gadget GadgetDescription, updateGrub bool, label string) *CoreGrubImage {
512+ var partCount int
513+ switch gadget.PartitionLayout() {
514+ case "minimal":
515+ partCount = 3
516+ }
517+
518 return &CoreGrubImage{
519 BaseImage: BaseImage{
520 location: location,
521 size: size,
522 rootSize: rootSize,
523 hardware: hw,
524+<<<<<<< TREE
525 oem: oem,
526 partCount: 5,
527 label: label,
528+=======
529+ gadget: gadget,
530+ partCount: partCount,
531+ label: label,
532+>>>>>>> MERGE-SOURCE
533 },
534 legacyGrub: updateGrub,
535 }
536+
537 }
538
539 const grubCfgContent = `# console only, no graphics/vga
540@@ -75,9 +91,10 @@
541 }
542
543 parted.addPart(grubLabel, "", fsNone, 4)
544- parted.addPart(bootLabel, bootDir, fsFat32, 128)
545- parted.addPart(systemALabel, systemADir, fsExt4, img.rootSize)
546- parted.addPart(systemBLabel, systemBDir, fsExt4, img.rootSize)
547+ switch img.gadget.PartitionLayout() {
548+ case "minimal":
549+ parted.addPart(bootLabel, bootDir, fsFat32, 64)
550+ }
551 parted.addPart(writableLabel, writableDir, fsExt4, -1)
552
553 parted.setBoot(2)
554@@ -88,6 +105,7 @@
555 return parted.create(img.location)
556 }
557
558+// SetupBoot sets up the bootloader logic for the image.
559 func (img *CoreGrubImage) SetupBoot() error {
560 if !img.legacyGrub {
561 // destinations
562@@ -121,14 +139,14 @@
563 return errors.New("cannot determined absolute path for output image")
564 }
565
566- rootDevPath := filepath.Join(img.System(), "root_dev")
567+ rootDevPath := filepath.Join(img.System(), "tmp", "root_dev")
568
569- if f, err := os.Create(rootDevPath); err != nil {
570+ f, err := os.Create(rootDevPath)
571+ if err != nil {
572 return err
573- } else {
574- f.Close()
575- defer os.Remove(rootDevPath)
576 }
577+ f.Close()
578+ defer os.Remove(rootDevPath)
579
580 if err := bindMount(outputPath, rootDevPath); err != nil {
581 return err
582@@ -165,7 +183,7 @@
583
584 var grubTarget string
585
586- arch := img.oem.Architecture()
587+ arch := img.gadget.Architecture()
588
589 switch arch {
590 case "armhf":
591@@ -174,13 +192,15 @@
592 grubTarget = "x86_64-efi"
593 case "i386":
594 grubTarget = "i386-efi"
595+ case "arm64":
596+ grubTarget = "arm64-efi"
597 default:
598 return fmt.Errorf("unsupported architecture for GRUB on EFI: %s", arch)
599 }
600
601 if arch == "amd64" || arch == "i386" {
602 // install grub BIOS support
603- if out, err := exec.Command("chroot", img.System(), "grub-install", "/root_dev").CombinedOutput(); err != nil {
604+ if out, err := exec.Command("chroot", img.System(), "grub-install", "tmp/root_dev").CombinedOutput(); err != nil {
605 return fmt.Errorf("unable to install grub (BIOS): %s", out)
606 }
607 }
608@@ -233,19 +253,3 @@
609
610 return nil
611 }
612-
613-func bindMount(src, dst string) error {
614- if out, err := exec.Command("mount", "--bind", src, dst).CombinedOutput(); err != nil {
615- return fmt.Errorf("issues while bind mounting: %s", out)
616- }
617-
618- return nil
619-}
620-
621-func unmount(dst string) error {
622- if out, err := exec.Command("umount", dst).CombinedOutput(); err != nil {
623- return fmt.Errorf("issues while unmounting: %s", out)
624- }
625-
626- return nil
627-}
628
629=== modified file 'diskimage/core_uboot.go'
630--- diskimage/core_uboot.go 2016-04-05 09:32:48 +0000
631+++ diskimage/core_uboot.go 2016-05-10 18:32:26 +0000
632@@ -66,16 +66,27 @@
633 Bootloader []string `yaml:"bootloader"`
634 }
635
636-func NewCoreUBootImage(location string, size int64, rootSize int, hw HardwareDescription, oem OemDescription, label string) *CoreUBootImage {
637+func NewCoreUBootImage(location string, size int64, rootSize int, hw HardwareDescription, gadget GadgetDescription, label string) *CoreUBootImage {
638+ var partCount int
639+ switch gadget.PartitionLayout() {
640+ case "minimal":
641+ partCount = 2
642+ }
643+
644 return &CoreUBootImage{
645 BaseImage{
646 hardware: hw,
647- oem: oem,
648+ gadget: gadget,
649 location: location,
650 size: size,
651 rootSize: rootSize,
652+<<<<<<< TREE
653 partCount: 4,
654 label: label,
655+=======
656+ partCount: partCount,
657+ label: label,
658+>>>>>>> MERGE-SOURCE
659 },
660 }
661 }
662@@ -95,9 +106,10 @@
663 return err
664 }
665
666- parted.addPart(bootLabel, bootDir, fsFat32, 128)
667- parted.addPart(systemALabel, systemADir, fsExt4, 1024)
668- parted.addPart(systemBLabel, systemBDir, fsExt4, 1024)
669+ switch img.gadget.PartitionLayout() {
670+ case "minimal":
671+ parted.addPart(bootLabel, bootDir, fsFat32, 128)
672+ }
673 parted.addPart(writableLabel, writableDir, fsExt4, -1)
674
675 parted.setBoot(1)
676@@ -117,7 +129,7 @@
677 }
678
679 // populate both A/B
680- for _, part := range img.oem.SystemParts() {
681+ for _, part := range img.gadget.SystemParts() {
682 bootDtbPath := filepath.Join(bootPath, part, "dtbs")
683 if err := img.provisionDtbs(bootDtbPath); err != nil {
684 return err
685@@ -131,7 +143,7 @@
686 defer snappySystemFile.Close()
687
688 var fdtfile string
689- if platform := img.oem.Platform(); platform != "" {
690+ if platform := img.gadget.Platform(); platform != "" {
691 fdtfile = fmt.Sprintf("fdtfile=%s.dtb", platform)
692 }
693
694@@ -154,28 +166,32 @@
695 return err
696 }
697
698- dtbFis, err := ioutil.ReadDir(dtbsPath)
699- if err != nil {
700- return err
701+ var dtbFis []os.FileInfo
702+ if img.hardware.Dtbs != "" {
703+ var err error
704+ dtbFis, err = ioutil.ReadDir(dtbsPath)
705+ if err != nil {
706+ return err
707+ }
708 }
709
710 if err := os.MkdirAll(bootDtbPath, 0755); err != nil {
711 return err
712 }
713
714- dtb := filepath.Join(dtbsPath, fmt.Sprintf("%s.dtb", img.oem.Platform()))
715+ dtb := filepath.Join(dtbsPath, fmt.Sprintf("%s.dtb", img.gadget.Platform()))
716
717 // if there is a specific dtb for the platform, copy it.
718- // First look in oem and then in device.
719- if oemDtb := img.oem.OEM.Hardware.Dtb; oemDtb != "" && img.oem.Platform() != "" {
720- oemRoot, err := img.oem.InstallPath()
721+ // First look in gadget and then in device.
722+ if gadgetDtb := img.gadget.Gadget.Hardware.Dtb; gadgetDtb != "" && img.gadget.Platform() != "" {
723+ gadgetRoot, err := img.gadget.InstallPath()
724 if err != nil {
725 return err
726 }
727
728- oemDtb := filepath.Join(oemRoot, oemDtb)
729+ gadgetDtb := filepath.Join(gadgetRoot, gadgetDtb)
730 dst := filepath.Join(bootDtbPath, filepath.Base(dtb))
731- if err := sysutils.CopyFile(oemDtb, dst); err != nil {
732+ if err := sysutils.CopyFile(gadgetDtb, dst); err != nil {
733 return err
734 }
735 } else if _, err := os.Stat(dtb); err == nil {
736
737=== modified file 'diskimage/partition.go'
738--- diskimage/partition.go 2015-01-15 21:05:01 +0000
739+++ diskimage/partition.go 2016-05-10 18:32:26 +0000
740@@ -5,6 +5,7 @@
741 //
742 // Written by Sergio Schvezov <sergio.schvezov@canonical.com>
743 //
744+
745 package diskimage
746
747 import (
748
749=== modified file 'ubuntu-device-flash/common.go'
750--- ubuntu-device-flash/common.go 2015-03-30 03:28:28 +0000
751+++ ubuntu-device-flash/common.go 2016-05-10 18:32:26 +0000
752@@ -61,11 +61,11 @@
753
754 // expandFile checks for file existence, correct permissions and returns the absolute path.
755 func expandFile(path string) (abspath string, err error) {
756- if p, err := filepath.Abs(path); err != nil {
757+ p, err := filepath.Abs(path)
758+ if err != nil {
759 return "", err
760- } else {
761- abspath = p
762 }
763+ abspath = p
764
765 fi, err := os.Lstat(abspath)
766 if err != nil {
767
768=== modified file 'ubuntu-device-flash/core.go'
769--- ubuntu-device-flash/core.go 2016-04-04 15:54:40 +0000
770+++ ubuntu-device-flash/core.go 2016-05-10 18:32:26 +0000
771@@ -77,21 +77,20 @@
772
773 if !coreCmd.Deprecated.Cloud {
774 coreCmd.customizationFunc = append(coreCmd.customizationFunc, coreCmd.setupCloudInit)
775- coreCmd.customizationFunc = append(coreCmd.customizationFunc, coreCmd.setupOemConfigs)
776+ coreCmd.customizationFunc = append(coreCmd.customizationFunc, coreCmd.setupGadgetConfigs)
777 }
778
779 return coreCmd.create()
780 }
781
782 // this is a hackish way to get the config in place
783-func (coreCmd *CoreCmd) setupOemConfigs() error {
784- modprobeDContent := coreCmd.oem.Config.UbuntuCore.Modprobe
785+func (coreCmd *CoreCmd) setupGadgetConfigs() error {
786+ modprobeDContent := coreCmd.gadget.Config.UbuntuCore.Modprobe
787 if modprobeDContent == nil {
788- printOut("no modprobe")
789 return nil
790 }
791
792- fmt.Println("Setting up oem hooks...")
793+ fmt.Println("Setting up gadget hooks...")
794
795 writablePath := coreCmd.img.Writable()
796
797@@ -101,12 +100,20 @@
798 }
799
800 // first we need to copy all the files in modprobe.d
801+<<<<<<< TREE
802 /*
803 systemModprobeDir := filepath.Join(coreCmd.img.System(), "etc", "modprobe.d")
804 if err := helpers.RSyncWithDelete(systemModprobeDir, modprobeDir); err != nil {
805 return err
806 }
807 */
808+=======
809+ systemModprobeDir := filepath.Join(coreCmd.img.System(), "etc", "modprobe.d")
810+ // FIXME: can we do "cp -a" here?
811+ if err := RSyncWithDelete(systemModprobeDir, modprobeDir); err != nil {
812+ return err
813+ }
814+>>>>>>> MERGE-SOURCE
815
816 modprobeD := filepath.Join(modprobeDir, "ubuntu-core.conf")
817 modprobeDFile, err := os.Create(modprobeD)
818
819=== added file 'ubuntu-device-flash/helpers.go'
820--- ubuntu-device-flash/helpers.go 1970-01-01 00:00:00 +0000
821+++ ubuntu-device-flash/helpers.go 2016-05-10 18:32:26 +0000
822@@ -0,0 +1,89 @@
823+// -*- Mode: Go; indent-tabs-mode: t -*-
824+
825+/*
826+ * Copyright (C) 2014-2015 Canonical Ltd
827+ *
828+ * This program is free software: you can redistribute it and/or modify
829+ * it under the terms of the GNU General Public License version 3 as
830+ * published by the Free Software Foundation.
831+ *
832+ * This program is distributed in the hope that it will be useful,
833+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
834+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
835+ * GNU General Public License for more details.
836+ *
837+ * You should have received a copy of the GNU General Public License
838+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
839+ *
840+ */
841+
842+package main
843+
844+import (
845+ "fmt"
846+ "os"
847+ "os/exec"
848+ "path/filepath"
849+ "syscall"
850+
851+ "github.com/ubuntu-core/snappy/osutil"
852+)
853+
854+// RSyncWithDelete syncs srcDir to destDir
855+func RSyncWithDelete(srcDirName, destDirName string) error {
856+ // first remove everything thats not in srcdir
857+ err := filepath.Walk(destDirName, func(path string, info os.FileInfo, err error) error {
858+ if err != nil {
859+ return err
860+ }
861+
862+ // relative to the root "destDirName"
863+ relPath := path[len(destDirName):]
864+ if !osutil.FileExists(filepath.Join(srcDirName, relPath)) {
865+ if err := os.RemoveAll(path); err != nil {
866+ return err
867+ }
868+ if info.IsDir() {
869+ return filepath.SkipDir
870+ }
871+ }
872+ return nil
873+ })
874+ if err != nil {
875+ return err
876+ }
877+
878+ // then copy or update the data from srcdir to destdir
879+ err = filepath.Walk(srcDirName, func(src string, info os.FileInfo, err error) error {
880+ if err != nil {
881+ return err
882+ }
883+
884+ // relative to the root "srcDirName"
885+ relPath := src[len(srcDirName):]
886+ dst := filepath.Join(destDirName, relPath)
887+ if info.IsDir() {
888+ if err := os.MkdirAll(dst, info.Mode()); err != nil {
889+ return err
890+ }
891+
892+ // this can panic. The alternative would be to use the "st, ok" pattern, and then if !ok... panic?
893+ st := info.Sys().(*syscall.Stat_t)
894+ ts := []syscall.Timespec{st.Atim, st.Mtim}
895+
896+ return syscall.UtimesNano(dst, ts)
897+ }
898+ if !osutil.FilesAreEqual(src, dst) {
899+ // XXX: we should (eventually) use CopyFile here,
900+ // but we need to teach it about preserving
901+ // of atime/mtime and permissions
902+ output, err := exec.Command("cp", "-va", src, dst).CombinedOutput()
903+ if err != nil {
904+ return fmt.Errorf("Failed to copy %s to %s (%s)", src, dst, output)
905+ }
906+ }
907+ return nil
908+ })
909+
910+ return err
911+}
912
913=== added file 'ubuntu-device-flash/helpers_test.go'
914--- ubuntu-device-flash/helpers_test.go 1970-01-01 00:00:00 +0000
915+++ ubuntu-device-flash/helpers_test.go 2016-05-10 18:32:26 +0000
916@@ -0,0 +1,135 @@
917+// -*- Mode: Go; indent-tabs-mode: t -*-
918+
919+/*
920+ * Copyright (C) 2014-2015 Canonical Ltd
921+ *
922+ * This program is free software: you can redistribute it and/or modify
923+ * it under the terms of the GNU General Public License version 3 as
924+ * published by the Free Software Foundation.
925+ *
926+ * This program is distributed in the hope that it will be useful,
927+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
928+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
929+ * GNU General Public License for more details.
930+ *
931+ * You should have received a copy of the GNU General Public License
932+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
933+ *
934+ */
935+
936+package main
937+
938+import (
939+ "fmt"
940+ "io/ioutil"
941+ "os"
942+ "os/exec"
943+ "path/filepath"
944+
945+ . "launchpad.net/gocheck"
946+)
947+
948+type HTestSuite struct{}
949+
950+var _ = Suite(&HTestSuite{})
951+
952+func makeTestFiles(c *C, srcDir, destDir string) {
953+ // a new file
954+ err := ioutil.WriteFile(filepath.Join(srcDir, "new"), []byte(nil), 0644)
955+ c.Assert(err, IsNil)
956+
957+ // a existing file that needs update
958+ err = ioutil.WriteFile(filepath.Join(destDir, "existing-update"), []byte("old-content"), 0644)
959+ c.Assert(err, IsNil)
960+ err = ioutil.WriteFile(filepath.Join(srcDir, "existing-update"), []byte("some-new-content"), 0644)
961+ c.Assert(err, IsNil)
962+
963+ // existing file that needs no update
964+ err = ioutil.WriteFile(filepath.Join(srcDir, "existing-unchanged"), []byte(nil), 0644)
965+ c.Assert(err, IsNil)
966+ err = exec.Command("cp", "-a", filepath.Join(srcDir, "existing-unchanged"), filepath.Join(destDir, "existing-unchanged")).Run()
967+ c.Assert(err, IsNil)
968+
969+ // a file that needs removal
970+ err = ioutil.WriteFile(filepath.Join(destDir, "to-be-deleted"), []byte(nil), 0644)
971+ c.Assert(err, IsNil)
972+}
973+
974+func compareDirs(c *C, srcDir, destDir string) {
975+ d1, err := exec.Command("ls", "-al", srcDir).CombinedOutput()
976+ c.Assert(err, IsNil)
977+ d2, err := exec.Command("ls", "-al", destDir).CombinedOutput()
978+ c.Assert(err, IsNil)
979+ c.Assert(string(d1), Equals, string(d2))
980+ // ensure content got updated
981+ c1, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", srcDir)).CombinedOutput()
982+ c.Assert(err, IsNil)
983+ c2, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", destDir)).CombinedOutput()
984+ c.Assert(err, IsNil)
985+ c.Assert(string(c1), Equals, string(c2))
986+}
987+
988+func (ts *HTestSuite) TestSyncDirs(c *C) {
989+
990+ for _, l := range [][2]string{
991+ [2]string{"src-short", "dst-loooooooooooong"},
992+ [2]string{"src-loooooooooooong", "dst-short"},
993+ [2]string{"src-eq", "dst-eq"},
994+ } {
995+
996+ // ensure we have src, dest dirs with different length
997+ srcDir := filepath.Join(c.MkDir(), l[0])
998+ err := os.MkdirAll(srcDir, 0755)
999+ c.Assert(err, IsNil)
1000+ destDir := filepath.Join(c.MkDir(), l[1])
1001+ err = os.MkdirAll(destDir, 0755)
1002+ c.Assert(err, IsNil)
1003+
1004+ // add a src subdir
1005+ subdir := filepath.Join(srcDir, "subdir")
1006+ err = os.Mkdir(subdir, 0755)
1007+ c.Assert(err, IsNil)
1008+ makeTestFiles(c, subdir, destDir)
1009+
1010+ // add a dst subdir that needs to get deleted
1011+ subdir2 := filepath.Join(destDir, "to-be-deleted-subdir")
1012+ err = os.Mkdir(subdir2, 0755)
1013+ subdir3 := filepath.Join(subdir2, "to-be-deleted-sub-subdir")
1014+ err = os.Mkdir(subdir3, 0755)
1015+
1016+ // and a toplevel
1017+ makeTestFiles(c, srcDir, destDir)
1018+
1019+ // do it
1020+ err = RSyncWithDelete(srcDir, destDir)
1021+ c.Assert(err, IsNil)
1022+
1023+ // ensure meta-data is identical
1024+ compareDirs(c, srcDir, destDir)
1025+ compareDirs(c, filepath.Join(srcDir, "subdir"), filepath.Join(destDir, "subdir"))
1026+ }
1027+}
1028+
1029+func (ts *HTestSuite) TestSyncDirFails(c *C) {
1030+ srcDir := c.MkDir()
1031+ err := os.MkdirAll(srcDir, 0755)
1032+ c.Assert(err, IsNil)
1033+
1034+ destDir := c.MkDir()
1035+ err = os.MkdirAll(destDir, 0755)
1036+ c.Assert(err, IsNil)
1037+
1038+ err = ioutil.WriteFile(filepath.Join(destDir, "meep"), []byte(nil), 0644)
1039+ c.Assert(err, IsNil)
1040+
1041+ // ensure remove fails
1042+ err = os.Chmod(destDir, 0100)
1043+ c.Assert(err, IsNil)
1044+ // make tempdir cleanup work again
1045+ defer os.Chmod(destDir, 0755)
1046+
1047+ // do it
1048+ err = RSyncWithDelete(srcDir, destDir)
1049+ c.Check(err, NotNil)
1050+ c.Check(err, ErrorMatches, ".*permission denied.*")
1051+}
1052
1053=== modified file 'ubuntu-device-flash/snappy.go'
1054--- ubuntu-device-flash/snappy.go 2016-04-05 09:39:49 +0000
1055+++ ubuntu-device-flash/snappy.go 2016-05-10 18:32:26 +0000
1056@@ -11,6 +11,22 @@
1057 import (
1058 "fmt"
1059
1060+<<<<<<< TREE
1061+=======
1062+ "github.com/ubuntu-core/snappy/arch"
1063+ "github.com/ubuntu-core/snappy/dirs"
1064+ "github.com/ubuntu-core/snappy/osutil"
1065+ "github.com/ubuntu-core/snappy/partition"
1066+ "github.com/ubuntu-core/snappy/progress"
1067+ "github.com/ubuntu-core/snappy/provisioning"
1068+ "github.com/ubuntu-core/snappy/release"
1069+ "github.com/ubuntu-core/snappy/snap"
1070+ // needed so that we register the squashfs format
1071+ _ "github.com/ubuntu-core/snappy/snap/squashfs"
1072+ "github.com/ubuntu-core/snappy/snappy"
1073+
1074+ "gopkg.in/yaml.v2"
1075+>>>>>>> MERGE-SOURCE
1076 "launchpad.net/goget-ubuntu-touch/diskimage"
1077 "launchpad.net/goget-ubuntu-touch/ubuntuimage"
1078 )
1079@@ -58,11 +74,14 @@
1080 }
1081 }
1082
1083+// Snapper holds common options applicable to snappy based images.
1084 type Snapper struct {
1085 Channel string `long:"channel" description:"Specify the channel to use" default:"stable"`
1086 Output string `long:"output" short:"o" description:"Name of the image file to create" required:"true"`
1087- Oem string `long:"oem" description:"The snappy oem package to base the image out of" default:"generic-amd64"`
1088+ Gadget string `long:"gadget" description:"The snappy gadget package to base the image out of" default:"generic-amd64"`
1089 StoreID string `long:"store" description:"Set an alternate store id."`
1090+ OS string `long:"os" description:"path to the OS snap."`
1091+ Kernel string `long:"kernel" description:"path to the kernel snap."`
1092
1093 Development struct {
1094 Install []string `long:"install" description:"Install additional packages (can be called multiple times)"`
1095@@ -71,12 +90,19 @@
1096 } `group:"Development"`
1097
1098 Positional struct {
1099- Release string `positional-arg-name:"release" description:"The release to base the image out of (15.04 or rolling)" required:"true"`
1100+ Release string `positional-arg-name:"release" description:"The release to base the image out of (16 or rolling)" required:"true"`
1101 } `positional-args:"yes" required:"yes"`
1102
1103+<<<<<<< TREE
1104 img diskimage.CoreImage
1105 hardware diskimage.HardwareDescription
1106 oem diskimage.OemDescription
1107+=======
1108+ img diskimage.CoreImage
1109+ hardware diskimage.HardwareDescription
1110+ gadget diskimage.GadgetDescription
1111+ stagingRootPath string
1112+>>>>>>> MERGE-SOURCE
1113
1114 size int64
1115
1116@@ -85,23 +111,765 @@
1117 customizationFunc []func() error
1118 }
1119
1120+<<<<<<< TREE
1121+=======
1122+func (s Snapper) sanityCheck() error {
1123+ // we don't want to overwrite the output, people might get angry :-)
1124+ if osutil.FileExists(s.Output) {
1125+ return fmt.Errorf("Giving up, the desired target output file %#v already exists", s.Output)
1126+ }
1127+
1128+ if s.size < s.flavor.minSize() {
1129+ return fmt.Errorf("minimum size for %s is %d", s.flavor, s.flavor.minSize())
1130+ }
1131+
1132+ if syscall.Getuid() != 0 {
1133+ return errors.New("command requires sudo/pkexec (root)")
1134+ }
1135+ if s.Positional.Release == "15.04" {
1136+ return errors.New("building 15.04 core images is no longer supported. Please use the ppa:snappy-dev/tools 15.04 version of this tool")
1137+ }
1138+
1139+ // ensure we error when running on e.g. 14.04 with a sensible
1140+ // error message instead of super strange error later
1141+ if !osutil.FileExists("/bin/systemctl") {
1142+ return errors.New("need '/bin/systemctl to work")
1143+ }
1144+
1145+ // only allow whitelisted gadget names for now
1146+ if os.Getenv("UBUNTU_DEVICE_FLASH_IGNORE_UNSTABLE_GADGET_DEFINITION") == "" {
1147+ contains := func(haystack []string, needle string) bool {
1148+ for _, elm := range haystack {
1149+ if elm == needle {
1150+ return true
1151+ }
1152+ }
1153+ return false
1154+ }
1155+ whitelist := []string{"canonical-i386", "canonical-pc", "canonical-pi2", "canonical-dragon", "beagleblack"}
1156+ if !contains(whitelist, s.Gadget) {
1157+ return fmt.Errorf("cannot use %q, must be one of: %q", s.Gadget, whitelist)
1158+ }
1159+ }
1160+
1161+ return nil
1162+}
1163+
1164+>>>>>>> MERGE-SOURCE
1165 func (s *Snapper) systemImage() (*ubuntuimage.Image, error) {
1166+<<<<<<< TREE
1167 return nil, nil
1168+=======
1169+ channels, err := ubuntuimage.NewChannels(globalArgs.Server)
1170+ if err != nil {
1171+ return nil, err
1172+ }
1173+
1174+ channel := systemImageChannel(s.flavor.Channel(), s.Positional.Release, s.Channel)
1175+ // TODO: remove once azure channel is gone
1176+ if s.device == "" {
1177+ s.device = systemImageDeviceChannel(s.gadget.Architecture())
1178+ }
1179+
1180+ deviceChannel, err := channels.GetDeviceChannel(globalArgs.Server, channel, s.device)
1181+ if err != nil {
1182+ return nil, err
1183+ }
1184+
1185+ systemImage, err := getImage(deviceChannel)
1186+ if err != nil {
1187+ return nil, err
1188+ }
1189+
1190+ // avoid passing more args to setup()
1191+ globalArgs.Revision = systemImage.Version
1192+
1193+ return &systemImage, nil
1194+}
1195+
1196+func systemdEnable(serviceName string) error {
1197+ fmt.Printf("Enabling systemd unit %s\n", serviceName)
1198+
1199+ servicesSystemdTarget := "multi-user.target"
1200+ snapServicesDir := "/etc/systemd/system"
1201+
1202+ enableSymlink := filepath.Join(dirs.GlobalRootDir, snapServicesDir, servicesSystemdTarget+".wants", serviceName)
1203+
1204+ serviceFilename := filepath.Join(dirs.GlobalRootDir, snapServicesDir, serviceName)
1205+
1206+ return os.Symlink(serviceFilename[len(dirs.GlobalRootDir):], enableSymlink)
1207+
1208+}
1209+
1210+func (s *Snapper) installFlags() snappy.InstallFlags {
1211+ flags := snappy.InhibitHooks | snappy.AllowGadget
1212+
1213+ if s.Development.DeveloperMode {
1214+ flags |= snappy.AllowUnauthenticated
1215+ }
1216+
1217+ return flags
1218+>>>>>>> MERGE-SOURCE
1219 }
1220
1221 func (s *Snapper) install(systemPath string) error {
1222- return nil
1223+<<<<<<< TREE
1224+ return nil
1225+=======
1226+ dirs.SetRootDir(systemPath)
1227+ defer dirs.SetRootDir("/")
1228+
1229+ flags := s.installFlags()
1230+ gadgetSoftware := s.gadget.Gadget.Software
1231+ packageCount := len(s.Development.Install) + len(gadgetSoftware.BuiltIn) + len(gadgetSoftware.Preinstalled) + 3
1232+ if s.Gadget != "" {
1233+ packageCount++
1234+ }
1235+
1236+ packageQueue := make([]string, 0, packageCount)
1237+ if s.Gadget != "" {
1238+ packageQueue = append(packageQueue, s.Gadget)
1239+ }
1240+ if s.OS != "" && s.Kernel != "" {
1241+ packageQueue = append(packageQueue, s.Kernel)
1242+ packageQueue = append(packageQueue, s.OS)
1243+ }
1244+ packageQueue = append(packageQueue, gadgetSoftware.BuiltIn...)
1245+ packageQueue = append(packageQueue, gadgetSoftware.Preinstalled...)
1246+ packageQueue = append(packageQueue, s.Development.Install...)
1247+
1248+ for _, snap := range packageQueue {
1249+ fmt.Println("Installing", snap)
1250+
1251+ pb := progress.NewTextProgress()
1252+ name := snap
1253+ if _, err := snappy.Install(name, s.Channel, flags, pb); err != nil {
1254+ return fmt.Errorf("failed to install %q from %q: %s", name, s.Channel, err)
1255+ }
1256+ }
1257+
1258+ // set the bootvars for kernel/os snaps, the latest snappy is
1259+ // not activating the snaps on install anymore (with inhibit)
1260+ // so we need to work around that here (only on first boot)
1261+ //
1262+ // there is also no mounted os/kernel snap in the systemPath
1263+ // all we have here is the blobs
1264+ if s.OS != "" && s.Kernel != "" {
1265+ bootloader, err := partition.FindBootloader()
1266+ if err != nil {
1267+ return fmt.Errorf("can not set kernel/os bootvars: %s", err)
1268+ }
1269+
1270+ snaps, _ := filepath.Glob(filepath.Join(dirs.SnapBlobDir, "*.snap"))
1271+ for _, fullname := range snaps {
1272+ bootvar := ""
1273+ bootvar2 := ""
1274+
1275+ // detect type
1276+ snapFile, err := snap.Open(fullname)
1277+ if err != nil {
1278+ return fmt.Errorf("can not read %v", fullname)
1279+ }
1280+ info, err := snap.ReadInfoFromSnapFile(snapFile, nil)
1281+ if err != nil {
1282+ return fmt.Errorf("can not get info for %v", fullname)
1283+ }
1284+ switch info.Type {
1285+ case snap.TypeOS:
1286+ bootvar = "snappy_os"
1287+ bootvar2 = "snappy_good_os"
1288+ case snap.TypeKernel:
1289+ bootvar = "snappy_kernel"
1290+ bootvar2 = "snappy_good_kernel"
1291+ }
1292+
1293+ name := filepath.Base(fullname)
1294+ for _, b := range []string{bootvar, bootvar2} {
1295+ if b != "" {
1296+ if err := bootloader.SetBootVar(b, name); err != nil {
1297+ return err
1298+ }
1299+ }
1300+ }
1301+ }
1302+
1303+ // HORRIBLE, snappy.Install() will check if running
1304+ // on a grub system based on the gadget snap and if
1305+ // it is grub it will not extract the kernel/os
1306+ //
1307+ // HOWEVER this won't work in u-d-f because there
1308+ // is no current symlink so kernel.go always unpacks
1309+ // the kernel. undo this here
1310+ if s.gadget.Gadget.Hardware.Bootloader == "grub" {
1311+ dirs, _ := filepath.Glob(filepath.Join(s.img.Boot(), "/EFI/ubuntu/grub/*.snap"))
1312+ for _, d := range dirs {
1313+ fmt.Printf("Removing unneeded: %s\n", d)
1314+ if err := os.RemoveAll(d); err != nil {
1315+ return err
1316+ }
1317+ }
1318+ }
1319+ }
1320+
1321+ return nil
1322+}
1323+
1324+func (s *Snapper) extractGadget(gadgetPackage string) error {
1325+ if gadgetPackage == "" {
1326+ return nil
1327+ }
1328+
1329+ tempDir, err := ioutil.TempDir("", "gadget")
1330+ if err != nil {
1331+ return err
1332+ }
1333+
1334+ // we need to fix the permissions for tempdir to be seteuid friendly
1335+ if err := os.Chmod(tempDir, 0755); err != nil {
1336+ return err
1337+ }
1338+
1339+ s.stagingRootPath = tempDir
1340+ os.MkdirAll(filepath.Join(tempDir, "/snap"), 0755)
1341+
1342+ dirs.SetRootDir(tempDir)
1343+ defer dirs.SetRootDir("/")
1344+ release.Series = s.Positional.Release
1345+
1346+ // we need to download and extract the squashfs snap
1347+ downloadedSnap := gadgetPackage
1348+ if !osutil.FileExists(gadgetPackage) {
1349+ repo := snappy.NewConfiguredUbuntuStoreSnapRepository()
1350+ snap, err := repo.Snap(gadgetPackage, s.Channel, nil)
1351+ if err != nil {
1352+ return fmt.Errorf("expected a gadget snaps: %s", err)
1353+ }
1354+
1355+ pb := progress.NewTextProgress()
1356+ downloadedSnap, err = repo.Download(snap, pb, nil)
1357+ if err != nil {
1358+ return err
1359+ }
1360+ }
1361+
1362+ // the fake snap needs to be in an expected location so that
1363+ // s.loadGadget() is happy
1364+ fakeGadgetDir := filepath.Join(tempDir, "/gadget/fake-gadget/1.0-fake/")
1365+ if err := os.MkdirAll(fakeGadgetDir, 0755); err != nil {
1366+ return err
1367+ }
1368+ cmd := exec.Command("unsquashfs", "-i", "-f", "-d", fakeGadgetDir, downloadedSnap)
1369+ if output, err := cmd.CombinedOutput(); err != nil {
1370+ return fmt.Errorf("snap unpack failed with: %v (%v)", err, string(output))
1371+ } else {
1372+ println(string(output))
1373+ }
1374+
1375+ if err := s.loadGadget(tempDir); err != nil {
1376+ return err
1377+ }
1378+
1379+ return nil
1380+}
1381+
1382+func (s *Snapper) loadGadget(systemPath string) error {
1383+ pkgs, err := filepath.Glob(filepath.Join(systemPath, "/gadget/*/*/meta/snap.yaml"))
1384+ if err != nil {
1385+ return err
1386+ }
1387+
1388+ // checking for len(pkgs) > 2 due to the 'current' symlink
1389+ if len(pkgs) == 0 {
1390+ return errors.New("no gadget package found")
1391+ } else if len(pkgs) > 2 || err != nil {
1392+ return errors.New("too many gadget packages installed")
1393+ }
1394+
1395+ f, err := ioutil.ReadFile(pkgs[0])
1396+ if err != nil {
1397+ return errors.New("failed to read gadget yaml")
1398+ }
1399+
1400+ var gadget diskimage.GadgetDescription
1401+ if err := yaml.Unmarshal([]byte(f), &gadget); err != nil {
1402+ return errors.New("cannot decode gadget yaml")
1403+ }
1404+ s.gadget = gadget
1405+ s.gadget.SetRoot(systemPath)
1406+
1407+ // ensure we can download and install snaps
1408+ arch.SetArchitecture(arch.ArchitectureType(s.gadget.Architecture()))
1409+
1410+ return nil
1411+}
1412+
1413+// Creates a YAML file inside the image that contains metadata relating
1414+// to the installation.
1415+func (s Snapper) writeInstallYaml(bootMountpoint string) error {
1416+ selfPath, err := exec.LookPath(os.Args[0])
1417+ if err != nil {
1418+ return err
1419+ }
1420+
1421+ bootDir := ""
1422+
1423+ switch s.gadget.Gadget.Hardware.Bootloader {
1424+ // Running systems use a bindmount for /boot/grub, but
1425+ // since the system isn't booted, create the file in the
1426+ // real location.
1427+ case "grub":
1428+ bootDir = "/EFI/ubuntu/grub"
1429+ }
1430+
1431+ installYamlFilePath := filepath.Join(bootMountpoint, bootDir, provisioning.InstallYamlFile)
1432+
1433+ i := provisioning.InstallYaml{
1434+ InstallMeta: provisioning.InstallMeta{
1435+ Timestamp: time.Now(),
1436+ },
1437+ InstallTool: provisioning.InstallTool{
1438+ Name: filepath.Base(selfPath),
1439+ Path: selfPath,
1440+ // FIXME: we don't know our own version yet :)
1441+ // Version: "???",
1442+ },
1443+ InstallOptions: provisioning.InstallOptions{
1444+ Size: s.size,
1445+ SizeUnit: "GB",
1446+ Output: s.Output,
1447+ Channel: s.Channel,
1448+ DevicePart: s.Development.DevicePart,
1449+ Gadget: s.Gadget,
1450+ OS: s.OS,
1451+ Kernel: s.Kernel,
1452+ DeveloperMode: s.Development.DeveloperMode,
1453+ },
1454+ }
1455+
1456+ data, err := yaml.Marshal(&i)
1457+ if err != nil {
1458+ return err
1459+ }
1460+
1461+ // the file isn't supposed to be modified, hence r/o.
1462+ return ioutil.WriteFile(installYamlFilePath, data, 0444)
1463+}
1464+
1465+func extractHWDescription(path string) (hw diskimage.HardwareDescription, err error) {
1466+ // hack to circumvent https://code.google.com/p/go/issues/detail?id=1435
1467+ if syscall.Getuid() == 0 {
1468+ runtime.GOMAXPROCS(1)
1469+ runtime.LockOSThread()
1470+
1471+ if err := sysutils.DropPrivs(); err != nil {
1472+ return hw, err
1473+ }
1474+ }
1475+
1476+ printOut("Searching for hardware.yaml in device part")
1477+ tmpdir, err := ioutil.TempDir("", "hardware")
1478+ if err != nil {
1479+ return hw, errors.New("cannot create tempdir to extract hardware.yaml from device part")
1480+ }
1481+ defer os.RemoveAll(tmpdir)
1482+
1483+ if out, err := exec.Command("tar", "xf", path, "-C", tmpdir, "hardware.yaml").CombinedOutput(); err != nil {
1484+ return hw, fmt.Errorf("failed to extract a hardware.yaml from the device part: %s", out)
1485+ }
1486+
1487+ data, err := ioutil.ReadFile(filepath.Join(tmpdir, "hardware.yaml"))
1488+ if err != nil {
1489+ return hw, err
1490+ }
1491+
1492+ err = yaml.Unmarshal([]byte(data), &hw)
1493+
1494+ return hw, err
1495+}
1496+
1497+func (s *Snapper) bindMount(d string) (string, error) {
1498+ src := filepath.Join(s.img.Writable(), "system-data", d)
1499+ dst := filepath.Join(s.img.System(), d)
1500+
1501+ if err := os.MkdirAll(src, 0755); err != nil {
1502+ return "", err
1503+ }
1504+ cmd := exec.Command("mount", "--bind", src, dst)
1505+ if o, err := cmd.CombinedOutput(); err != nil {
1506+ return "", fmt.Errorf("bind mount failed for %s to %s with: %s %v ", src, dst, err, string(o))
1507+ }
1508+ return dst, nil
1509+}
1510+
1511+func (s *Snapper) downloadOS(osPackage string) (string, error) {
1512+ if osPackage == "" {
1513+ return "", nil
1514+ }
1515+ // if its pointing to a local file, just return that
1516+ if _, err := os.Stat(osPackage); err == nil {
1517+ return osPackage, nil
1518+ }
1519+ release.Series = s.Positional.Release
1520+
1521+ m := snappy.NewConfiguredUbuntuStoreSnapRepository()
1522+ snap, err := m.Snap(osPackage, s.Channel, nil)
1523+ if err != nil {
1524+ return "", fmt.Errorf("failed to find os snap: %s", err)
1525+ }
1526+ pb := progress.NewTextProgress()
1527+ path, err := m.Download(snap, pb, nil)
1528+ if err != nil {
1529+ return "", err
1530+ }
1531+
1532+ return path, nil
1533+}
1534+
1535+func (s *Snapper) setup(systemImageFiles []Files) error {
1536+ printOut("Mounting...")
1537+ if err := s.img.Mount(); err != nil {
1538+ return err
1539+ }
1540+ defer func() {
1541+ printOut("Unmounting...")
1542+ if err := s.img.Unmount(); err != nil {
1543+ fmt.Println("WARNING: unexpected issue:", err)
1544+ }
1545+ }()
1546+
1547+ printOut("Provisioning...")
1548+ for i := range systemImageFiles {
1549+ if out, err := exec.Command("fakeroot", "tar", "--numeric-owner", "-axvf", systemImageFiles[i].FilePath, "-C", s.img.BaseMount()).CombinedOutput(); err != nil {
1550+ printOut(string(out))
1551+ return fmt.Errorf("issues while extracting: %s", out)
1552+ }
1553+ }
1554+
1555+ systemPath := s.img.System()
1556+
1557+ // setup a fake system
1558+ if s.gadget.PartitionLayout() == "minimal" {
1559+ if err := os.MkdirAll(systemPath, 0755); err != nil {
1560+ return err
1561+ }
1562+
1563+ // this is a bit terrible, we need to download the OS
1564+ // mount it, "sync dirs" (see below) and then we
1565+ // will need to download it again to install it properly
1566+ osSnap, err := s.downloadOS(s.OS)
1567+ if err != nil {
1568+ return err
1569+ }
1570+
1571+ // mount os snap
1572+ cmd := exec.Command("mount", osSnap, systemPath)
1573+ if o, err := cmd.CombinedOutput(); err != nil {
1574+ return fmt.Errorf("os snap mount failed with: %s %v ", err, string(o))
1575+ }
1576+ defer exec.Command("umount", systemPath).Run()
1577+
1578+ // we need to do what "writable-paths" normally does on
1579+ // boot for etc/systemd/system, i.e. copy all the stuff
1580+ // from the os into the writable partition. normally
1581+ // this is the job of the initrd, however it won't touch
1582+ // the dir if there are files in there already. and a
1583+ // kernel/os install will create auto-mount units in there
1584+ src := filepath.Join(systemPath, "etc", "systemd", "system")
1585+ dst := filepath.Join(s.img.Writable(), "system-data", "etc", "systemd")
1586+ if err := os.MkdirAll(dst, 0755); err != nil {
1587+ return err
1588+ }
1589+ cmd = exec.Command("cp", "-a", src, dst)
1590+ if o, err := cmd.CombinedOutput(); err != nil {
1591+ return fmt.Errorf("copy failed: %s %s", err, o)
1592+ }
1593+
1594+ // bind mount all relevant dirs
1595+ for _, d := range []string{"snap", "var/snap", "var/lib/snapd", "etc/systemd/system/", "tmp"} {
1596+ dst, err := s.bindMount(d)
1597+ if err != nil {
1598+ return err
1599+ }
1600+ defer exec.Command("umount", dst).Run()
1601+ }
1602+
1603+ // bind mount /boot/efi
1604+ dst = filepath.Join(systemPath, "/boot/efi")
1605+ cmd = exec.Command("mount", "--bind", s.img.Boot(), dst)
1606+ if o, err := cmd.CombinedOutput(); err != nil {
1607+ return fmt.Errorf("boot bind mount failed with: %s %v ", err, string(o))
1608+ }
1609+ defer exec.Command("umount", dst).Run()
1610+ switch s.gadget.Gadget.Hardware.Bootloader {
1611+ case "grub":
1612+ // grub needs this
1613+ grubUbuntu := filepath.Join(s.img.Boot(), "EFI/ubuntu/grub")
1614+ os.MkdirAll(grubUbuntu, 0755)
1615+
1616+ // and /boot/grub
1617+ src = grubUbuntu
1618+ dst = filepath.Join(systemPath, "/boot/grub")
1619+ cmd = exec.Command("mount", "--bind", src, dst)
1620+ if o, err := cmd.CombinedOutput(); err != nil {
1621+ return fmt.Errorf("boot/ubuntu bind mount failed with: %s %v ", err, string(o))
1622+ }
1623+ defer exec.Command("umount", dst).Run()
1624+
1625+ // TERRIBLE but we need a /boot/grub/grub.cfg so that
1626+ // the kernel and os snap can be installed
1627+ glob, err := filepath.Glob(filepath.Join(s.stagingRootPath, "gadget", "*", "*", "grub.cfg"))
1628+ if err != nil {
1629+ return fmt.Errorf("grub.cfg glob failed: %s", err)
1630+ }
1631+ if len(glob) != 1 {
1632+ return fmt.Errorf("can not find a valid grub.cfg, found %v instead", len(glob))
1633+ }
1634+ gadgetGrubCfg := glob[0]
1635+ cmd = exec.Command("cp", gadgetGrubCfg, grubUbuntu)
1636+ o, err := cmd.CombinedOutput()
1637+ if err != nil {
1638+ return fmt.Errorf("failed to copy %s %s", err, o)
1639+ }
1640+ case "u-boot":
1641+ src = s.img.Boot()
1642+ dst = filepath.Join(systemPath, "/boot/uboot")
1643+ cmd = exec.Command("mount", "--bind", src, dst)
1644+ if o, err := cmd.CombinedOutput(); err != nil {
1645+ return fmt.Errorf("boot/ubuntu bind mount failed with: %s %v ", err, string(o))
1646+ }
1647+ defer exec.Command("umount", dst).Run()
1648+ }
1649+ }
1650+
1651+ if err := s.img.SetupBoot(); err != nil {
1652+ return err
1653+ }
1654+
1655+ if err := s.install(systemPath); err != nil {
1656+ return err
1657+ }
1658+
1659+ for i := range s.customizationFunc {
1660+ if err := s.customizationFunc[i](); err != nil {
1661+ return err
1662+ }
1663+ }
1664+
1665+ return s.writeInstallYaml(s.img.Boot())
1666+>>>>>>> MERGE-SOURCE
1667 }
1668
1669 // deploy orchestrates the priviledged part of the setup
1670+<<<<<<< TREE
1671 func (s *Snapper) deploy(systemImage *ubuntuimage.Image, filePathChan <-chan string) error {
1672+=======
1673+func (s *Snapper) deploy(systemImageFiles []Files) error {
1674+ // hack to circumvent https://code.google.com/p/go/issues/detail?id=1435
1675+ runtime.GOMAXPROCS(1)
1676+ runtime.LockOSThread()
1677+ if err := sysutils.EscalatePrivs(); err != nil {
1678+ return err
1679+ }
1680+ defer sysutils.DropPrivs()
1681+
1682+ printOut("Formatting...")
1683+ if err := s.img.Format(); err != nil {
1684+ return err
1685+ }
1686+
1687+ if err := s.setup(systemImageFiles); err != nil {
1688+ return err
1689+ }
1690+
1691+>>>>>>> MERGE-SOURCE
1692 return nil
1693 }
1694
1695+<<<<<<< TREE
1696 func (s *Snapper) create() error {
1697 return fmt.Errorf(`Building core images is currently not supported.
1698
1699 Images for ubuntu-core 15.04 can be build with the ppa:snappy-dev/tools.
1700 Building images for ubuntu-core 16.04 will be supported by this tool soon.
1701 `)
1702+=======
1703+func (s Snapper) printSummary() {
1704+ fmt.Println("New image complete")
1705+ fmt.Println("Summary:")
1706+ fmt.Println(" Output:", s.Output)
1707+ fmt.Println(" Architecture:", s.gadget.Architecture())
1708+ fmt.Println(" Channel:", s.Channel)
1709+ fmt.Println(" Version:", globalArgs.Revision)
1710+}
1711+
1712+func (s *Snapper) getSystemImage() ([]Files, error) {
1713+ var devicePart string
1714+ if s.Development.DevicePart != "" {
1715+ p, err := expandFile(s.Development.DevicePart)
1716+ if err != nil {
1717+ return nil, err
1718+ }
1719+
1720+ fmt.Println("Using a custom OS or Kernel part will prevent updates for these components")
1721+
1722+ devicePart = p
1723+ }
1724+
1725+ fmt.Println("Fetching information from server...")
1726+ systemImage, err := s.systemImage()
1727+ if err != nil {
1728+ return nil, err
1729+ }
1730+
1731+ filesChan := make(chan Files, len(systemImage.Files))
1732+ sigFiles := ubuntuimage.GetGPGFiles()
1733+
1734+ fmt.Println("Downloading and setting up...")
1735+
1736+ go func() {
1737+ sigFilesChan := make(chan Files, len(sigFiles))
1738+ defer close(sigFilesChan)
1739+
1740+ for _, f := range sigFiles {
1741+ bitDownloader(f, sigFilesChan, globalArgs.Server, cacheDir)
1742+ }
1743+ }()
1744+
1745+ filePaths := make([]Files, 0, len(systemImage.Files))
1746+ hwChan := make(chan diskimage.HardwareDescription)
1747+
1748+ go func() {
1749+ for i := 0; i < len(systemImage.Files); i++ {
1750+ f := <-filesChan
1751+
1752+ if isDevicePart(f.FilePath) {
1753+ devicePart = f.FilePath
1754+
1755+ if hardware, err := extractHWDescription(f.FilePath); err != nil {
1756+ fmt.Println("Failed to read harware.yaml from device part, provisioning may fail:", err)
1757+ } else {
1758+ hwChan <- hardware
1759+ }
1760+ }
1761+
1762+ printOut("Download finished for", f.FilePath)
1763+ filePaths = append(filePaths, f)
1764+ }
1765+ close(hwChan)
1766+ close(filesChan)
1767+ }()
1768+
1769+ for _, f := range systemImage.Files {
1770+ if devicePart != "" && isDevicePart(f.Path) {
1771+ printOut("Using a custom device tarball")
1772+ filesChan <- Files{FilePath: devicePart}
1773+ } else {
1774+ go bitDownloader(f, filesChan, globalArgs.Server, cacheDir)
1775+ }
1776+ }
1777+
1778+ s.hardware = <-hwChan
1779+
1780+ return filePaths, nil
1781+}
1782+
1783+func (s *Snapper) create() (err error) {
1784+ if err := s.sanityCheck(); err != nil {
1785+ return err
1786+ }
1787+
1788+ if s.StoreID != "" {
1789+ fmt.Println("Setting store id to", s.StoreID)
1790+ os.Setenv("UBUNTU_STORE_ID", s.StoreID)
1791+ }
1792+
1793+ fmt.Println("Determining gadget configuration")
1794+ if err := s.extractGadget(s.Gadget); err != nil {
1795+ return err
1796+ }
1797+ defer os.RemoveAll(s.stagingRootPath)
1798+
1799+ // hack to circumvent https://code.google.com/p/go/issues/detail?id=1435
1800+ runtime.GOMAXPROCS(1)
1801+ runtime.LockOSThread()
1802+ if err := sysutils.DropPrivs(); err != nil {
1803+ return err
1804+ }
1805+
1806+ systemImageFiles := []Files{}
1807+ switch s.gadget.Gadget.Hardware.PartitionLayout {
1808+ case "minimal":
1809+ if s.OS == "" && s.Kernel == "" {
1810+ return errors.New("kernel and os have to be specified to support partition-layout: minimal")
1811+ }
1812+ }
1813+
1814+ switch s.gadget.Gadget.Hardware.Bootloader {
1815+ case "grub":
1816+ legacy := isLegacy(s.Positional.Release, s.Channel, globalArgs.Revision)
1817+ if legacy {
1818+ printOut("Using legacy setup")
1819+ }
1820+
1821+ s.img = diskimage.NewCoreGrubImage(s.Output, s.size, s.flavor.rootSize(), s.hardware, s.gadget, legacy, "gpt")
1822+ case "u-boot":
1823+ label := "msdos"
1824+ if s.gadget.Architecture() == archArm64 {
1825+ label = "gpt"
1826+ }
1827+ s.img = diskimage.NewCoreUBootImage(s.Output, s.size, s.flavor.rootSize(), s.hardware, s.gadget, label)
1828+ default:
1829+ return errors.New("no hardware description in Gadget snap")
1830+ }
1831+
1832+ printOut("Partitioning...")
1833+ if err := s.img.Partition(); err != nil {
1834+ return err
1835+ }
1836+ defer func() {
1837+ if err != nil {
1838+ os.Remove(s.Output)
1839+ }
1840+ }()
1841+
1842+ // Handle SIGINT and SIGTERM.
1843+ go func() {
1844+ ch := make(chan os.Signal)
1845+ signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
1846+
1847+ for sig := range ch {
1848+ printOut("Received", sig, "... ignoring")
1849+ }
1850+ }()
1851+
1852+ // Execute the following code with escalated privs and drop them when done
1853+ if err := s.deploy(systemImageFiles); err != nil {
1854+ return err
1855+ }
1856+
1857+ if err := s.img.FlashExtra(); err != nil {
1858+ return err
1859+ }
1860+
1861+ s.printSummary()
1862+
1863+ return nil
1864+}
1865+
1866+func isLegacy(release, channel string, revision int) bool {
1867+ if release != "15.04" {
1868+ return false
1869+ }
1870+
1871+ switch channel {
1872+ case "edge":
1873+ return revision <= 149
1874+ case "alpha":
1875+ return revision <= 9
1876+ case "stable":
1877+ return revision <= 4
1878+ }
1879+
1880+ return false
1881+>>>>>>> MERGE-SOURCE
1882 }

Subscribers

People subscribed via source and target branches