Merge lp:~chipaca/snappy/activate-package into lp:~snappy-dev/snappy/snappy-moved-to-github

Proposed by John Lenton on 2015-09-29
Status: Merged
Approved by: Michael Vogt on 2015-10-05
Approved revision: 727
Merge reported by: John Lenton
Merged at revision: not available
Proposed branch: lp:~chipaca/snappy/activate-package
Merge into: lp:~snappy-dev/snappy/snappy-moved-to-github
Diff against target: 507 lines (+289/-32)
11 files modified
cmd/snappy/cmd_activate.go (+60/-0)
daemon/api.go (+12/-0)
daemon/snappy_part_iface_test.go (+2/-2)
po/snappy.pot (+13/-1)
snappy/parts.go (+3/-3)
snappy/set_active.go (+53/-0)
snappy/set_active_test.go (+20/-0)
snappy/snapp.go (+7/-3)
snappy/snapp_test.go (+2/-1)
snappy/systemimage.go (+23/-11)
snappy/systemimage_test.go (+94/-11)
To merge this branch: bzr merge lp:~chipaca/snappy/activate-package
Reviewer Review Type Date Requested Status
Michael Vogt 2015-09-29 Approve on 2015-10-05
Review via email: mp+272716@code.launchpad.net

Commit Message

activate/deactivate packages.

To post a comment you must log in.
lp:~chipaca/snappy/activate-package updated on 2015-09-29
727. By John Lenton on 2015-09-29

Merged current-data-dir into activate-package.

Michael Vogt (mvo) wrote :

Very nice!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'cmd/snappy/cmd_activate.go'
2--- cmd/snappy/cmd_activate.go 1970-01-01 00:00:00 +0000
3+++ cmd/snappy/cmd_activate.go 2015-09-29 12:18:14 +0000
4@@ -0,0 +1,60 @@
5+// -*- Mode: Go; indent-tabs-mode: t -*-
6+
7+/*
8+ * Copyright (C) 2015 Canonical Ltd
9+ *
10+ * This program is free software: you can redistribute it and/or modify
11+ * it under the terms of the GNU General Public License version 3 as
12+ * published by the Free Software Foundation.
13+ *
14+ * This program is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ * GNU General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU General Public License
20+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21+ *
22+ */
23+
24+package main
25+
26+import (
27+ "launchpad.net/snappy/i18n"
28+ "launchpad.net/snappy/logger"
29+ "launchpad.net/snappy/progress"
30+ "launchpad.net/snappy/snappy"
31+)
32+
33+type cmdActivate struct {
34+ Args struct {
35+ Snap string `positional-arg-name:"snap"`
36+ } `positional-args:"yes" required:"very yes"`
37+ activate bool
38+}
39+
40+func init() {
41+ _, err := parser.AddCommand("activate",
42+ i18n.G(`Activate a package`),
43+ i18n.G(`Activate a package that has previously been deactivated. If the package is already activated, do nothing.`),
44+ &cmdActivate{activate: true})
45+ if err != nil {
46+ logger.Panicf("Unable to activate: %v", err)
47+ }
48+
49+ _, err = parser.AddCommand("deactivate",
50+ i18n.G(`Deactivate a package`),
51+ i18n.G(`Deactivate a package. If the package is already deactivated, do nothing.`),
52+ &cmdActivate{activate: false})
53+ if err != nil {
54+ logger.Panicf("Unable to deactivate: %v", err)
55+ }
56+}
57+
58+func (x *cmdActivate) Execute(args []string) error {
59+ return withMutex(x.doActivate)
60+}
61+
62+func (x *cmdActivate) doActivate() error {
63+ return snappy.SetActive(x.Args.Snap, x.activate, progress.MakeProgressBar())
64+}
65
66=== modified file 'daemon/api.go'
67--- daemon/api.go 2015-09-15 12:57:04 +0000
68+++ daemon/api.go 2015-09-29 12:18:14 +0000
69@@ -569,6 +569,14 @@
70 return err
71 }
72
73+func (inst *packageInstruction) activate() interface{} {
74+ return snappy.SetActive(inst.pkg, true, inst.prog)
75+}
76+
77+func (inst *packageInstruction) deactivate() interface{} {
78+ return snappy.SetActive(inst.pkg, false, inst.prog)
79+}
80+
81 func (inst *packageInstruction) dispatch() func() interface{} {
82 switch inst.Action {
83 case "install":
84@@ -582,6 +590,10 @@
85 return inst.purge
86 case "rollback":
87 return inst.rollback
88+ case "activate":
89+ return inst.activate
90+ case "deactivate":
91+ return inst.deactivate
92 default:
93 return nil
94 }
95
96=== modified file 'daemon/snappy_part_iface_test.go'
97--- daemon/snappy_part_iface_test.go 2015-09-14 14:35:06 +0000
98+++ daemon/snappy_part_iface_test.go 2015-09-29 12:18:14 +0000
99@@ -83,8 +83,8 @@
100 }
101 return p.config, p.configErr
102 }
103-func (p *tP) SetActive(progress.Meter) error { return p.setActiveErr }
104-func (p *tP) Frameworks() ([]string, error) { return p.frameworks, p.frameworksErr }
105+func (p *tP) SetActive(bool, progress.Meter) error { return p.setActiveErr }
106+func (p *tP) Frameworks() ([]string, error) { return p.frameworks, p.frameworksErr }
107
108 // for ServiceYamler interface:
109 func (p *tP) ServiceYamls() []snappy.ServiceYaml { return p.svcYamls }
110
111=== modified file 'po/snappy.pot'
112--- po/snappy.pot 2015-09-14 09:22:43 +0000
113+++ po/snappy.pot 2015-09-29 12:18:14 +0000
114@@ -7,7 +7,7 @@
115 msgid ""
116 msgstr "Project-Id-Version: snappy\n"
117 "Report-Msgid-Bugs-To: snappy-devel@lists.ubuntu.com\n"
118- "POT-Creation-Date: 2015-09-14 10:22+0100\n"
119+ "POT-Creation-Date: 2015-09-29 10:18+0100\n"
120 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
121 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
122 "Language-Team: LANGUAGE <LL@li.org>\n"
123@@ -61,6 +61,12 @@
124 "The verbose version of the info command for a package will also tell you the available channels for that package, when it was installed for the first time, disk space utilization, and in the case of frameworks, which apps are able to use the framework."
125 msgstr ""
126
127+msgid "Activate a package"
128+msgstr ""
129+
130+msgid "Activate a package that has previously been deactivated. If the package is already activated, do nothing."
131+msgstr ""
132+
133 msgid "Allows rollback of a snap to a previous installed version. Without any arguments, the previous installed version is selected. It is also possible to specify the version to rollback to as a additional argument.\n"
134 msgstr ""
135
136@@ -84,6 +90,12 @@
137 msgid "Creates a snap package and if available, runs the review scripts."
138 msgstr ""
139
140+msgid "Deactivate a package"
141+msgstr ""
142+
143+msgid "Deactivate a package. If the package is already deactivated, do nothing."
144+msgstr ""
145+
146 msgid "Display a summary of key attributes of the snappy system."
147 msgstr ""
148
149
150=== modified file 'snappy/parts.go'
151--- snappy/parts.go 2015-09-25 15:27:11 +0000
152+++ snappy/parts.go 2015-09-29 12:18:14 +0000
153@@ -92,8 +92,8 @@
154 // Config takes a yaml configuration and returns the full snap
155 // config with the changes. Note that "configuration" may be empty.
156 Config(configuration []byte) (newConfig string, err error)
157- // make a inactive part active
158- SetActive(pb progress.Meter) error
159+ // make an inactive part active, or viceversa
160+ SetActive(bool, progress.Meter) error
161
162 // get the list of frameworks needed by the part
163 Frameworks() ([]string, error)
164@@ -334,7 +334,7 @@
165 case 0:
166 return fmt.Errorf("Can not find %s with version %s", pkg, ver)
167 case 1:
168- return parts[0].SetActive(inter)
169+ return parts[0].SetActive(true, inter)
170 default:
171 return fmt.Errorf("More than one %s with version %s", pkg, ver)
172 }
173
174=== added file 'snappy/set_active.go'
175--- snappy/set_active.go 1970-01-01 00:00:00 +0000
176+++ snappy/set_active.go 2015-09-29 12:18:14 +0000
177@@ -0,0 +1,53 @@
178+// -*- Mode: Go; indent-tabs-mode: t -*-
179+
180+/*
181+ * Copyright (C) 2015 Canonical Ltd
182+ *
183+ * This program is free software: you can redistribute it and/or modify
184+ * it under the terms of the GNU General Public License version 3 as
185+ * published by the Free Software Foundation.
186+ *
187+ * This program is distributed in the hope that it will be useful,
188+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
189+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
190+ * GNU General Public License for more details.
191+ *
192+ * You should have received a copy of the GNU General Public License
193+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
194+ *
195+ */
196+
197+package snappy
198+
199+import (
200+ "sort"
201+
202+ "launchpad.net/snappy/progress"
203+)
204+
205+// SetActive sets the active state of the given package
206+func SetActive(fullName string, active bool, meter progress.Meter) error {
207+ // TODO: switch this to using husks
208+ m := NewMetaLocalRepository()
209+ installed, err := m.Installed()
210+ if err != nil {
211+ return err
212+ }
213+
214+ parts := FindSnapsByName(fullName, installed)
215+ if len(parts) == 0 {
216+ return ErrPackageNotFound
217+ }
218+
219+ sort.Sort(sort.Reverse(BySnapVersion(parts)))
220+
221+ part := parts[0]
222+ for i := range parts {
223+ if parts[i].IsActive() {
224+ part = parts[i]
225+ break
226+ }
227+ }
228+
229+ return part.SetActive(active, meter)
230+}
231
232=== added file 'snappy/set_active_test.go'
233--- snappy/set_active_test.go 1970-01-01 00:00:00 +0000
234+++ snappy/set_active_test.go 2015-09-29 12:18:14 +0000
235@@ -0,0 +1,20 @@
236+// -*- Mode: Go; indent-tabs-mode: t -*-
237+
238+/*
239+ * Copyright (C) 2015 Canonical Ltd
240+ *
241+ * This program is free software: you can redistribute it and/or modify
242+ * it under the terms of the GNU General Public License version 3 as
243+ * published by the Free Software Foundation.
244+ *
245+ * This program is distributed in the hope that it will be useful,
246+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
247+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
248+ * GNU General Public License for more details.
249+ *
250+ * You should have received a copy of the GNU General Public License
251+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
252+ *
253+ */
254+
255+package snappy
256
257=== modified file 'snappy/snapp.go'
258--- snappy/snapp.go 2015-09-29 07:07:13 +0000
259+++ snappy/snapp.go 2015-09-29 12:18:14 +0000
260@@ -981,8 +981,12 @@
261 }
262
263 // SetActive sets the snap active
264-func (s *SnapPart) SetActive(pb progress.Meter) (err error) {
265- return s.activate(false, pb)
266+func (s *SnapPart) SetActive(active bool, pb progress.Meter) (err error) {
267+ if active {
268+ return s.activate(false, pb)
269+ }
270+
271+ return s.deactivate(false, pb)
272 }
273
274 func (s *SnapPart) activate(inhibitHooks bool, inter interacter) error {
275@@ -1653,7 +1657,7 @@
276 }
277
278 // SetActive sets the snap active
279-func (s *RemoteSnapPart) SetActive(progress.Meter) error {
280+func (s *RemoteSnapPart) SetActive(bool, progress.Meter) error {
281 return ErrNotInstalled
282 }
283
284
285=== modified file 'snappy/snapp_test.go'
286--- snappy/snapp_test.go 2015-09-25 15:27:11 +0000
287+++ snappy/snapp_test.go 2015-09-29 12:18:14 +0000
288@@ -770,7 +770,8 @@
289 func (s *SnapTestSuite) TestRemoteSnapErrors(c *C) {
290 snap := RemoteSnapPart{}
291
292- c.Assert(snap.SetActive(nil), Equals, ErrNotInstalled)
293+ c.Assert(snap.SetActive(true, nil), Equals, ErrNotInstalled)
294+ c.Assert(snap.SetActive(false, nil), Equals, ErrNotInstalled)
295 c.Assert(snap.Uninstall(nil), Equals, ErrNotInstalled)
296 }
297
298
299=== modified file 'snappy/systemimage.go'
300--- snappy/systemimage.go 2015-09-15 12:55:09 +0000
301+++ snappy/systemimage.go 2015-09-29 12:18:14 +0000
302@@ -155,18 +155,30 @@
303 }
304
305 // SetActive sets the snap active
306-func (s *SystemImagePart) SetActive(pb progress.Meter) (err error) {
307+func (s *SystemImagePart) SetActive(active bool, pb progress.Meter) error {
308 isNextBootOther := s.partition.IsNextBootOther()
309- // active and no switch scheduled -> nothing to do
310- if s.IsActive() && !isNextBootOther {
311- return nil
312- }
313- // not currently active but switch scheduled already -> nothing to do
314- if !s.IsActive() && isNextBootOther {
315- return nil
316- }
317-
318- return s.partition.ToggleNextBoot()
319+ isActive := s.IsActive()
320+
321+ // * active
322+ // | * isActive
323+ // | | * isNextBootOther
324+ // | | |
325+ // F F F nop
326+ // F F T toggle
327+ // F T F toggle
328+ // F T T nop
329+ // T F F toggle
330+ // T F T nop
331+ // T T F nop
332+ // T T T toggle
333+ //
334+ // ∴ this function is the parity (a.k.a. XOR, ⊻) of these inputs \o/
335+ // ( and, ∀ p, q boolean: p ⊻ q ⇔ p ≠ q )
336+ if active != isActive != isNextBootOther {
337+ return s.partition.ToggleNextBoot()
338+ }
339+
340+ return nil
341 }
342
343 // override in tests
344
345=== modified file 'snappy/systemimage_test.go'
346--- snappy/systemimage_test.go 2015-07-15 07:53:43 +0000
347+++ snappy/systemimage_test.go 2015-09-29 12:18:14 +0000
348@@ -147,13 +147,13 @@
349 }
350
351 type MockPartition struct {
352- toggleNextBootCalled bool
353+ toggleNextBoot bool
354 markBootSuccessfulCalled bool
355 syncBootloaderFilesCalled bool
356 }
357
358 func (p *MockPartition) ToggleNextBoot() error {
359- p.toggleNextBootCalled = true
360+ p.toggleNextBoot = !p.toggleNextBoot
361 return nil
362 }
363
364@@ -166,7 +166,7 @@
365 return nil
366 }
367 func (p *MockPartition) IsNextBootOther() bool {
368- return false
369+ return p.toggleNextBoot
370 }
371
372 func (p *MockPartition) RunWithOther(option partition.MountOption, f func(otherRoot string) (err error)) (err error) {
373@@ -199,7 +199,7 @@
374 // do the install
375 _, err = sp.Install(pb, 0)
376 c.Assert(err, IsNil)
377- c.Assert(mockPartition.toggleNextBootCalled, Equals, true)
378+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
379 c.Assert(pb.total, Equals, 100.0)
380 c.Assert(pb.spin, Equals, true)
381 c.Assert(pb.spinMsg, Equals, "Applying")
382@@ -269,7 +269,7 @@
383
384 _, err = sp.Install(nil, 0)
385 c.Assert(err, IsNil)
386- c.Assert(mockPartition.toggleNextBootCalled, Equals, true)
387+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
388 }
389
390 func (s *SITestSuite) TestSystemImagePartSetActiveAlreadyActive(c *C) {
391@@ -280,9 +280,9 @@
392 mockPartition := MockPartition{}
393 sp.partition = &mockPartition
394
395- err = sp.SetActive(nil)
396+ err = sp.SetActive(true, nil)
397 c.Assert(err, IsNil)
398- c.Assert(mockPartition.toggleNextBootCalled, Equals, false)
399+ c.Assert(mockPartition.toggleNextBoot, Equals, false)
400 }
401
402 func (s *SITestSuite) TestSystemImagePartSetActiveMakeActive(c *C) {
403@@ -293,9 +293,92 @@
404 mockPartition := MockPartition{}
405 sp.partition = &mockPartition
406
407- err = sp.SetActive(nil)
408- c.Assert(err, IsNil)
409- c.Assert(mockPartition.toggleNextBootCalled, Equals, true)
410+ err = sp.SetActive(true, nil)
411+ c.Assert(err, IsNil)
412+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
413+}
414+
415+func (s *SITestSuite) TestSystemImagePartSetActiveAlreadyToggled(c *C) {
416+ // in other words, check that calling SetActive twice does not
417+ // untoggle
418+ parts, err := s.systemImage.Installed()
419+
420+ sp := parts[1].(*SystemImagePart)
421+ c.Assert(sp.IsActive(), Equals, false)
422+ mockPartition := MockPartition{toggleNextBoot: true}
423+ sp.partition = &mockPartition
424+
425+ err = sp.SetActive(true, nil)
426+ c.Assert(err, IsNil)
427+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
428+}
429+
430+func (s *SITestSuite) TestSystemImagePartSetActiveAlreadyActiveAlreadyToggled(c *C) {
431+ // in other words, check that calling SetActive on one
432+ // partition when it's been called on the other one undoes the
433+ // toggle
434+ parts, err := s.systemImage.Installed()
435+
436+ sp := parts[0].(*SystemImagePart)
437+ c.Assert(sp.IsActive(), Equals, true)
438+ mockPartition := MockPartition{toggleNextBoot: true}
439+ sp.partition = &mockPartition
440+
441+ err = sp.SetActive(true, nil)
442+ c.Assert(err, IsNil)
443+ c.Assert(mockPartition.toggleNextBoot, Equals, false)
444+}
445+
446+func (s *SITestSuite) TestSystemImagePartUnsetActiveOnActive(c *C) {
447+ parts, err := s.systemImage.Installed()
448+
449+ sp := parts[0].(*SystemImagePart)
450+ c.Assert(sp.IsActive(), Equals, true)
451+ mockPartition := MockPartition{}
452+ sp.partition = &mockPartition
453+
454+ err = sp.SetActive(false, nil)
455+ c.Assert(err, IsNil)
456+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
457+}
458+
459+func (s *SITestSuite) TestSystemImagePartUnsetActiveOnUnactiveNOP(c *C) {
460+ parts, err := s.systemImage.Installed()
461+
462+ sp := parts[1].(*SystemImagePart)
463+ c.Assert(sp.IsActive(), Equals, false)
464+ mockPartition := MockPartition{}
465+ sp.partition = &mockPartition
466+
467+ err = sp.SetActive(false, nil)
468+ c.Assert(err, IsNil)
469+ c.Assert(mockPartition.toggleNextBoot, Equals, false)
470+}
471+
472+func (s *SITestSuite) TestSystemImagePartUnsetActiveAlreadyToggled(c *C) {
473+ parts, err := s.systemImage.Installed()
474+
475+ sp := parts[1].(*SystemImagePart)
476+ c.Assert(sp.IsActive(), Equals, false)
477+ mockPartition := MockPartition{toggleNextBoot: true}
478+ sp.partition = &mockPartition
479+
480+ err = sp.SetActive(false, nil)
481+ c.Assert(err, IsNil)
482+ c.Assert(mockPartition.toggleNextBoot, Equals, false)
483+}
484+
485+func (s *SITestSuite) TestSystemImagePartUnsetActiveAlreadyActiveAlreadyToggled(c *C) {
486+ parts, err := s.systemImage.Installed()
487+
488+ sp := parts[0].(*SystemImagePart)
489+ c.Assert(sp.IsActive(), Equals, true)
490+ mockPartition := MockPartition{toggleNextBoot: true}
491+ sp.partition = &mockPartition
492+
493+ err = sp.SetActive(false, nil)
494+ c.Assert(err, IsNil)
495+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
496 }
497
498 func (s *SITestSuite) TestTestVerifyUpgradeWasAppliedSuccess(c *C) {
499@@ -464,7 +547,7 @@
500
501 // ensure that we do not sync the bootfiles in this case (see above)
502 c.Assert(mockPartition.syncBootloaderFilesCalled, Equals, false)
503- c.Assert(mockPartition.toggleNextBootCalled, Equals, true)
504+ c.Assert(mockPartition.toggleNextBoot, Equals, true)
505 }
506
507 func (s *SITestSuite) TestNeedsBootAssetSyncNeedsSync(c *C) {

Subscribers

People subscribed via source and target branches