Merge lp:~mvo/goget-ubuntu-touch/minimal-first-boot into lp:goget-ubuntu-touch
- minimal-first-boot
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~mvo/goget-ubuntu-touch/minimal-first-boot |
Merge into: | lp:goget-ubuntu-touch |
Diff against target: |
1819 lines (+1145/-164) (has conflicts) 17 files modified
debian/changelog (+15/-0) debian/control (+14/-0) dependencies.tsv (+6/-1) diskimage/bootloader.go (+21/-12) diskimage/common.go (+99/-80) diskimage/common_test.go (+14/-14) diskimage/core_grub.go (+31/-27) diskimage/core_uboot.go (+32/-16) diskimage/partition.go (+1/-0) snapcraft.yaml (+35/-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/main.go (+1/-1) ubuntu-device-flash/snappy.go (+513/-5) ubuntu-device-flash/snappy_compat_yaml.go (+124/-0) 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:~mvo/goget-ubuntu-touch/minimal-first-boot |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email: mp+296646@code.launchpad.net |
Commit message
Description of the change
This implements creating a ubuntu core 16 image with minimal support from snapd (grub only for now). Most importantly the snap install part is dropped and the code only downloads and drops the files into the right location.
This is the basis for the `firstboot` part of snapd. Also note that this is only a temporary tree that will be replaced with ubuntu-image. However ubuntu-image can still use this code (and layout) as a blueprint how to generate the basic dir layout. Plus for ubuntu-image we will need something like "snap-bootstrap" as the python-code will not be able to call into the go code.
- 283. By Michael Vogt
-
prefix first-boot snaps with "first-boot"
- 284. By Michael Vogt
-
use .sideinfo instead of .meta
- 285. By Michael Vogt
-
make u-d-f install the snap under exactly the same name as snappy would expect it
- 286. By Michael Vogt
-
only create .sideinfo if we actually have sideinfo
- 287. By Michael Vogt
-
use `snap boostrap` for os,kernel,gadget install
- 288. By Michael Vogt
-
add channel and store-id to boostrap.yaml
- 289. By Michael Vogt
-
add extra installs
- 290. By Michael Vogt
-
remove dead code
- 291. By Michael Vogt
-
use new `snap weld`
- 292. By Michael Vogt
-
update to latest create-image api
- 293. By Michael Vogt
-
cherry pick r290 from lp:~mvo/goget-ubuntu-touch/minimal-first-boot-no-prepare-image
- 294. By Michael Vogt
-
fix copy
- 295. By Michael Vogt
-
take model assertion as input instead of of --kernel/--os
- 296. By Michael Vogt
-
ubuntu-
device- flash/main. go: fix cmdline parsing - 297. By Michael Vogt
-
add snapcraft.yaml that includes the "snap" command
- 298. By Michael Vogt
-
remove some dead code
- 299. By Michael Vogt
-
remove boot-assets/
uEnv.txt from compat yaml
Unmerged revisions
- 299. By Michael Vogt
-
remove boot-assets/
uEnv.txt from compat yaml - 298. By Michael Vogt
-
remove some dead code
- 297. By Michael Vogt
-
add snapcraft.yaml that includes the "snap" command
- 296. By Michael Vogt
-
ubuntu-
device- flash/main. go: fix cmdline parsing - 295. By Michael Vogt
-
take model assertion as input instead of of --kernel/--os
- 294. By Michael Vogt
-
fix copy
- 293. By Michael Vogt
-
cherry pick r290 from lp:~mvo/goget-ubuntu-touch/minimal-first-boot-no-prepare-image
- 292. By Michael Vogt
-
update to latest create-image api
- 291. By Michael Vogt
-
use new `snap weld`
- 290. By Michael Vogt
-
remove dead code
Preview Diff
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2016-08-05 13:21:10 +0000 |
3 | +++ debian/changelog 2016-09-04 15:15:47 +0000 |
4 | @@ -1,3 +1,4 @@ |
5 | +<<<<<<< TREE |
6 | goget-ubuntu-touch (0.34+16.10.20160805-0ubuntu1) yakkety; urgency=medium |
7 | |
8 | [ Andrea Bernabei ] |
9 | @@ -34,6 +35,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-09-04 15:15:47 +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-09-04 15:15:47 +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-09-04 15:15:47 +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-09-04 15:15:47 +0000 |
137 | @@ -9,7 +9,6 @@ |
138 | |
139 | import ( |
140 | "bufio" |
141 | - "errors" |
142 | "fmt" |
143 | "io/ioutil" |
144 | "os" |
145 | @@ -17,8 +16,6 @@ |
146 | "path/filepath" |
147 | "strings" |
148 | "syscall" |
149 | - |
150 | - "launchpad.net/goget-ubuntu-touch/sysutils" |
151 | ) |
152 | |
153 | // This program is free software: you can redistribute it and/or modify it |
154 | @@ -47,10 +44,6 @@ |
155 | initrdFileName = "initrd.img" |
156 | ) |
157 | |
158 | -const ( |
159 | - partLayoutSystemAB = "system-AB" |
160 | -) |
161 | - |
162 | var ( |
163 | syscallSync = syscall.Sync |
164 | ) |
165 | @@ -88,9 +81,16 @@ |
166 | } |
167 | |
168 | type BootAssetRawPartitions struct { |
169 | +<<<<<<< TREE |
170 | Name string `yaml:"name"` |
171 | Size string `yaml:"size"` |
172 | Type string `yaml:"type"` |
173 | +======= |
174 | + Name string `yaml:"name"` |
175 | + Size int `yaml:"size"` |
176 | + Pos int `yaml:"pos"` |
177 | + Type string `yaml:"type"` |
178 | +>>>>>>> MERGE-SOURCE |
179 | } |
180 | |
181 | type BootAssetFiles struct { |
182 | @@ -107,11 +107,11 @@ |
183 | RawPartitions []BootAssetRawPartitions `yaml:"raw-partitions,omitempty"` |
184 | } |
185 | |
186 | -type OemDescription struct { |
187 | +type GadgetDescription struct { |
188 | Name string `yaml:"name"` |
189 | Version string `yaml:"version"` |
190 | |
191 | - OEM struct { |
192 | + Gadget struct { |
193 | Hardware struct { |
194 | Bootloader string `yaml:"bootloader"` |
195 | PartitionLayout string `yaml:"partition-layout"` |
196 | @@ -129,7 +129,7 @@ |
197 | Store *struct { |
198 | ID string `yaml:"id,omitempty"` |
199 | } |
200 | - } `yaml:"oem,omitempty"` |
201 | + } `yaml:"gadget,omitempty"` |
202 | |
203 | Config struct { |
204 | UbuntuCore struct { |
205 | @@ -140,53 +140,42 @@ |
206 | rootDir string |
207 | } |
208 | |
209 | -func (o *OemDescription) SetRoot(rootDir string) { |
210 | +func (o *GadgetDescription) SetRoot(rootDir string) { |
211 | o.rootDir = rootDir |
212 | } |
213 | |
214 | // SystemParts returns the system labels depending on the partition layout. |
215 | // |
216 | // The default is to return a flat structure for any unknown layout. |
217 | -func (o *OemDescription) SystemParts() []string { |
218 | - switch o.OEM.Hardware.PartitionLayout { |
219 | - case partLayoutSystemAB: |
220 | - return []string{"a", "b"} |
221 | +func (o *GadgetDescription) SystemParts() []string { |
222 | + switch o.Gadget.Hardware.PartitionLayout { |
223 | default: |
224 | return []string{""} |
225 | } |
226 | } |
227 | |
228 | -func (o OemDescription) InstallPath() (string, error) { |
229 | - glob, err := filepath.Glob(fmt.Sprintf("%s/oem/%s/current", o.rootDir, o.Name)) |
230 | - if err != nil { |
231 | - return "", err |
232 | - } |
233 | - |
234 | - if len(glob) != 1 { |
235 | - return "", errors.New("oem package not installed") |
236 | - } |
237 | - |
238 | - return glob[0], nil |
239 | -} |
240 | - |
241 | -func (o OemDescription) Architecture() string { |
242 | - return o.OEM.Hardware.Architecture |
243 | -} |
244 | - |
245 | -func (o *OemDescription) SetArchitecture(architecture string) { |
246 | - o.OEM.Hardware.Architecture = architecture |
247 | -} |
248 | - |
249 | -func (o OemDescription) PartitionLayout() string { |
250 | - return o.OEM.Hardware.PartitionLayout |
251 | -} |
252 | - |
253 | -func (o OemDescription) Platform() string { |
254 | - return o.OEM.Hardware.Platform |
255 | -} |
256 | - |
257 | -func (o *OemDescription) SetPlatform(platform string) { |
258 | - o.OEM.Hardware.Platform = platform |
259 | +func (o GadgetDescription) InstallPath() (string, error) { |
260 | + return o.rootDir, nil |
261 | +} |
262 | + |
263 | +func (o GadgetDescription) Architecture() string { |
264 | + return o.Gadget.Hardware.Architecture |
265 | +} |
266 | + |
267 | +func (o *GadgetDescription) SetArchitecture(architecture string) { |
268 | + o.Gadget.Hardware.Architecture = architecture |
269 | +} |
270 | + |
271 | +func (o GadgetDescription) PartitionLayout() string { |
272 | + return o.Gadget.Hardware.PartitionLayout |
273 | +} |
274 | + |
275 | +func (o GadgetDescription) Platform() string { |
276 | + return o.Gadget.Hardware.Platform |
277 | +} |
278 | + |
279 | +func (o *GadgetDescription) SetPlatform(platform string) { |
280 | + o.Gadget.Hardware.Platform = platform |
281 | } |
282 | |
283 | func sectorSize(dev string) (string, error) { |
284 | @@ -200,6 +189,7 @@ |
285 | |
286 | // BaseImage implements the basic primitives to manage images. |
287 | type BaseImage struct { |
288 | +<<<<<<< TREE |
289 | baseMount string |
290 | hardware HardwareDescription |
291 | location string |
292 | @@ -209,8 +199,22 @@ |
293 | size int64 |
294 | rootSize int |
295 | label string |
296 | +======= |
297 | + baseMount string |
298 | + bindMounts []string |
299 | + hardware HardwareDescription |
300 | + location string |
301 | + gadget GadgetDescription |
302 | + parts []partition |
303 | + partCount int |
304 | + size int64 |
305 | + rootSize int |
306 | + label string |
307 | +>>>>>>> MERGE-SOURCE |
308 | } |
309 | |
310 | +var bindMounts = []string{"dev", "sys", "proc", filepath.Join("sys", "firmware")} |
311 | + |
312 | // Mount mounts the image. This also maps the loop device. |
313 | func (img *BaseImage) Mount() error { |
314 | if err := img.doMap(); err != nil { |
315 | @@ -267,8 +271,27 @@ |
316 | } |
317 | img.baseMount = baseMount |
318 | |
319 | + mountpoints := make([]string, 0, len(bindMounts)) |
320 | + if img.gadget.PartitionLayout() == "minimal" { |
321 | + mountpoints = bindMounts |
322 | + |
323 | + for _, d := range mountpoints { |
324 | + p := filepath.Join(baseMount, d) |
325 | + |
326 | + if err := os.MkdirAll(p, 0755); err != nil { |
327 | + return err |
328 | + } |
329 | + |
330 | + printOut("Bind mounting", d, "to", p) |
331 | + if err := bindMount(filepath.Join("/", d), p); err != nil { |
332 | + return err |
333 | + } |
334 | + |
335 | + img.bindMounts = append(img.bindMounts, p) |
336 | + } |
337 | + } |
338 | + |
339 | return nil |
340 | - |
341 | } |
342 | |
343 | // Unmount unmounts the image. This also unmaps the loop device. |
344 | @@ -283,6 +306,13 @@ |
345 | panic("No base mountpoint set") |
346 | } |
347 | |
348 | + for i := len(img.bindMounts) - 1; i >= 0; i-- { |
349 | + if err := unmount(img.bindMounts[i]); err != nil { |
350 | + return err |
351 | + } |
352 | + } |
353 | + img.bindMounts = nil |
354 | + |
355 | syscallSync() |
356 | |
357 | for _, part := range img.parts { |
358 | @@ -466,55 +496,28 @@ |
359 | } |
360 | |
361 | func (img *BaseImage) GenericBootSetup(bootPath string) error { |
362 | - // origins |
363 | - hardwareYamlPath := filepath.Join(img.baseMount, hardwareFileName) |
364 | - kernelPath := filepath.Join(img.baseMount, img.hardware.Kernel) |
365 | - initrdPath := filepath.Join(img.baseMount, img.hardware.Initrd) |
366 | - |
367 | - // populate both A/B |
368 | - for _, part := range img.oem.SystemParts() { |
369 | - path := filepath.Join(bootPath, part) |
370 | - |
371 | - printOut("Setting up", path) |
372 | - |
373 | - if err := os.MkdirAll(path, 0755); err != nil { |
374 | - return err |
375 | - } |
376 | - |
377 | - if err := sysutils.CopyFile(hardwareYamlPath, filepath.Join(path, hardwareFileName)); err != nil { |
378 | - return err |
379 | - } |
380 | - |
381 | - if err := sysutils.CopyFile(kernelPath, filepath.Join(path, kernelFileName)); err != nil { |
382 | - return err |
383 | - } |
384 | - |
385 | - if err := sysutils.CopyFile(initrdPath, filepath.Join(path, initrdFileName)); err != nil { |
386 | - return err |
387 | - } |
388 | - } |
389 | - |
390 | - oemRoot, err := img.oem.InstallPath() |
391 | + gadgetRoot, err := img.gadget.InstallPath() |
392 | if err != nil { |
393 | return err |
394 | } |
395 | |
396 | - return setupBootAssetFiles(img.Boot(), bootPath, oemRoot, img.oem.OEM.Hardware.BootAssets.Files) |
397 | + return setupBootAssetFiles(img.Boot(), bootPath, gadgetRoot, img.gadget.Gadget.Hardware.BootAssets.Files) |
398 | } |
399 | |
400 | func (img *BaseImage) FlashExtra() error { |
401 | - oemRoot, err := img.oem.InstallPath() |
402 | + gadgetRoot, err := img.gadget.InstallPath() |
403 | if err != nil { |
404 | return err |
405 | } |
406 | |
407 | - if bootAssets := img.oem.OEM.Hardware.BootAssets; bootAssets != nil { |
408 | + if bootAssets := img.gadget.Gadget.Hardware.BootAssets; bootAssets != nil { |
409 | if bootAssets.RawPartitions != nil { |
410 | if err := setupBootAssetRawPartitions(img.location, img.partCount, bootAssets.RawPartitions); err != nil { |
411 | return err |
412 | } |
413 | } |
414 | - return setupBootAssetRawFiles(img.location, oemRoot, bootAssets.RawFiles) |
415 | + |
416 | + return setupBootAssetRawFiles(img.location, gadgetRoot, bootAssets.RawFiles) |
417 | } |
418 | |
419 | return nil |
420 | @@ -525,3 +528,19 @@ |
421 | fmt.Println(args...) |
422 | } |
423 | } |
424 | + |
425 | +func bindMount(src, dst string) error { |
426 | + if out, err := exec.Command("mount", "--bind", src, dst).CombinedOutput(); err != nil { |
427 | + return fmt.Errorf("issues while bind mounting: %s", out) |
428 | + } |
429 | + |
430 | + return nil |
431 | +} |
432 | + |
433 | +func unmount(dst string) error { |
434 | + if out, err := exec.Command("umount", dst).CombinedOutput(); err != nil { |
435 | + return fmt.Errorf("issues while unmounting: %s", out) |
436 | + } |
437 | + |
438 | + return nil |
439 | +} |
440 | |
441 | === modified file 'diskimage/common_test.go' |
442 | --- diskimage/common_test.go 2015-09-09 16:00:01 +0000 |
443 | +++ diskimage/common_test.go 2016-09-04 15:15:47 +0000 |
444 | @@ -28,7 +28,7 @@ |
445 | |
446 | type CommonTestSuite struct { |
447 | tmpdir string |
448 | - oem OemDescription |
449 | + gadget GadgetDescription |
450 | packageInst string |
451 | } |
452 | |
453 | @@ -36,27 +36,27 @@ |
454 | |
455 | func (s *CommonTestSuite) SetUpTest(c *C) { |
456 | s.tmpdir = c.MkDir() |
457 | - s.oem = OemDescription{Name: "packagename", Version: "42"} |
458 | - s.packageInst = s.oem.Name |
459 | + s.gadget = GadgetDescription{Name: "packagename", Version: "42"} |
460 | + s.packageInst = s.gadget.Name |
461 | } |
462 | |
463 | func (s *CommonTestSuite) TestOemInstallPath(c *C) { |
464 | - err := os.MkdirAll(filepath.Join(s.tmpdir, "oem", s.packageInst, "current"), 0755) |
465 | - c.Assert(err, IsNil) |
466 | - |
467 | - s.oem.SetRoot(s.tmpdir) |
468 | - installPath, err := s.oem.InstallPath() |
469 | - |
470 | - c.Assert(err, IsNil) |
471 | - c.Assert(installPath, Equals, filepath.Join(s.tmpdir, "oem/packagename/current")) |
472 | + err := os.MkdirAll(filepath.Join(s.tmpdir, "gadget", s.packageInst, "current"), 0755) |
473 | + c.Assert(err, IsNil) |
474 | + |
475 | + s.gadget.SetRoot(s.tmpdir) |
476 | + installPath, err := s.gadget.InstallPath() |
477 | + |
478 | + c.Assert(err, IsNil) |
479 | + c.Assert(installPath, Equals, filepath.Join(s.tmpdir, "gadget/packagename/current")) |
480 | } |
481 | |
482 | func (s *CommonTestSuite) TestOemInstallPathNoOem(c *C) { |
483 | - err := os.MkdirAll(filepath.Join(s.tmpdir, "oem", s.packageInst), 0755) |
484 | + err := os.MkdirAll(filepath.Join(s.tmpdir, "gadget", s.packageInst), 0755) |
485 | c.Assert(err, IsNil) |
486 | |
487 | - s.oem.SetRoot(s.tmpdir) |
488 | - installPath, err := s.oem.InstallPath() |
489 | + s.gadget.SetRoot(s.tmpdir) |
490 | + installPath, err := s.gadget.InstallPath() |
491 | |
492 | c.Assert(err, NotNil) |
493 | c.Assert(installPath, Equals, "") |
494 | |
495 | === modified file 'diskimage/core_grub.go' |
496 | --- diskimage/core_grub.go 2016-04-05 09:32:48 +0000 |
497 | +++ diskimage/core_grub.go 2016-09-04 15:15:47 +0000 |
498 | @@ -5,6 +5,7 @@ |
499 | // |
500 | // Written by Sergio Schvezov <sergio.schvezov@canonical.com> |
501 | // |
502 | + |
503 | package diskimage |
504 | |
505 | import ( |
506 | @@ -31,25 +32,40 @@ |
507 | // You should have received a copy of the GNU General Public License along |
508 | // with this program. If not, see <http://www.gnu.org/licenses/>. |
509 | |
510 | +// CoreGrubImage holds the logic to create a core image using grub. |
511 | type CoreGrubImage struct { |
512 | BaseImage |
513 | |
514 | legacyGrub bool |
515 | } |
516 | |
517 | -func NewCoreGrubImage(location string, size int64, rootSize int, hw HardwareDescription, oem OemDescription, updateGrub bool, label string) *CoreGrubImage { |
518 | +// NewCoreGrubImage creates a new instance of CoreGrubImage |
519 | +func NewCoreGrubImage(location string, size int64, rootSize int, hw HardwareDescription, gadget GadgetDescription, updateGrub bool, label string) *CoreGrubImage { |
520 | + var partCount int |
521 | + switch gadget.PartitionLayout() { |
522 | + case "minimal": |
523 | + partCount = 3 |
524 | + } |
525 | + |
526 | return &CoreGrubImage{ |
527 | BaseImage: BaseImage{ |
528 | location: location, |
529 | size: size, |
530 | rootSize: rootSize, |
531 | hardware: hw, |
532 | +<<<<<<< TREE |
533 | oem: oem, |
534 | partCount: 5, |
535 | label: label, |
536 | +======= |
537 | + gadget: gadget, |
538 | + partCount: partCount, |
539 | + label: label, |
540 | +>>>>>>> MERGE-SOURCE |
541 | }, |
542 | legacyGrub: updateGrub, |
543 | } |
544 | + |
545 | } |
546 | |
547 | const grubCfgContent = `# console only, no graphics/vga |
548 | @@ -75,9 +91,10 @@ |
549 | } |
550 | |
551 | parted.addPart(grubLabel, "", fsNone, 4) |
552 | - parted.addPart(bootLabel, bootDir, fsFat32, 128) |
553 | - parted.addPart(systemALabel, systemADir, fsExt4, img.rootSize) |
554 | - parted.addPart(systemBLabel, systemBDir, fsExt4, img.rootSize) |
555 | + switch img.gadget.PartitionLayout() { |
556 | + case "minimal": |
557 | + parted.addPart(bootLabel, bootDir, fsFat32, 64) |
558 | + } |
559 | parted.addPart(writableLabel, writableDir, fsExt4, -1) |
560 | |
561 | parted.setBoot(2) |
562 | @@ -88,6 +105,7 @@ |
563 | return parted.create(img.location) |
564 | } |
565 | |
566 | +// SetupBoot sets up the bootloader logic for the image. |
567 | func (img *CoreGrubImage) SetupBoot() error { |
568 | if !img.legacyGrub { |
569 | // destinations |
570 | @@ -121,14 +139,14 @@ |
571 | return errors.New("cannot determined absolute path for output image") |
572 | } |
573 | |
574 | - rootDevPath := filepath.Join(img.System(), "root_dev") |
575 | + rootDevPath := filepath.Join(img.System(), "tmp", "root_dev") |
576 | |
577 | - if f, err := os.Create(rootDevPath); err != nil { |
578 | + f, err := os.Create(rootDevPath) |
579 | + if err != nil { |
580 | return err |
581 | - } else { |
582 | - f.Close() |
583 | - defer os.Remove(rootDevPath) |
584 | } |
585 | + f.Close() |
586 | + defer os.Remove(rootDevPath) |
587 | |
588 | if err := bindMount(outputPath, rootDevPath); err != nil { |
589 | return err |
590 | @@ -165,7 +183,7 @@ |
591 | |
592 | var grubTarget string |
593 | |
594 | - arch := img.oem.Architecture() |
595 | + arch := img.gadget.Architecture() |
596 | |
597 | switch arch { |
598 | case "armhf": |
599 | @@ -174,13 +192,15 @@ |
600 | grubTarget = "x86_64-efi" |
601 | case "i386": |
602 | grubTarget = "i386-efi" |
603 | + case "arm64": |
604 | + grubTarget = "arm64-efi" |
605 | default: |
606 | return fmt.Errorf("unsupported architecture for GRUB on EFI: %s", arch) |
607 | } |
608 | |
609 | if arch == "amd64" || arch == "i386" { |
610 | // install grub BIOS support |
611 | - if out, err := exec.Command("chroot", img.System(), "grub-install", "/root_dev").CombinedOutput(); err != nil { |
612 | + if out, err := exec.Command("chroot", img.System(), "grub-install", "tmp/root_dev").CombinedOutput(); err != nil { |
613 | return fmt.Errorf("unable to install grub (BIOS): %s", out) |
614 | } |
615 | } |
616 | @@ -233,19 +253,3 @@ |
617 | |
618 | return nil |
619 | } |
620 | - |
621 | -func bindMount(src, dst string) error { |
622 | - if out, err := exec.Command("mount", "--bind", src, dst).CombinedOutput(); err != nil { |
623 | - return fmt.Errorf("issues while bind mounting: %s", out) |
624 | - } |
625 | - |
626 | - return nil |
627 | -} |
628 | - |
629 | -func unmount(dst string) error { |
630 | - if out, err := exec.Command("umount", dst).CombinedOutput(); err != nil { |
631 | - return fmt.Errorf("issues while unmounting: %s", out) |
632 | - } |
633 | - |
634 | - return nil |
635 | -} |
636 | |
637 | === modified file 'diskimage/core_uboot.go' |
638 | --- diskimage/core_uboot.go 2016-04-05 09:32:48 +0000 |
639 | +++ diskimage/core_uboot.go 2016-09-04 15:15:47 +0000 |
640 | @@ -66,16 +66,27 @@ |
641 | Bootloader []string `yaml:"bootloader"` |
642 | } |
643 | |
644 | -func NewCoreUBootImage(location string, size int64, rootSize int, hw HardwareDescription, oem OemDescription, label string) *CoreUBootImage { |
645 | +func NewCoreUBootImage(location string, size int64, rootSize int, hw HardwareDescription, gadget GadgetDescription, label string) *CoreUBootImage { |
646 | + var partCount int |
647 | + switch gadget.PartitionLayout() { |
648 | + case "minimal": |
649 | + partCount = 2 |
650 | + } |
651 | + |
652 | return &CoreUBootImage{ |
653 | BaseImage{ |
654 | hardware: hw, |
655 | - oem: oem, |
656 | + gadget: gadget, |
657 | location: location, |
658 | size: size, |
659 | rootSize: rootSize, |
660 | +<<<<<<< TREE |
661 | partCount: 4, |
662 | label: label, |
663 | +======= |
664 | + partCount: partCount, |
665 | + label: label, |
666 | +>>>>>>> MERGE-SOURCE |
667 | }, |
668 | } |
669 | } |
670 | @@ -95,9 +106,10 @@ |
671 | return err |
672 | } |
673 | |
674 | - parted.addPart(bootLabel, bootDir, fsFat32, 128) |
675 | - parted.addPart(systemALabel, systemADir, fsExt4, 1024) |
676 | - parted.addPart(systemBLabel, systemBDir, fsExt4, 1024) |
677 | + switch img.gadget.PartitionLayout() { |
678 | + case "minimal": |
679 | + parted.addPart(bootLabel, bootDir, fsFat32, 128) |
680 | + } |
681 | parted.addPart(writableLabel, writableDir, fsExt4, -1) |
682 | |
683 | parted.setBoot(1) |
684 | @@ -117,7 +129,7 @@ |
685 | } |
686 | |
687 | // populate both A/B |
688 | - for _, part := range img.oem.SystemParts() { |
689 | + for _, part := range img.gadget.SystemParts() { |
690 | bootDtbPath := filepath.Join(bootPath, part, "dtbs") |
691 | if err := img.provisionDtbs(bootDtbPath); err != nil { |
692 | return err |
693 | @@ -131,7 +143,7 @@ |
694 | defer snappySystemFile.Close() |
695 | |
696 | var fdtfile string |
697 | - if platform := img.oem.Platform(); platform != "" { |
698 | + if platform := img.gadget.Platform(); platform != "" { |
699 | fdtfile = fmt.Sprintf("fdtfile=%s.dtb", platform) |
700 | } |
701 | |
702 | @@ -154,28 +166,32 @@ |
703 | return err |
704 | } |
705 | |
706 | - dtbFis, err := ioutil.ReadDir(dtbsPath) |
707 | - if err != nil { |
708 | - return err |
709 | + var dtbFis []os.FileInfo |
710 | + if img.hardware.Dtbs != "" { |
711 | + var err error |
712 | + dtbFis, err = ioutil.ReadDir(dtbsPath) |
713 | + if err != nil { |
714 | + return err |
715 | + } |
716 | } |
717 | |
718 | if err := os.MkdirAll(bootDtbPath, 0755); err != nil { |
719 | return err |
720 | } |
721 | |
722 | - dtb := filepath.Join(dtbsPath, fmt.Sprintf("%s.dtb", img.oem.Platform())) |
723 | + dtb := filepath.Join(dtbsPath, fmt.Sprintf("%s.dtb", img.gadget.Platform())) |
724 | |
725 | // if there is a specific dtb for the platform, copy it. |
726 | - // First look in oem and then in device. |
727 | - if oemDtb := img.oem.OEM.Hardware.Dtb; oemDtb != "" && img.oem.Platform() != "" { |
728 | - oemRoot, err := img.oem.InstallPath() |
729 | + // First look in gadget and then in device. |
730 | + if gadgetDtb := img.gadget.Gadget.Hardware.Dtb; gadgetDtb != "" && img.gadget.Platform() != "" { |
731 | + gadgetRoot, err := img.gadget.InstallPath() |
732 | if err != nil { |
733 | return err |
734 | } |
735 | |
736 | - oemDtb := filepath.Join(oemRoot, oemDtb) |
737 | + gadgetDtb := filepath.Join(gadgetRoot, gadgetDtb) |
738 | dst := filepath.Join(bootDtbPath, filepath.Base(dtb)) |
739 | - if err := sysutils.CopyFile(oemDtb, dst); err != nil { |
740 | + if err := sysutils.CopyFile(gadgetDtb, dst); err != nil { |
741 | return err |
742 | } |
743 | } else if _, err := os.Stat(dtb); err == nil { |
744 | |
745 | === modified file 'diskimage/partition.go' |
746 | --- diskimage/partition.go 2015-01-15 21:05:01 +0000 |
747 | +++ diskimage/partition.go 2016-09-04 15:15:47 +0000 |
748 | @@ -5,6 +5,7 @@ |
749 | // |
750 | // Written by Sergio Schvezov <sergio.schvezov@canonical.com> |
751 | // |
752 | + |
753 | package diskimage |
754 | |
755 | import ( |
756 | |
757 | === added file 'snapcraft.yaml' |
758 | --- snapcraft.yaml 1970-01-01 00:00:00 +0000 |
759 | +++ snapcraft.yaml 2016-09-04 15:15:47 +0000 |
760 | @@ -0,0 +1,35 @@ |
761 | +name: ubuntu-device-flash |
762 | +summary: Flash supported devices with Ubuntu |
763 | +description: | |
764 | + Use this tool to flash a suported device with Ubuntu. This works |
765 | + for different kinds of Ubuntu like Core or Touch. |
766 | +version: 11 |
767 | +confinement: devmode |
768 | + |
769 | +apps: |
770 | + ubuntu-device-flash: |
771 | + command: bin/ubuntu-device-flash |
772 | + |
773 | +parts: |
774 | + goget-ubuntu-touch: |
775 | + plugin: go |
776 | + source: lp:~mvo/goget-ubuntu-touch/minimal-first-boot |
777 | + source-type: bzr |
778 | + go-importpath: launchpad.net/goget-ubuntu-touch |
779 | + organize: |
780 | + sbin/kpartx: bin/kpartx |
781 | + sbin/dmsetup: bin/dmsetup |
782 | + snap: |
783 | + - bin/ubuntu-device-flash |
784 | + - bin/kpartx |
785 | + - bin/dmsetup |
786 | + stage-packages: |
787 | + - kpartx |
788 | + - dmsetup |
789 | + snapd: |
790 | + plugin: go |
791 | + source: https://github.com/snapcore/snapd |
792 | + source-type: git |
793 | + go-importpath: github.com/snapcore/snapd |
794 | + snap: |
795 | + - bin/snap |
796 | |
797 | === modified file 'ubuntu-device-flash/common.go' |
798 | --- ubuntu-device-flash/common.go 2015-03-30 03:28:28 +0000 |
799 | +++ ubuntu-device-flash/common.go 2016-09-04 15:15:47 +0000 |
800 | @@ -61,11 +61,11 @@ |
801 | |
802 | // expandFile checks for file existence, correct permissions and returns the absolute path. |
803 | func expandFile(path string) (abspath string, err error) { |
804 | - if p, err := filepath.Abs(path); err != nil { |
805 | + p, err := filepath.Abs(path) |
806 | + if err != nil { |
807 | return "", err |
808 | - } else { |
809 | - abspath = p |
810 | } |
811 | + abspath = p |
812 | |
813 | fi, err := os.Lstat(abspath) |
814 | if err != nil { |
815 | |
816 | === modified file 'ubuntu-device-flash/core.go' |
817 | --- ubuntu-device-flash/core.go 2016-04-04 15:54:40 +0000 |
818 | +++ ubuntu-device-flash/core.go 2016-09-04 15:15:47 +0000 |
819 | @@ -77,21 +77,20 @@ |
820 | |
821 | if !coreCmd.Deprecated.Cloud { |
822 | coreCmd.customizationFunc = append(coreCmd.customizationFunc, coreCmd.setupCloudInit) |
823 | - coreCmd.customizationFunc = append(coreCmd.customizationFunc, coreCmd.setupOemConfigs) |
824 | + coreCmd.customizationFunc = append(coreCmd.customizationFunc, coreCmd.setupGadgetConfigs) |
825 | } |
826 | |
827 | return coreCmd.create() |
828 | } |
829 | |
830 | // this is a hackish way to get the config in place |
831 | -func (coreCmd *CoreCmd) setupOemConfigs() error { |
832 | - modprobeDContent := coreCmd.oem.Config.UbuntuCore.Modprobe |
833 | +func (coreCmd *CoreCmd) setupGadgetConfigs() error { |
834 | + modprobeDContent := coreCmd.gadget.Config.UbuntuCore.Modprobe |
835 | if modprobeDContent == nil { |
836 | - printOut("no modprobe") |
837 | return nil |
838 | } |
839 | |
840 | - fmt.Println("Setting up oem hooks...") |
841 | + fmt.Println("Setting up gadget hooks...") |
842 | |
843 | writablePath := coreCmd.img.Writable() |
844 | |
845 | @@ -101,12 +100,20 @@ |
846 | } |
847 | |
848 | // first we need to copy all the files in modprobe.d |
849 | +<<<<<<< TREE |
850 | /* |
851 | systemModprobeDir := filepath.Join(coreCmd.img.System(), "etc", "modprobe.d") |
852 | if err := helpers.RSyncWithDelete(systemModprobeDir, modprobeDir); err != nil { |
853 | return err |
854 | } |
855 | */ |
856 | +======= |
857 | + systemModprobeDir := filepath.Join(coreCmd.img.System(), "etc", "modprobe.d") |
858 | + // FIXME: can we do "cp -a" here? |
859 | + if err := RSyncWithDelete(systemModprobeDir, modprobeDir); err != nil { |
860 | + return err |
861 | + } |
862 | +>>>>>>> MERGE-SOURCE |
863 | |
864 | modprobeD := filepath.Join(modprobeDir, "ubuntu-core.conf") |
865 | modprobeDFile, err := os.Create(modprobeD) |
866 | |
867 | === added file 'ubuntu-device-flash/helpers.go' |
868 | --- ubuntu-device-flash/helpers.go 1970-01-01 00:00:00 +0000 |
869 | +++ ubuntu-device-flash/helpers.go 2016-09-04 15:15:47 +0000 |
870 | @@ -0,0 +1,89 @@ |
871 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
872 | + |
873 | +/* |
874 | + * Copyright (C) 2014-2015 Canonical Ltd |
875 | + * |
876 | + * This program is free software: you can redistribute it and/or modify |
877 | + * it under the terms of the GNU General Public License version 3 as |
878 | + * published by the Free Software Foundation. |
879 | + * |
880 | + * This program is distributed in the hope that it will be useful, |
881 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
882 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
883 | + * GNU General Public License for more details. |
884 | + * |
885 | + * You should have received a copy of the GNU General Public License |
886 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
887 | + * |
888 | + */ |
889 | + |
890 | +package main |
891 | + |
892 | +import ( |
893 | + "fmt" |
894 | + "os" |
895 | + "os/exec" |
896 | + "path/filepath" |
897 | + "syscall" |
898 | + |
899 | + "github.com/snapcore/snapd/osutil" |
900 | +) |
901 | + |
902 | +// RSyncWithDelete syncs srcDir to destDir |
903 | +func RSyncWithDelete(srcDirName, destDirName string) error { |
904 | + // first remove everything thats not in srcdir |
905 | + err := filepath.Walk(destDirName, func(path string, info os.FileInfo, err error) error { |
906 | + if err != nil { |
907 | + return err |
908 | + } |
909 | + |
910 | + // relative to the root "destDirName" |
911 | + relPath := path[len(destDirName):] |
912 | + if !osutil.FileExists(filepath.Join(srcDirName, relPath)) { |
913 | + if err := os.RemoveAll(path); err != nil { |
914 | + return err |
915 | + } |
916 | + if info.IsDir() { |
917 | + return filepath.SkipDir |
918 | + } |
919 | + } |
920 | + return nil |
921 | + }) |
922 | + if err != nil { |
923 | + return err |
924 | + } |
925 | + |
926 | + // then copy or update the data from srcdir to destdir |
927 | + err = filepath.Walk(srcDirName, func(src string, info os.FileInfo, err error) error { |
928 | + if err != nil { |
929 | + return err |
930 | + } |
931 | + |
932 | + // relative to the root "srcDirName" |
933 | + relPath := src[len(srcDirName):] |
934 | + dst := filepath.Join(destDirName, relPath) |
935 | + if info.IsDir() { |
936 | + if err := os.MkdirAll(dst, info.Mode()); err != nil { |
937 | + return err |
938 | + } |
939 | + |
940 | + // this can panic. The alternative would be to use the "st, ok" pattern, and then if !ok... panic? |
941 | + st := info.Sys().(*syscall.Stat_t) |
942 | + ts := []syscall.Timespec{st.Atim, st.Mtim} |
943 | + |
944 | + return syscall.UtimesNano(dst, ts) |
945 | + } |
946 | + if !osutil.FilesAreEqual(src, dst) { |
947 | + // XXX: we should (eventually) use CopyFile here, |
948 | + // but we need to teach it about preserving |
949 | + // of atime/mtime and permissions |
950 | + output, err := exec.Command("cp", "-va", src, dst).CombinedOutput() |
951 | + if err != nil { |
952 | + return fmt.Errorf("Failed to copy %s to %s (%s)", src, dst, output) |
953 | + } |
954 | + } |
955 | + return nil |
956 | + }) |
957 | + |
958 | + return err |
959 | +} |
960 | |
961 | === added file 'ubuntu-device-flash/helpers_test.go' |
962 | --- ubuntu-device-flash/helpers_test.go 1970-01-01 00:00:00 +0000 |
963 | +++ ubuntu-device-flash/helpers_test.go 2016-09-04 15:15:47 +0000 |
964 | @@ -0,0 +1,135 @@ |
965 | +// -*- Mode: Go; indent-tabs-mode: t -*- |
966 | + |
967 | +/* |
968 | + * Copyright (C) 2014-2015 Canonical Ltd |
969 | + * |
970 | + * This program is free software: you can redistribute it and/or modify |
971 | + * it under the terms of the GNU General Public License version 3 as |
972 | + * published by the Free Software Foundation. |
973 | + * |
974 | + * This program is distributed in the hope that it will be useful, |
975 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
976 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
977 | + * GNU General Public License for more details. |
978 | + * |
979 | + * You should have received a copy of the GNU General Public License |
980 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
981 | + * |
982 | + */ |
983 | + |
984 | +package main |
985 | + |
986 | +import ( |
987 | + "fmt" |
988 | + "io/ioutil" |
989 | + "os" |
990 | + "os/exec" |
991 | + "path/filepath" |
992 | + |
993 | + . "launchpad.net/gocheck" |
994 | +) |
995 | + |
996 | +type HTestSuite struct{} |
997 | + |
998 | +var _ = Suite(&HTestSuite{}) |
999 | + |
1000 | +func makeTestFiles(c *C, srcDir, destDir string) { |
1001 | + // a new file |
1002 | + err := ioutil.WriteFile(filepath.Join(srcDir, "new"), []byte(nil), 0644) |
1003 | + c.Assert(err, IsNil) |
1004 | + |
1005 | + // a existing file that needs update |
1006 | + err = ioutil.WriteFile(filepath.Join(destDir, "existing-update"), []byte("old-content"), 0644) |
1007 | + c.Assert(err, IsNil) |
1008 | + err = ioutil.WriteFile(filepath.Join(srcDir, "existing-update"), []byte("some-new-content"), 0644) |
1009 | + c.Assert(err, IsNil) |
1010 | + |
1011 | + // existing file that needs no update |
1012 | + err = ioutil.WriteFile(filepath.Join(srcDir, "existing-unchanged"), []byte(nil), 0644) |
1013 | + c.Assert(err, IsNil) |
1014 | + err = exec.Command("cp", "-a", filepath.Join(srcDir, "existing-unchanged"), filepath.Join(destDir, "existing-unchanged")).Run() |
1015 | + c.Assert(err, IsNil) |
1016 | + |
1017 | + // a file that needs removal |
1018 | + err = ioutil.WriteFile(filepath.Join(destDir, "to-be-deleted"), []byte(nil), 0644) |
1019 | + c.Assert(err, IsNil) |
1020 | +} |
1021 | + |
1022 | +func compareDirs(c *C, srcDir, destDir string) { |
1023 | + d1, err := exec.Command("ls", "-al", srcDir).CombinedOutput() |
1024 | + c.Assert(err, IsNil) |
1025 | + d2, err := exec.Command("ls", "-al", destDir).CombinedOutput() |
1026 | + c.Assert(err, IsNil) |
1027 | + c.Assert(string(d1), Equals, string(d2)) |
1028 | + // ensure content got updated |
1029 | + c1, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", srcDir)).CombinedOutput() |
1030 | + c.Assert(err, IsNil) |
1031 | + c2, err := exec.Command("sh", "-c", fmt.Sprintf("find %s -type f |xargs cat", destDir)).CombinedOutput() |
1032 | + c.Assert(err, IsNil) |
1033 | + c.Assert(string(c1), Equals, string(c2)) |
1034 | +} |
1035 | + |
1036 | +func (ts *HTestSuite) TestSyncDirs(c *C) { |
1037 | + |
1038 | + for _, l := range [][2]string{ |
1039 | + [2]string{"src-short", "dst-loooooooooooong"}, |
1040 | + [2]string{"src-loooooooooooong", "dst-short"}, |
1041 | + [2]string{"src-eq", "dst-eq"}, |
1042 | + } { |
1043 | + |
1044 | + // ensure we have src, dest dirs with different length |
1045 | + srcDir := filepath.Join(c.MkDir(), l[0]) |
1046 | + err := os.MkdirAll(srcDir, 0755) |
1047 | + c.Assert(err, IsNil) |
1048 | + destDir := filepath.Join(c.MkDir(), l[1]) |
1049 | + err = os.MkdirAll(destDir, 0755) |
1050 | + c.Assert(err, IsNil) |
1051 | + |
1052 | + // add a src subdir |
1053 | + subdir := filepath.Join(srcDir, "subdir") |
1054 | + err = os.Mkdir(subdir, 0755) |
1055 | + c.Assert(err, IsNil) |
1056 | + makeTestFiles(c, subdir, destDir) |
1057 | + |
1058 | + // add a dst subdir that needs to get deleted |
1059 | + subdir2 := filepath.Join(destDir, "to-be-deleted-subdir") |
1060 | + err = os.Mkdir(subdir2, 0755) |
1061 | + subdir3 := filepath.Join(subdir2, "to-be-deleted-sub-subdir") |
1062 | + err = os.Mkdir(subdir3, 0755) |
1063 | + |
1064 | + // and a toplevel |
1065 | + makeTestFiles(c, srcDir, destDir) |
1066 | + |
1067 | + // do it |
1068 | + err = RSyncWithDelete(srcDir, destDir) |
1069 | + c.Assert(err, IsNil) |
1070 | + |
1071 | + // ensure meta-data is identical |
1072 | + compareDirs(c, srcDir, destDir) |
1073 | + compareDirs(c, filepath.Join(srcDir, "subdir"), filepath.Join(destDir, "subdir")) |
1074 | + } |
1075 | +} |
1076 | + |
1077 | +func (ts *HTestSuite) TestSyncDirFails(c *C) { |
1078 | + srcDir := c.MkDir() |
1079 | + err := os.MkdirAll(srcDir, 0755) |
1080 | + c.Assert(err, IsNil) |
1081 | + |
1082 | + destDir := c.MkDir() |
1083 | + err = os.MkdirAll(destDir, 0755) |
1084 | + c.Assert(err, IsNil) |
1085 | + |
1086 | + err = ioutil.WriteFile(filepath.Join(destDir, "meep"), []byte(nil), 0644) |
1087 | + c.Assert(err, IsNil) |
1088 | + |
1089 | + // ensure remove fails |
1090 | + err = os.Chmod(destDir, 0100) |
1091 | + c.Assert(err, IsNil) |
1092 | + // make tempdir cleanup work again |
1093 | + defer os.Chmod(destDir, 0755) |
1094 | + |
1095 | + // do it |
1096 | + err = RSyncWithDelete(srcDir, destDir) |
1097 | + c.Check(err, NotNil) |
1098 | + c.Check(err, ErrorMatches, ".*permission denied.*") |
1099 | +} |
1100 | |
1101 | === modified file 'ubuntu-device-flash/main.go' |
1102 | --- ubuntu-device-flash/main.go 2015-11-13 15:19:25 +0000 |
1103 | +++ ubuntu-device-flash/main.go 2016-09-04 15:15:47 +0000 |
1104 | @@ -43,7 +43,7 @@ |
1105 | var cacheDir = ubuntuimage.GetCacheDir() |
1106 | |
1107 | func main() { |
1108 | - execute(os.Args) |
1109 | + execute(os.Args[1:]) |
1110 | } |
1111 | |
1112 | func execute(args []string) { |
1113 | |
1114 | === modified file 'ubuntu-device-flash/snappy.go' |
1115 | --- ubuntu-device-flash/snappy.go 2016-04-05 09:39:49 +0000 |
1116 | +++ ubuntu-device-flash/snappy.go 2016-09-04 15:15:47 +0000 |
1117 | @@ -9,10 +9,32 @@ |
1118 | package main |
1119 | |
1120 | import ( |
1121 | +<<<<<<< TREE |
1122 | +======= |
1123 | + "encoding/json" |
1124 | + "errors" |
1125 | +>>>>>>> MERGE-SOURCE |
1126 | "fmt" |
1127 | |
1128 | +<<<<<<< TREE |
1129 | +======= |
1130 | + "github.com/snapcore/snapd/arch" |
1131 | + "github.com/snapcore/snapd/asserts" |
1132 | + "github.com/snapcore/snapd/osutil" |
1133 | + "github.com/snapcore/snapd/progress" |
1134 | + "github.com/snapcore/snapd/provisioning" |
1135 | + "github.com/snapcore/snapd/release" |
1136 | + "github.com/snapcore/snapd/snap" |
1137 | + "github.com/snapcore/snapd/store" |
1138 | + |
1139 | + "gopkg.in/yaml.v2" |
1140 | +>>>>>>> MERGE-SOURCE |
1141 | "launchpad.net/goget-ubuntu-touch/diskimage" |
1142 | +<<<<<<< TREE |
1143 | "launchpad.net/goget-ubuntu-touch/ubuntuimage" |
1144 | +======= |
1145 | + "launchpad.net/goget-ubuntu-touch/sysutils" |
1146 | +>>>>>>> MERGE-SOURCE |
1147 | ) |
1148 | |
1149 | type imageFlavor string |
1150 | @@ -58,25 +80,34 @@ |
1151 | } |
1152 | } |
1153 | |
1154 | +// Snapper holds common options applicable to snappy based images. |
1155 | type Snapper struct { |
1156 | Channel string `long:"channel" description:"Specify the channel to use" default:"stable"` |
1157 | Output string `long:"output" short:"o" description:"Name of the image file to create" required:"true"` |
1158 | - Oem string `long:"oem" description:"The snappy oem package to base the image out of" default:"generic-amd64"` |
1159 | - StoreID string `long:"store" description:"Set an alternate store id."` |
1160 | |
1161 | Development struct { |
1162 | Install []string `long:"install" description:"Install additional packages (can be called multiple times)"` |
1163 | - DevicePart string `long:"device-part" description:"Specify a local device part to override the one from the server"` |
1164 | DeveloperMode bool `long:"developer-mode" description:"Finds the latest public key in your ~/.ssh and sets it up using cloud-init"` |
1165 | } `group:"Development"` |
1166 | |
1167 | Positional struct { |
1168 | - Release string `positional-arg-name:"release" description:"The release to base the image out of (15.04 or rolling)" required:"true"` |
1169 | + Release string `positional-arg-name:"release" description:"The release to base the image out of (16 or rolling)" required:"true"` |
1170 | + ModelAssertion string `positional-arg-name:"model-assertion" description:"The model assertion to use" required:"true"` |
1171 | } `positional-args:"yes" required:"yes"` |
1172 | |
1173 | +<<<<<<< TREE |
1174 | img diskimage.CoreImage |
1175 | hardware diskimage.HardwareDescription |
1176 | oem diskimage.OemDescription |
1177 | +======= |
1178 | + img diskimage.CoreImage |
1179 | + hardware diskimage.HardwareDescription |
1180 | + gadget diskimage.GadgetDescription |
1181 | + stagingRootPath string |
1182 | +>>>>>>> MERGE-SOURCE |
1183 | + |
1184 | + prepareImagePath string |
1185 | + modelAssertion *asserts.Model |
1186 | |
1187 | size int64 |
1188 | |
1189 | @@ -85,23 +116,500 @@ |
1190 | customizationFunc []func() error |
1191 | } |
1192 | |
1193 | +<<<<<<< TREE |
1194 | func (s *Snapper) systemImage() (*ubuntuimage.Image, error) { |
1195 | return nil, nil |
1196 | +======= |
1197 | +func (s Snapper) sanityCheck() error { |
1198 | + // we don't want to overwrite the output, people might get angry :-) |
1199 | + if osutil.FileExists(s.Output) { |
1200 | + return fmt.Errorf("Giving up, the desired target output file %#v already exists", s.Output) |
1201 | + } |
1202 | + |
1203 | + if s.size < s.flavor.minSize() { |
1204 | + return fmt.Errorf("minimum size for %s is %d", s.flavor, s.flavor.minSize()) |
1205 | + } |
1206 | + |
1207 | + if syscall.Getuid() != 0 { |
1208 | + return errors.New("command requires sudo/pkexec (root)") |
1209 | + } |
1210 | + if s.Positional.Release == "15.04" { |
1211 | + 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") |
1212 | + } |
1213 | + |
1214 | + // ensure we error when running on e.g. 14.04 with a sensible |
1215 | + // error message instead of super strange error later |
1216 | + if !osutil.FileExists("/bin/systemctl") { |
1217 | + return errors.New("need '/bin/systemctl to work") |
1218 | + } |
1219 | + |
1220 | + return nil |
1221 | +} |
1222 | + |
1223 | +func snapTargetPathFromSnapFile(src string) (string, error) { |
1224 | + snapFile, err := snap.Open(src) |
1225 | + if err != nil { |
1226 | + return "", err |
1227 | + } |
1228 | + var si snap.SideInfo |
1229 | + // XXX: copied from snapmgr.go |
1230 | + metafn := src + ".sideinfo" |
1231 | + if j, err := ioutil.ReadFile(metafn); err == nil { |
1232 | + if err := json.Unmarshal(j, &si); err != nil { |
1233 | + return "", fmt.Errorf("cannot read metadata: %s %s\n", metafn, err) |
1234 | + } |
1235 | + } |
1236 | + info, err := snap.ReadInfoFromSnapFile(snapFile, &si) |
1237 | + if err != nil { |
1238 | + return "", err |
1239 | + } |
1240 | + |
1241 | + // local snap |
1242 | + if info.Revision.Unset() { |
1243 | + info.Revision = snap.R(-1) |
1244 | + } |
1245 | + |
1246 | + return info.MountFile(), nil |
1247 | +} |
1248 | + |
1249 | +func copyFile(src, dst string) error { |
1250 | + cmd := exec.Command("cp", "-va", src, dst) |
1251 | + if o, err := cmd.CombinedOutput(); err != nil { |
1252 | + return fmt.Errorf("copy failed: %s %s", err, o) |
1253 | + } |
1254 | + return nil |
1255 | +} |
1256 | + |
1257 | +func (s *Snapper) prepareImage() error { |
1258 | + var err error |
1259 | + s.prepareImagePath, err = ioutil.TempDir("", "prepare-image") |
1260 | + if err != nil { |
1261 | + return err |
1262 | + } |
1263 | + |
1264 | + raw, err := ioutil.ReadFile(s.Positional.ModelAssertion) |
1265 | + if err != nil { |
1266 | + return err |
1267 | + } |
1268 | + as, err := asserts.Decode(raw) |
1269 | + if err != nil { |
1270 | + return err |
1271 | + } |
1272 | + s.modelAssertion = as.(*asserts.Model) |
1273 | + arch.SetArchitecture(arch.ArchitectureType(s.modelAssertion.Architecture())) |
1274 | + |
1275 | + os.Setenv("SNAP_REEXEC", "0") |
1276 | + cmdArgs := []string{ |
1277 | + "snap", |
1278 | + "prepare-image", |
1279 | + "--channel", s.Channel, |
1280 | + s.Positional.ModelAssertion, |
1281 | + s.prepareImagePath, |
1282 | + } |
1283 | + for _, extra := range s.Development.Install { |
1284 | + cmdArgs = append(cmdArgs, "--extra-snaps="+extra) |
1285 | + } |
1286 | + |
1287 | + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) |
1288 | + cmd.Stdin = os.Stdin |
1289 | + cmd.Stdout = os.Stdout |
1290 | + cmd.Stderr = os.Stderr |
1291 | + if err := cmd.Run(); err != nil { |
1292 | + return fmt.Errorf("cannot run snap bootstrap: %s", err) |
1293 | + } |
1294 | + return nil |
1295 | +>>>>>>> MERGE-SOURCE |
1296 | } |
1297 | |
1298 | func (s *Snapper) install(systemPath string) error { |
1299 | - return nil |
1300 | +<<<<<<< TREE |
1301 | + return nil |
1302 | +======= |
1303 | + tmpSystemPath := filepath.Join(s.prepareImagePath, "image") |
1304 | + |
1305 | + mv := exec.Command("sh", "-c", fmt.Sprintf("cp -rv %s/* %s", tmpSystemPath, systemPath)) |
1306 | + mv.Stdin = os.Stdin |
1307 | + mv.Stdout = os.Stdout |
1308 | + mv.Stderr = os.Stderr |
1309 | + if err := mv.Run(); err != nil { |
1310 | + return fmt.Errorf("cannot run snap bootstrap: %s", err) |
1311 | + } |
1312 | + |
1313 | + return nil |
1314 | +} |
1315 | + |
1316 | +func (s *Snapper) extractGadget(gadgetPackage string) error { |
1317 | + fakeGadgetDir := filepath.Join(s.prepareImagePath, "gadget") |
1318 | + |
1319 | + // HORRIBLE - there is always one more circle of hell, never assume |
1320 | + // you have reached the end of it yet |
1321 | + // |
1322 | + // the new gadget snaps do no have the old gadget specific stuff |
1323 | + // anymore - however we still need it to create images until we |
1324 | + // have the new stuff available |
1325 | + var gadgetMetaYaml string |
1326 | + switch gadgetPackage { |
1327 | + case "pc": |
1328 | + gadgetMetaYaml = compatCanonicalPCamd64 |
1329 | + case "386": |
1330 | + gadgetMetaYaml = compatCanonicalPCi386 |
1331 | + case "pi2": |
1332 | + gadgetMetaYaml = compatCanonicalPi2 |
1333 | + case "dragon": |
1334 | + gadgetMetaYaml = compatCanonicalDragon |
1335 | + |
1336 | + } |
1337 | + if gadgetMetaYaml != "" { |
1338 | + if err := ioutil.WriteFile(filepath.Join(fakeGadgetDir, "meta/snap.yaml"), []byte(gadgetMetaYaml), 0644); err != nil { |
1339 | + return err |
1340 | + } |
1341 | + } |
1342 | + |
1343 | + f, err := ioutil.ReadFile(filepath.Join(fakeGadgetDir, "meta/snap.yaml")) |
1344 | + if err != nil { |
1345 | + return errors.New("failed to read gadget yaml") |
1346 | + } |
1347 | + var gadget diskimage.GadgetDescription |
1348 | + if err := yaml.Unmarshal([]byte(f), &gadget); err != nil { |
1349 | + return errors.New("cannot decode gadget yaml") |
1350 | + } |
1351 | + |
1352 | + s.gadget = gadget |
1353 | + s.gadget.SetRoot(fakeGadgetDir) |
1354 | + return nil |
1355 | +} |
1356 | + |
1357 | +// Creates a YAML file inside the image that contains metadata relating |
1358 | +// to the installation. |
1359 | +func (s Snapper) writeInstallYaml(bootMountpoint string) error { |
1360 | + selfPath, err := exec.LookPath(os.Args[0]) |
1361 | + if err != nil { |
1362 | + return err |
1363 | + } |
1364 | + |
1365 | + bootDir := "" |
1366 | + |
1367 | + switch s.gadget.Gadget.Hardware.Bootloader { |
1368 | + // Running systems use a bindmount for /boot/grub, but |
1369 | + // since the system isn't booted, create the file in the |
1370 | + // real location. |
1371 | + case "grub": |
1372 | + bootDir = "/EFI/ubuntu/grub" |
1373 | + } |
1374 | + |
1375 | + installYamlFilePath := filepath.Join(bootMountpoint, bootDir, provisioning.InstallYamlFile) |
1376 | + |
1377 | + i := provisioning.InstallYaml{ |
1378 | + InstallMeta: provisioning.InstallMeta{ |
1379 | + Timestamp: time.Now(), |
1380 | + }, |
1381 | + InstallTool: provisioning.InstallTool{ |
1382 | + Name: filepath.Base(selfPath), |
1383 | + Path: selfPath, |
1384 | + // FIXME: we don't know our own version yet :) |
1385 | + // Version: "???", |
1386 | + }, |
1387 | + InstallOptions: provisioning.InstallOptions{ |
1388 | + Size: s.size, |
1389 | + SizeUnit: "GB", |
1390 | + Output: s.Output, |
1391 | + Channel: s.Channel, |
1392 | + DeveloperMode: s.Development.DeveloperMode, |
1393 | + }, |
1394 | + } |
1395 | + |
1396 | + data, err := yaml.Marshal(&i) |
1397 | + if err != nil { |
1398 | + return err |
1399 | + } |
1400 | + |
1401 | + // the file isn't supposed to be modified, hence r/o. |
1402 | + return ioutil.WriteFile(installYamlFilePath, data, 0444) |
1403 | +} |
1404 | + |
1405 | +func (s *Snapper) bindMount(d string) (string, error) { |
1406 | + src := filepath.Join(s.img.Writable(), "system-data", d) |
1407 | + dst := filepath.Join(s.img.System(), d) |
1408 | + |
1409 | + if err := os.MkdirAll(src, 0755); err != nil { |
1410 | + return "", err |
1411 | + } |
1412 | + cmd := exec.Command("mount", "--bind", src, dst) |
1413 | + if o, err := cmd.CombinedOutput(); err != nil { |
1414 | + return "", fmt.Errorf("bind mount failed for %s to %s with: %s %v ", src, dst, err, string(o)) |
1415 | + } |
1416 | + return dst, nil |
1417 | +} |
1418 | + |
1419 | +func (s *Snapper) downloadSnap(snapName string) (string, error) { |
1420 | + if snapName == "" { |
1421 | + return "", nil |
1422 | + } |
1423 | + // if its pointing to a local file, just return that |
1424 | + if _, err := os.Stat(snapName); err == nil { |
1425 | + return snapName, nil |
1426 | + } |
1427 | + release.Series = s.Positional.Release |
1428 | + |
1429 | + cfg := store.DefaultConfig() |
1430 | + cfg.StoreID = s.modelAssertion.Store() |
1431 | + m := store.New(cfg, nil) |
1432 | + snap, err := m.Snap(snapName, s.Channel, false, snap.R(0), nil) |
1433 | + if err != nil { |
1434 | + return "", fmt.Errorf("failed to find os snap: %s", err) |
1435 | + } |
1436 | + pb := progress.NewTextProgress() |
1437 | + tmpName, err := m.Download(snapName, &snap.DownloadInfo, pb, nil) |
1438 | + if err != nil { |
1439 | + return "", err |
1440 | + } |
1441 | + // rename to the snapid |
1442 | + baseName := fmt.Sprintf("%s_%s.snap", snap.SnapID, snap.Revision) |
1443 | + path := filepath.Join(filepath.Dir(tmpName), baseName) |
1444 | + if err := os.Rename(tmpName, path); err != nil { |
1445 | + return "", err |
1446 | + } |
1447 | + |
1448 | + // write out metadata for first boot |
1449 | + out, err := json.Marshal(snap) |
1450 | + if err != nil { |
1451 | + return "", err |
1452 | + } |
1453 | + if err := ioutil.WriteFile(path+".sideinfo", []byte(out), 0644); err != nil { |
1454 | + return "", err |
1455 | + } |
1456 | + |
1457 | + return path, nil |
1458 | +} |
1459 | + |
1460 | +func (s *Snapper) setup() error { |
1461 | + if s.gadget.PartitionLayout() != "minimal" { |
1462 | + return fmt.Errorf("only supporting 'minimal' partition layout") |
1463 | + } |
1464 | + |
1465 | + printOut("Mounting...") |
1466 | + if err := s.img.Mount(); err != nil { |
1467 | + return err |
1468 | + } |
1469 | + defer func() { |
1470 | + printOut("Unmounting...") |
1471 | + if err := s.img.Unmount(); err != nil { |
1472 | + fmt.Println("WARNING: unexpected issue:", err) |
1473 | + } |
1474 | + }() |
1475 | + |
1476 | + printOut("Provisioning...") |
1477 | + systemPath := s.img.System() |
1478 | + |
1479 | + // setup a fake system |
1480 | + if err := os.MkdirAll(systemPath, 0755); err != nil { |
1481 | + return err |
1482 | + } |
1483 | + |
1484 | + // this is a bit terrible, we need to download the OS |
1485 | + // mount it, "sync dirs" (see below) and then we |
1486 | + // will need to download it again to install it properly |
1487 | + osSnap, err := s.downloadSnap("ubuntu-core") |
1488 | + if err != nil { |
1489 | + return err |
1490 | + } |
1491 | + |
1492 | + // mount os snap |
1493 | + cmd := exec.Command("mount", osSnap, systemPath) |
1494 | + if o, err := cmd.CombinedOutput(); err != nil { |
1495 | + return fmt.Errorf("os snap mount failed with: %s %v ", err, string(o)) |
1496 | + } |
1497 | + defer exec.Command("umount", systemPath).Run() |
1498 | + |
1499 | + // bind mount all relevant dirs: |
1500 | + // - /snap so that we can temporarly mount the kernel |
1501 | + // - /var/lib/snapd to put the downloaded snaps in there |
1502 | + // - /tmp so that we can create /tmp/root_dev for grub |
1503 | + for _, d := range []string{"snap", "var/lib/snapd", "tmp"} { |
1504 | + dst, err := s.bindMount(d) |
1505 | + if err != nil { |
1506 | + return err |
1507 | + } |
1508 | + defer exec.Command("umount", dst).Run() |
1509 | + } |
1510 | + |
1511 | + // bind mount /boot/efi |
1512 | + dst := filepath.Join(systemPath, "/boot/efi") |
1513 | + cmd = exec.Command("mount", "--bind", s.img.Boot(), dst) |
1514 | + if o, err := cmd.CombinedOutput(); err != nil { |
1515 | + return fmt.Errorf("boot bind mount failed with: %s %v ", err, string(o)) |
1516 | + } |
1517 | + defer exec.Command("umount", dst).Run() |
1518 | + switch s.gadget.Gadget.Hardware.Bootloader { |
1519 | + case "grub": |
1520 | + // grub needs this |
1521 | + grubUbuntu := filepath.Join(s.img.Boot(), "EFI/ubuntu/grub") |
1522 | + os.MkdirAll(grubUbuntu, 0755) |
1523 | + |
1524 | + // and /boot/grub |
1525 | + src := grubUbuntu |
1526 | + dst = filepath.Join(systemPath, "/boot/grub") |
1527 | + cmd = exec.Command("mount", "--bind", src, dst) |
1528 | + if o, err := cmd.CombinedOutput(); err != nil { |
1529 | + return fmt.Errorf("boot/ubuntu bind mount failed with: %s %v ", err, string(o)) |
1530 | + } |
1531 | + defer exec.Command("umount", dst).Run() |
1532 | + case "u-boot": |
1533 | + src := s.img.Boot() |
1534 | + dst = filepath.Join(systemPath, "/boot/uboot") |
1535 | + cmd = exec.Command("mount", "--bind", src, dst) |
1536 | + if o, err := cmd.CombinedOutput(); err != nil { |
1537 | + return fmt.Errorf("boot/ubuntu bind mount failed with: %s %v ", err, string(o)) |
1538 | + } |
1539 | + defer exec.Command("umount", dst).Run() |
1540 | + } |
1541 | + |
1542 | + if err := s.img.SetupBoot(); err != nil { |
1543 | + return err |
1544 | + } |
1545 | + |
1546 | + if err := s.install(systemPath); err != nil { |
1547 | + return err |
1548 | + } |
1549 | + |
1550 | + for i := range s.customizationFunc { |
1551 | + if err := s.customizationFunc[i](); err != nil { |
1552 | + return err |
1553 | + } |
1554 | + } |
1555 | + |
1556 | + return s.writeInstallYaml(s.img.Boot()) |
1557 | +>>>>>>> MERGE-SOURCE |
1558 | } |
1559 | |
1560 | // deploy orchestrates the priviledged part of the setup |
1561 | +<<<<<<< TREE |
1562 | func (s *Snapper) deploy(systemImage *ubuntuimage.Image, filePathChan <-chan string) error { |
1563 | +======= |
1564 | +func (s *Snapper) deploy() error { |
1565 | + // hack to circumvent https://code.google.com/p/go/issues/detail?id=1435 |
1566 | + runtime.GOMAXPROCS(1) |
1567 | + runtime.LockOSThread() |
1568 | + if err := sysutils.EscalatePrivs(); err != nil { |
1569 | + return err |
1570 | + } |
1571 | + defer sysutils.DropPrivs() |
1572 | + |
1573 | + printOut("Formatting...") |
1574 | + if err := s.img.Format(); err != nil { |
1575 | + return err |
1576 | + } |
1577 | + |
1578 | + if err := s.setup(); err != nil { |
1579 | + return err |
1580 | + } |
1581 | + |
1582 | +>>>>>>> MERGE-SOURCE |
1583 | return nil |
1584 | } |
1585 | |
1586 | +<<<<<<< TREE |
1587 | func (s *Snapper) create() error { |
1588 | return fmt.Errorf(`Building core images is currently not supported. |
1589 | |
1590 | Images for ubuntu-core 15.04 can be build with the ppa:snappy-dev/tools. |
1591 | Building images for ubuntu-core 16.04 will be supported by this tool soon. |
1592 | `) |
1593 | +======= |
1594 | +func (s Snapper) printSummary() { |
1595 | + fmt.Println("New image complete") |
1596 | + fmt.Println("Summary:") |
1597 | + fmt.Println(" Output:", s.Output) |
1598 | + fmt.Println(" Architecture:", s.gadget.Architecture()) |
1599 | + fmt.Println(" Channel:", s.Channel) |
1600 | + fmt.Println(" Version:", globalArgs.Revision) |
1601 | +} |
1602 | + |
1603 | +func (s *Snapper) create() (err error) { |
1604 | + if err := s.sanityCheck(); err != nil { |
1605 | + return err |
1606 | + } |
1607 | + |
1608 | + fmt.Println("Calling prepare image") |
1609 | + if err := s.prepareImage(); err != nil { |
1610 | + return err |
1611 | + } |
1612 | + |
1613 | + fmt.Println("Determining gadget configuration") |
1614 | + if err := s.extractGadget(s.modelAssertion.Gadget()); err != nil { |
1615 | + return err |
1616 | + } |
1617 | + defer os.RemoveAll(s.stagingRootPath) |
1618 | + |
1619 | + // hack to circumvent https://code.google.com/p/go/issues/detail?id=1435 |
1620 | + runtime.GOMAXPROCS(1) |
1621 | + runtime.LockOSThread() |
1622 | + if err := sysutils.DropPrivs(); err != nil { |
1623 | + return err |
1624 | + } |
1625 | + |
1626 | + switch s.gadget.Gadget.Hardware.Bootloader { |
1627 | + case "grub": |
1628 | + legacy := false |
1629 | + s.img = diskimage.NewCoreGrubImage(s.Output, s.size, s.flavor.rootSize(), s.hardware, s.gadget, legacy, "gpt") |
1630 | + case "u-boot": |
1631 | + label := "msdos" |
1632 | + if s.gadget.Architecture() == archArm64 { |
1633 | + label = "gpt" |
1634 | + } |
1635 | + s.img = diskimage.NewCoreUBootImage(s.Output, s.size, s.flavor.rootSize(), s.hardware, s.gadget, label) |
1636 | + default: |
1637 | + return errors.New("no hardware description in Gadget snap") |
1638 | + } |
1639 | + |
1640 | + printOut("Partitioning...") |
1641 | + if err := s.img.Partition(); err != nil { |
1642 | + return err |
1643 | + } |
1644 | + defer func() { |
1645 | + if err != nil { |
1646 | + os.Remove(s.Output) |
1647 | + } |
1648 | + }() |
1649 | + |
1650 | + // Handle SIGINT and SIGTERM. |
1651 | + go func() { |
1652 | + ch := make(chan os.Signal) |
1653 | + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) |
1654 | + |
1655 | + for sig := range ch { |
1656 | + printOut("Received", sig, "... ignoring") |
1657 | + } |
1658 | + }() |
1659 | + |
1660 | + // Execute the following code with escalated privs and drop them when done |
1661 | + if err := s.deploy(); err != nil { |
1662 | + return err |
1663 | + } |
1664 | + |
1665 | + if err := s.img.FlashExtra(); err != nil { |
1666 | + return err |
1667 | + } |
1668 | + |
1669 | + s.printSummary() |
1670 | + |
1671 | + return nil |
1672 | +} |
1673 | + |
1674 | +func isLegacy(release, channel string, revision int) bool { |
1675 | + if release != "15.04" { |
1676 | + return false |
1677 | + } |
1678 | + |
1679 | + switch channel { |
1680 | + case "edge": |
1681 | + return revision <= 149 |
1682 | + case "alpha": |
1683 | + return revision <= 9 |
1684 | + case "stable": |
1685 | + return revision <= 4 |
1686 | + } |
1687 | + |
1688 | + return false |
1689 | +>>>>>>> MERGE-SOURCE |
1690 | } |
1691 | |
1692 | === added file 'ubuntu-device-flash/snappy_compat_yaml.go' |
1693 | --- ubuntu-device-flash/snappy_compat_yaml.go 1970-01-01 00:00:00 +0000 |
1694 | +++ ubuntu-device-flash/snappy_compat_yaml.go 2016-09-04 15:15:47 +0000 |
1695 | @@ -0,0 +1,124 @@ |
1696 | +// |
1697 | +// ubuntu-device-flash - Tool to download and flash devices with an Ubuntu Image |
1698 | +// based system |
1699 | +// |
1700 | +// Copyright (c) 2016 Canonical Ltd. |
1701 | +// |
1702 | +package main |
1703 | + |
1704 | +var compatCanonicalPCamd64 = ` |
1705 | +name: canonical-pc |
1706 | +gadget: |
1707 | + branding: |
1708 | + name: amd64 |
1709 | + subname: generic |
1710 | + |
1711 | + hardware: |
1712 | + bootloader: grub |
1713 | + architecture: amd64 |
1714 | + partition-layout: minimal |
1715 | + boot-assets: |
1716 | + files: |
1717 | + - path: grub.cfg |
1718 | +` |
1719 | + |
1720 | +var compatCanonicalPCi386 = ` |
1721 | +name: canonical-i386 |
1722 | +gadget: |
1723 | + branding: |
1724 | + name: i386 |
1725 | + subname: generic |
1726 | + |
1727 | + hardware: |
1728 | + bootloader: grub |
1729 | + architecture: amd64 |
1730 | + partition-layout: minimal |
1731 | + boot-assets: |
1732 | + files: |
1733 | + - path: grub.cfg |
1734 | +` |
1735 | + |
1736 | +var compatCanonicalPi2 = ` |
1737 | +name: canonical-pi2 |
1738 | +gadget: |
1739 | + hardware: |
1740 | + platform: bcm2836-rpi-2-b |
1741 | + architecture: armhf |
1742 | + partition-layout: minimal |
1743 | + bootloader: u-boot |
1744 | + boot-assets: |
1745 | + files: |
1746 | + - path: boot-assets/config.txt |
1747 | + - path: boot-assets/cmdline.txt |
1748 | + - path: boot-assets/uboot.bin |
1749 | + - path: boot-assets/uboot.env |
1750 | + - path: boot-assets/bcm2708-rpi-b.dtb |
1751 | + - path: boot-assets/bcm2708-rpi-b-plus.dtb |
1752 | + - path: boot-assets/bcm2709-rpi-2-b.dtb |
1753 | + - path: boot-assets/bootcode.bin |
1754 | + - path: boot-assets/COPYING.linux |
1755 | + - path: boot-assets/fixup_cd.dat |
1756 | + - path: boot-assets/fixup.dat |
1757 | + - path: boot-assets/fixup_x.dat |
1758 | + - path: boot-assets/LICENCE.broadcom |
1759 | + - path: boot-assets/LICENSE.oracle |
1760 | + - path: boot-assets/start_cd.elf |
1761 | + - path: boot-assets/start.elf |
1762 | + - path: boot-assets/start_x.elf |
1763 | + - path: boot-assets/overlays.tgz |
1764 | +` |
1765 | + |
1766 | +var compatCanonicalDragon = ` |
1767 | +name: canonical-dragon |
1768 | +gadget: |
1769 | + branding: |
1770 | + name: Dragonboard |
1771 | + subname: Dragonboard |
1772 | + |
1773 | + hardware: |
1774 | + platform: msm8916-mtp |
1775 | + architecture: arm64 |
1776 | + partition-layout: minimal |
1777 | + bootloader: u-boot |
1778 | + boot-assets: |
1779 | + files: |
1780 | + - path: uboot.env |
1781 | + raw-files: |
1782 | + - path: sbl1.mbn |
1783 | + offset: 17408 |
1784 | + - path: rpm.mbn |
1785 | + offset: 541696 |
1786 | + - path: tz.mbn |
1787 | + offset: 1065984 |
1788 | + - path: hyp.mbn |
1789 | + offset: 1590272 |
1790 | + - path: sec.dat |
1791 | + offset: 2114560 |
1792 | + - path: sd_appsboot.mbn |
1793 | + offset: 2130944 |
1794 | + - path: u-boot.img |
1795 | + offset: 3179520 |
1796 | + raw-partitions: |
1797 | + - name: sbl1 |
1798 | + size: 512 |
1799 | + pos: 34 |
1800 | + type: DEA0BA2C-CBDD-4805-B4F9-F428251C3E98 |
1801 | + - name: rpm |
1802 | + size: 512 |
1803 | + type: 098DF793-D712-413D-9D4E-89D711772228 |
1804 | + - name: tz |
1805 | + size: 512 |
1806 | + type: A053AA7F-40B8-4B1C-BA08-2F68AC71A4F4 |
1807 | + - name: hyp |
1808 | + size: 512 |
1809 | + type: E1A6A689-0C8D-4CC6-B4E8-55A4320FBD8A |
1810 | + - name: sec |
1811 | + size: 16 |
1812 | + type: 303E6AC3-AF15-4C54-9E9B-D9A8FBECF401 |
1813 | + - name: aboot |
1814 | + size: 1024 |
1815 | + type: 400FFDCD-22E0-47E7-9A23-F16ED9382388 |
1816 | + - name: boot |
1817 | + size: 512 |
1818 | + type: 20117F86-E985-4357-B9EE-374BC1D8487D |
1819 | +` |