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

Proposed by Michael Vogt
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 Approve
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.
Revision history for this message
Michael Vogt (mvo) wrote :

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

Revision history for this message
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...

Revision history for this message
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
Revision history for this message
Sergio Schvezov (sergiusens) :
Revision history for this message
Michael Vogt (mvo) wrote :

This is updated and all comments are addressed now.

Revision history for this message
Sergio Schvezov (sergiusens) :
review: Approve
Revision history for this message
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

Update to latest snappy code

265. By Michael Vogt

ppa uploads

266. By Michael Vogt

fix bind mounts

267. By Michael Vogt

update to the latest api

268. By Michael Vogt

manually enable all snaps on the system

269. By Michael Vogt

remove debug code

270. By Michael Vogt

update for latest snappy

271. By Michael Vogt

add check for having systemctl

272. By Michael Vogt

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

273. By Michael Vogt

fix squashfs format issue

274. By Michael Vogt

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

275. By Michael Vogt

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

276. By Michael Vogt

fix for latest api change

Unmerged revisions

276. By Michael Vogt

fix for latest api change

275. By Michael Vogt

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

274. By Michael Vogt

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

273. By Michael Vogt

fix squashfs format issue

272. By Michael Vogt

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

271. By Michael Vogt

add check for having systemctl

270. By Michael Vogt

update for latest snappy

269. By Michael Vogt

remove debug code

268. By Michael Vogt

manually enable all snaps on the system

267. By Michael Vogt

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