Merge lp:~sergiusens/snapcraft/ubuntu-core into lp:~snappy-dev/snapcraft/core

Proposed by Sergio Schvezov
Status: Merged
Approved by: Michael Vogt
Approved revision: 163
Merged at revision: 154
Proposed branch: lp:~sergiusens/snapcraft/ubuntu-core
Merge into: lp:~snappy-dev/snapcraft/core
Diff against target: 1062 lines (+306/-369)
28 files modified
debian/control (+0/-1)
examples/webcam-webui-snap/snapcraft.yaml (+2/-2)
examples/wget-deb/snapcraft.yaml (+0/-12)
integration-tests/data/assemble/snapcraft.yaml (+1/-1)
plugins/ant-project.yaml (+1/-0)
plugins/autotools-project.yaml (+8/-7)
plugins/cmake-project.yaml (+1/-0)
plugins/copy.yaml (+1/-1)
plugins/go-project.yaml (+1/-0)
plugins/make-project.yaml (+1/-0)
plugins/maven-project.yaml (+1/-0)
plugins/python2-project.yaml (+1/-0)
plugins/python3-project.yaml (+1/-0)
plugins/tar-content.yaml (+1/-0)
plugins/ubuntu.yaml (+0/-6)
schema/snapcraft.yaml (+9/-3)
setup.py (+1/-1)
snapcraft/__init__.py (+13/-0)
snapcraft/plugin.py (+21/-4)
snapcraft/plugins/jdk.py (+6/-16)
snapcraft/plugins/python2.py (+3/-16)
snapcraft/plugins/python3.py (+3/-16)
snapcraft/plugins/qml.py (+40/-53)
snapcraft/plugins/tests/test_ubuntu.py (+0/-61)
snapcraft/plugins/ubuntu.py (+0/-132)
snapcraft/repo.py (+132/-0)
snapcraft/tests/test_repo.py (+38/-22)
snapcraft/tests/test_yaml.py (+20/-15)
To merge this branch: bzr merge lp:~sergiusens/snapcraft/ubuntu-core
Reviewer Review Type Date Requested Status
Michael Vogt (community) Approve
Review via email: mp+269938@code.launchpad.net

Commit message

Replace Ubuntu plugin with a builtin solution

Description of the change

This completely removes the Ubuntu plugin and introduces stage-packages for
both plugins and parts in one big bundle.

I'm not sure the big bundle is the best solution, but if required a plugin author could use repo.Ubuntu directly and independently from what a part does.

This is missing complete feature parity as the get_snap_files equivalent is missing and coming with filtering implementation exposed in the part.

As you can see, this model invalidates the wget example because it is a 1:1 conversion and nothing else, not sure if this was the desired outcome from the proposal.

To post a comment you must log in.
lp:~sergiusens/snapcraft/ubuntu-core updated
155. By Sergio Schvezov

Making PLUGIN_STAGE_PACKAGES private so isbaseclass in the plugin loader doesn't get all confused

156. By Sergio Schvezov

merging trunk

157. By Sergio Schvezov

stage-package for parts and plugins separation of concerns

Revision history for this message
Ted Gould (ted) wrote :

I've been playing with this for the Python PIP case, and I think it gets
a little confusing. The problem is that for the PIP case we need to have
the packages installed before we can use them to download the packages
from the PIP repository. So by specifying the packages we can't then use
PIP in the pull phase for the plugin. The reason that we need to be in
the pull phase is that we want to be the stage that everything is
downloaded in, which clearly PIP does a fair amount of.

I also think that we need to maintain the package list as a singleton in
the core of snapcraft as if two parts want to use the same Ubuntu
package, that should be fine, but we can't install both of them into the
snap. This gets complicated with multiple repositories (having one part
and set of deps that are built on one distro version and another on a
different version; complicated but something that'll probably happen
when people use the wiki entries) but I think the singleton can handle
this by installing them to different directories in that case.

I think that this architecture means that also we can effectively create
a virtual dependency for each plugin that uses Ubuntu packages, so that
it can run all of its phases after the Ubuntu plugin installs its
packages. In that way the other plugins can use the packages that are
installed to evaluate their own phases.

I'm a little concerned with the idea that we'd install the packages
before running the pull phases of the other plugins. I think that this
creates a scenario where we can't do all the downloads in one phase.
This is a traditional setup for the builders to limit exposure to user
delivered code, so they can turn off networking while things are
building. But, I don't see a way around that. I think we'll have to have
that conversation with the LP folks as it comes along. We may have to
provide a "virtual" ubuntu plugin for non-Ubuntu repositories so that
the only execution before pull are done with packages in the official
repos. But, I don't think we need to solve that problem today :-)

lp:~sergiusens/snapcraft/ubuntu-core updated
158. By Sergio Schvezov

pull stage packages before pulling the code

159. By Sergio Schvezov

cleanup

Revision history for this message
Leo Arias (elopio) wrote :

Just a couple of comments on the diff.

And a question: how would you build a deb into a snap?

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

> And a question: how would you build a deb into a snap?

The simple answer, which may support the third paragraph in the description, is that the new design doesn't allow for a 1:1 translation, so snaps based out of pure ubuntu packages are not allowed but instead used to support greater snaps.

lp:~sergiusens/snapcraft/ubuntu-core updated
160. By Sergio Schvezov

minor elopio improvement

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks, this looks good! I have some inline comments, but nothing that blocks this from landing, a mix of nitpick and ideas for improvement. I like the idea of running it before pull and to allow the plugins to override it.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

@mvo, thanks for the review, I'll look into addressing your comments

lp:~sergiusens/snapcraft/ubuntu-core updated
161. By Sergio Schvezov

Simplifying __init__ for plugins and stage packages

Revision history for this message
Sergio Schvezov (sergiusens) :
lp:~sergiusens/snapcraft/ubuntu-core updated
162. By Sergio Schvezov

making manifest.txt useful again

163. By Sergio Schvezov

Merging trunk

Revision history for this message
Michael Vogt (mvo) wrote :

Nice, thanks for addressing my comments.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-09-02 07:48:09 +0000
3+++ debian/control 2015-09-08 12:03:39 +0000
4@@ -31,7 +31,6 @@
5 Depends: ${misc:Depends},
6 ${python3:Depends},
7 bzr,
8- devscripts,
9 dpkg-dev,
10 git,
11 python3-apt,
12
13=== modified file 'examples/webcam-webui-snap/snapcraft.yaml'
14--- examples/webcam-webui-snap/snapcraft.yaml 2015-08-27 21:33:56 +0000
15+++ examples/webcam-webui-snap/snapcraft.yaml 2015-09-08 12:03:39 +0000
16@@ -13,9 +13,9 @@
17 golang-static-http:
18 plugin: go-project
19 source: git://github.com/mikix/golang-static-http
20- fswebcam:
21- plugin: ubuntu
22 glue:
23 plugin: copy
24+ stage-packages:
25+ - fswebcam
26 files:
27 webcam-webui: bin/webcam-webui
28
29=== removed directory 'examples/wget-deb'
30=== removed file 'examples/wget-deb/icon.png'
31Binary files examples/wget-deb/icon.png 2015-08-27 21:33:56 +0000 and examples/wget-deb/icon.png 1970-01-01 00:00:00 +0000 differ
32=== removed file 'examples/wget-deb/snapcraft.yaml'
33--- examples/wget-deb/snapcraft.yaml 2015-08-27 21:33:56 +0000
34+++ examples/wget-deb/snapcraft.yaml 1970-01-01 00:00:00 +0000
35@@ -1,12 +0,0 @@
36-name: wget
37-version: 0
38-vendor: Michael Terry <mterry@ubuntu.com>
39-binaries:
40- - name: usr/bin/wget
41-summary: wget for snappy
42-description: a basic example from ubuntu packages
43-icon: icon.png
44-
45-parts:
46- wget:
47- plugin: ubuntu
48
49=== modified file 'integration-tests/data/assemble/snapcraft.yaml'
50--- integration-tests/data/assemble/snapcraft.yaml 2015-08-27 21:33:56 +0000
51+++ integration-tests/data/assemble/snapcraft.yaml 2015-09-08 12:03:39 +0000
52@@ -16,4 +16,4 @@
53
54 parts:
55 make-project:
56- source: .
57+ source: .
58
59=== modified file 'plugins/ant-project.yaml'
60--- plugins/ant-project.yaml 2015-09-02 08:56:06 +0000
61+++ plugins/ant-project.yaml 2015-09-08 12:03:39 +0000
62@@ -8,5 +8,6 @@
63 source-type:
64 source-tag:
65 source-branch:
66+ stage-packages:
67 build-tools:
68 - ant
69
70=== modified file 'plugins/autotools-project.yaml'
71--- plugins/autotools-project.yaml 2015-07-22 18:45:52 +0000
72+++ plugins/autotools-project.yaml 2015-09-08 12:03:39 +0000
73@@ -1,10 +1,11 @@
74 module: autotools_project
75 build-tools: [autoconf, automake, autopoint]
76 options:
77- source:
78- required: true
79- source-type:
80- source-tag:
81- source-branch:
82- configflags:
83- required: false
84+ source:
85+ required: true
86+ source-type:
87+ source-tag:
88+ source-branch:
89+ configflags:
90+ required: false
91+ stage-packages:
92
93=== modified file 'plugins/cmake-project.yaml'
94--- plugins/cmake-project.yaml 2015-07-22 18:45:52 +0000
95+++ plugins/cmake-project.yaml 2015-09-08 12:03:39 +0000
96@@ -8,3 +8,4 @@
97 source-branch:
98 configflags:
99 required: false
100+ stage-packages:
101
102=== modified file 'plugins/copy.yaml'
103--- plugins/copy.yaml 2015-07-17 06:40:24 +0000
104+++ plugins/copy.yaml 2015-09-08 12:03:39 +0000
105@@ -1,4 +1,4 @@
106 options:
107 files:
108 required: true
109-
110+ stage-packages:
111
112=== modified file 'plugins/go-project.yaml'
113--- plugins/go-project.yaml 2015-07-31 15:16:47 +0000
114+++ plugins/go-project.yaml 2015-09-08 12:03:39 +0000
115@@ -6,3 +6,4 @@
116 required: true
117 configflags:
118 required: false
119+ stage-packages:
120
121=== modified file 'plugins/make-project.yaml'
122--- plugins/make-project.yaml 2015-07-22 18:45:52 +0000
123+++ plugins/make-project.yaml 2015-09-08 12:03:39 +0000
124@@ -6,3 +6,4 @@
125 source-type:
126 source-tag:
127 source-branch:
128+ stage-packages:
129
130=== modified file 'plugins/maven-project.yaml'
131--- plugins/maven-project.yaml 2015-08-19 17:42:25 +0000
132+++ plugins/maven-project.yaml 2015-09-08 12:03:39 +0000
133@@ -9,3 +9,4 @@
134 source-type:
135 source-tag:
136 source-branch:
137+ stage-packages:
138
139=== modified file 'plugins/python2-project.yaml'
140--- plugins/python2-project.yaml 2015-08-03 18:21:58 +0000
141+++ plugins/python2-project.yaml 2015-09-08 12:03:39 +0000
142@@ -7,3 +7,4 @@
143 source-type:
144 source-tag:
145 source-branch:
146+ stage-packages:
147
148=== modified file 'plugins/python3-project.yaml'
149--- plugins/python3-project.yaml 2015-08-03 18:19:07 +0000
150+++ plugins/python3-project.yaml 2015-09-08 12:03:39 +0000
151@@ -7,3 +7,4 @@
152 source-type:
153 source-tag:
154 source-branch:
155+ stage-packages:
156
157=== modified file 'plugins/tar-content.yaml'
158--- plugins/tar-content.yaml 2015-07-17 19:39:00 +0000
159+++ plugins/tar-content.yaml 2015-09-08 12:03:39 +0000
160@@ -2,3 +2,4 @@
161 options:
162 source:
163 required: true
164+ stage-packages:
165
166=== removed file 'plugins/ubuntu.yaml'
167--- plugins/ubuntu.yaml 2015-08-05 18:40:06 +0000
168+++ plugins/ubuntu.yaml 1970-01-01 00:00:00 +0000
169@@ -1,6 +0,0 @@
170-build-tools: [devscripts]
171-options:
172- packages:
173- required: false
174- recommends:
175- required: false
176
177=== modified file 'schema/snapcraft.yaml'
178--- schema/snapcraft.yaml 2015-08-27 22:04:07 +0000
179+++ schema/snapcraft.yaml 2015-09-08 12:03:39 +0000
180@@ -79,10 +79,16 @@
181 source:
182 type: string
183 description: path to the sources
184- # TODO To be enabled once the Ubuntu plugin is removed
185+ stage-packages:
186+ type: array
187+ description: Ubuntu packages used to support the part.
188+ minItems: 1
189+ uniqueItems: true
190+ items:
191+ type: string
192 # required:
193- # - plugin
194- # - source
195+ # - plugin
196+ # - source
197 addtionalProperties: false
198 required:
199 - name
200
201=== modified file 'setup.py'
202--- setup.py 2015-08-25 20:32:40 +0000
203+++ setup.py 2015-09-08 12:03:39 +0000
204@@ -34,7 +34,7 @@
205 url="https://launchpad.net/snapcraft",
206 packages=['snapcraft',
207 'snapcraft.plugins'],
208- package_data={'snapcraft.plugins': ['manifest.txt']},
209+ package_data={'snapcraft': ['manifest.txt']},
210 scripts=['bin/snapcraft'],
211 data_files=[
212 ('share/snapcraft/plugins', ['plugins/' + x for x in os.listdir('plugins')]),
213
214=== modified file 'snapcraft/__init__.py'
215--- snapcraft/__init__.py 2015-08-31 13:49:40 +0000
216+++ snapcraft/__init__.py 2015-09-08 12:03:39 +0000
217@@ -19,6 +19,7 @@
218
219 import snapcraft.common
220 import snapcraft.sources
221+import snapcraft.repo
222
223
224 logger = logging.getLogger(__name__)
225@@ -26,11 +27,16 @@
226
227 class BasePlugin:
228
229+ @property
230+ def PLUGIN_STAGE_PACKAGES(self):
231+ return getattr(self, '_PLUGIN_STAGE_PACKAGES', [])
232+
233 def __init__(self, name, options):
234 self.name = name
235 self.options = options
236 self.sourcedir = os.path.join(os.getcwd(), "parts", self.name, "src")
237 self.builddir = os.path.join(os.getcwd(), "parts", self.name, "build")
238+ self.ubuntudir = os.path.join(os.getcwd(), "parts", self.name, 'ubuntu')
239 self.installdir = os.path.join(os.getcwd(), "parts", self.name, "install")
240 self.stagedir = os.path.join(os.getcwd(), "stage")
241 self.snapdir = os.path.join(os.getcwd(), "snap")
242@@ -91,6 +97,13 @@
243 def makedirs(self, d):
244 os.makedirs(d, exist_ok=True)
245
246+ def setup_stage_packages(self):
247+ ubuntu = snapcraft.repo.Ubuntu(self.ubuntudir)
248+ part_stage_packages = getattr(self.options, 'stage_packages', [])
249+ if self.PLUGIN_STAGE_PACKAGES or part_stage_packages:
250+ ubuntu.get(self.PLUGIN_STAGE_PACKAGES + part_stage_packages)
251+ ubuntu.unpack(self.installdir)
252+
253
254 def _get_source_handler(source_type, source):
255 if source_type is None:
256
257=== renamed file 'snapcraft/plugins/manifest.txt' => 'snapcraft/manifest.txt'
258=== modified file 'snapcraft/plugin.py'
259--- snapcraft/plugin.py 2015-08-28 15:38:04 +0000
260+++ snapcraft/plugin.py 2015-09-08 12:03:39 +0000
261@@ -24,6 +24,7 @@
262
263 import snapcraft
264 from snapcraft import common
265+from snapcraft import repo
266
267
268 logger = logging.getLogger(__name__)
269@@ -57,6 +58,7 @@
270 parts_dir = os.path.join(os.getcwd(), 'parts')
271 self.sourcedir = os.path.join(parts_dir, part_name, 'src')
272 self.builddir = os.path.join(parts_dir, part_name, 'build')
273+ self.ubuntudir = os.path.join(parts_dir, part_name, 'ubuntu')
274 self.installdir = os.path.join(parts_dir, part_name, 'install')
275 self.stagedir = os.path.join(os.getcwd(), 'stage')
276 self.snapdir = os.path.join(os.getcwd(), 'snap')
277@@ -127,7 +129,7 @@
278 def makedirs(self):
279 dirs = [
280 self.sourcedir, self.builddir, self.installdir, self.stagedir,
281- self.snapdir
282+ self.snapdir, self.ubuntudir
283 ]
284 for d in dirs:
285 os.makedirs(d, exist_ok=True)
286@@ -163,11 +165,25 @@
287 if not self.should_stage_run('pull', force):
288 return True
289 self.makedirs()
290- if self.code and hasattr(self.code, 'pull'):
291+
292+ run_setup_stage_packages = self.code and hasattr(self.code, 'setup_stage_packages')
293+ run_pull = self.code and hasattr(self.code, 'pull')
294+
295+ if run_setup_stage_packages or run_pull:
296 self.notify_stage("Pulling")
297+
298+ if run_setup_stage_packages:
299+ try:
300+ self.code.setup_stage_packages()
301+ except repo.PackageNotFoundError as e:
302+ logger.error(e.message)
303+ return False
304+
305+ if run_pull:
306 if not getattr(self.code, 'pull')():
307 return False
308- self.mark_done('pull')
309+
310+ self.mark_done('pull')
311 return True
312
313 def build(self, force=False):
314@@ -178,7 +194,8 @@
315 self.notify_stage("Building")
316 if not getattr(self.code, 'build')():
317 return False
318- self.mark_done('build')
319+
320+ self.mark_done('build')
321 return True
322
323 def stage(self, force=False):
324
325=== modified file 'snapcraft/plugins/jdk.py'
326--- snapcraft/plugins/jdk.py 2015-08-05 15:39:18 +0000
327+++ snapcraft/plugins/jdk.py 2015-09-08 12:03:39 +0000
328@@ -15,28 +15,18 @@
329 # along with this program. If not, see <http://www.gnu.org/licenses/>.
330
331 import snapcraft
332-from snapcraft.plugins.ubuntu import UbuntuPlugin
333
334
335 class JdkPlugin(snapcraft.BasePlugin):
336
337- def __init__(self, name, options):
338- super().__init__(name, options)
339-
340- class UbuntuOptions:
341- packages = ["default-jdk"]
342- self.ubuntu = UbuntuPlugin(name, UbuntuOptions())
343-
344- def pull(self):
345- return self.ubuntu.pull()
346-
347- def build(self):
348- return self.ubuntu.build()
349+ _PLUGIN_STAGE_PACKAGES = [
350+ 'default-jdk',
351+ ]
352
353 def env(self, root):
354- return self.ubuntu.env(root) + \
355- ['JAVA_HOME=%s/usr/lib/jvm/default-java' % root,
356- 'PATH=%s/usr/lib/jvm/default-java/bin:%s/usr/lib/jvm/default-java/jre/bin:$PATH' % (root, root)]
357+ return ['JAVA_HOME=%s/usr/lib/jvm/default-java' % root,
358+ 'PATH=%s/usr/lib/jvm/default-java/bin:'
359+ '%s/usr/lib/jvm/default-java/jre/bin:$PATH' % (root, root)]
360
361 def snap_files(self):
362 # Cut out jdk bits (jre bits are in default-java/jre)
363
364=== modified file 'snapcraft/plugins/python2.py'
365--- snapcraft/plugins/python2.py 2015-08-05 15:39:18 +0000
366+++ snapcraft/plugins/python2.py 2015-09-08 12:03:39 +0000
367@@ -15,27 +15,14 @@
368 # along with this program. If not, see <http://www.gnu.org/licenses/>.
369
370 import snapcraft
371-from snapcraft.plugins import ubuntu
372
373
374 class Python2Plugin(snapcraft.BasePlugin):
375
376- def __init__(self, name, options):
377- super().__init__(name, options)
378-
379- class UbuntuOptions:
380- packages = ["python-dev"]
381- self.ubuntu = ubuntu.UbuntuPlugin(name, UbuntuOptions())
382+ _PLUGIN_STAGE_PACKAGES = [
383+ 'python-dev',
384+ ]
385
386 # note that we don't need to set PYTHONHOME here,
387 # python discovers this automatically from it installed
388 # location. And PATH is automatically set by snapcraft.
389-
390- def pull(self):
391- return self.ubuntu.pull()
392-
393- def build(self):
394- return self.ubuntu.build()
395-
396- def snap_files(self):
397- return self.ubuntu.snap_files()
398
399=== modified file 'snapcraft/plugins/python3.py'
400--- snapcraft/plugins/python3.py 2015-08-05 15:39:18 +0000
401+++ snapcraft/plugins/python3.py 2015-09-08 12:03:39 +0000
402@@ -15,29 +15,16 @@
403 # along with this program. If not, see <http://www.gnu.org/licenses/>.
404
405 import snapcraft
406-from snapcraft.plugins.ubuntu import UbuntuPlugin
407
408
409 class Python3Plugin(snapcraft.BasePlugin):
410
411- def __init__(self, name, options):
412- super().__init__(name, options)
413-
414- class Py3Options:
415- packages = ["python3-dev"]
416- self.ubuntu = UbuntuPlugin(name, Py3Options())
417+ _PLUGIN_STAGE_PACKAGES = [
418+ 'python3-dev',
419+ ]
420
421 # note that we don't need to set PYTHONHOME here,
422 # python discovers this automatically from it installed
423 # location, see https://code.launchpad.net/~mvo/snapcraft/python3-project/+merge/264521/comments/664308
424 #
425 # PATH is automatically set by snapcraft
426-
427- def pull(self):
428- return self.ubuntu.pull()
429-
430- def build(self):
431- return self.ubuntu.build()
432-
433- def snap_files(self):
434- return self.ubuntu.snap_files()
435
436=== modified file 'snapcraft/plugins/qml.py'
437--- snapcraft/plugins/qml.py 2015-08-26 04:20:25 +0000
438+++ snapcraft/plugins/qml.py 2015-09-08 12:03:39 +0000
439@@ -15,61 +15,50 @@
440 # along with this program. If not, see <http://www.gnu.org/licenses/>.
441
442 import os
443+import snapcraft
444 import snapcraft.common
445
446-from snapcraft.plugins.ubuntu import UbuntuPlugin
447-
448
449 class QmlPlugin(snapcraft.BasePlugin):
450
451- def __init__(self, name, options):
452- super().__init__(name, options)
453-
454- class QmlPackageOptions:
455- packages = [
456- "qmlscene",
457- "qtdeclarative5-qtmir-plugin",
458- "mir-graphics-drivers-desktop",
459- "qtubuntu-desktop",
460- "ttf-ubuntu-font-family",
461- # if there's a metapackage for these, please swap it in here:
462- "qml-module-qt-labs-folderlistmodel",
463- "qml-module-qt-labs-settings",
464- "qml-module-qt-websockets",
465- "qml-module-qtfeedback",
466- "qml-module-qtgraphicaleffects",
467- "qml-module-qtlocation",
468- "qml-module-qtmultimedia",
469- "qml-module-qtorganizer",
470- "qml-module-qtpositioning",
471- "qml-module-qtqml-models2",
472- "qml-module-qtqml-statemachine",
473- "qml-module-qtquick-controls",
474- "qml-module-qtquick-dialogs",
475- "qml-module-qtquick-layouts",
476- "qml-module-qtquick-localstorage",
477- "qml-module-qtquick-particles2",
478- "qml-module-qtquick-privatewidgets",
479- "qml-module-qtquick-window2",
480- "qml-module-qtquick-xmllistmodel",
481- "qml-module-qtquick2",
482- "qml-module-qtsensors",
483- "qml-module-qtsysteminfo",
484- "qml-module-qttest",
485- "qml-module-qtwebkit",
486- "qml-module-ubuntu-connectivity",
487- "qml-module-ubuntu-onlineaccounts",
488- "qml-module-ubuntu-onlineaccounts-client",
489- ]
490- recommends = False
491-
492- self.ubuntu = UbuntuPlugin(name, QmlPackageOptions())
493-
494- def pull(self):
495- return self.ubuntu.pull()
496+ _PLUGIN_STAGE_PACKAGES = [
497+ "qmlscene",
498+ "qtdeclarative5-qtmir-plugin",
499+ "mir-graphics-drivers-desktop",
500+ "qtubuntu-desktop",
501+ "ttf-ubuntu-font-family",
502+ # if there's a metapackage for these, please swap it in here:
503+ "qml-module-qt-labs-folderlistmodel",
504+ "qml-module-qt-labs-settings",
505+ "qml-module-qt-websockets",
506+ "qml-module-qtfeedback",
507+ "qml-module-qtgraphicaleffects",
508+ "qml-module-qtlocation",
509+ "qml-module-qtmultimedia",
510+ "qml-module-qtorganizer",
511+ "qml-module-qtpositioning",
512+ "qml-module-qtqml-models2",
513+ "qml-module-qtqml-statemachine",
514+ "qml-module-qtquick-controls",
515+ "qml-module-qtquick-dialogs",
516+ "qml-module-qtquick-layouts",
517+ "qml-module-qtquick-localstorage",
518+ "qml-module-qtquick-particles2",
519+ "qml-module-qtquick-privatewidgets",
520+ "qml-module-qtquick-window2",
521+ "qml-module-qtquick-xmllistmodel",
522+ "qml-module-qtquick2",
523+ "qml-module-qtsensors",
524+ "qml-module-qtsysteminfo",
525+ "qml-module-qttest",
526+ "qml-module-qtwebkit",
527+ "qml-module-ubuntu-connectivity",
528+ "qml-module-ubuntu-onlineaccounts",
529+ "qml-module-ubuntu-onlineaccounts-client",
530+ ]
531
532 def snap_files(self):
533- include, exclude = self.ubuntu.snap_files()
534+ include, exclude = ['*'], []
535 include.append('./etc/xdg/qtchooser/snappy-qt5.conf')
536 return (include, exclude)
537
538@@ -84,12 +73,11 @@
539 return True
540
541 def build(self):
542- return self.ubuntu.build() and self.build_qt_config()
543+ return self.build_qt_config()
544
545 def env(self, root):
546 arch = snapcraft.common.get_arch_triplet()
547- envs = self.ubuntu.env(root)
548- envs.extend([
549+ return [
550 "LD_LIBRARY_PATH=%s/usr/lib/%s:$LD_LIBRARY_PATH" % (root, arch),
551 # Mir config
552 "MIR_SOCKET=/run/mir_socket",
553@@ -118,5 +106,4 @@
554 # Font Config
555 "FONTCONFIG_PATH=%s/etc/fonts/config.d" % root,
556 "FONTCONFIG_FILE=%s/etc/fonts/fonts.conf" % root,
557- ])
558- return envs
559+ ]
560
561=== removed directory 'snapcraft/plugins/tests'
562=== removed file 'snapcraft/plugins/tests/__init__.py'
563=== removed file 'snapcraft/plugins/tests/test_ubuntu.py'
564--- snapcraft/plugins/tests/test_ubuntu.py 2015-08-06 01:00:44 +0000
565+++ snapcraft/plugins/tests/test_ubuntu.py 1970-01-01 00:00:00 +0000
566@@ -1,61 +0,0 @@
567-# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
568-#
569-# Copyright (C) 2015 Canonical Ltd
570-#
571-# This program is free software: you can redistribute it and/or modify
572-# it under the terms of the GNU General Public License version 3 as
573-# published by the Free Software Foundation.
574-#
575-# This program is distributed in the hope that it will be useful,
576-# but WITHOUT ANY WARRANTY; without even the implied warranty of
577-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
578-# GNU General Public License for more details.
579-#
580-# You should have received a copy of the GNU General Public License
581-# along with this program. If not, see <http://www.gnu.org/licenses/>.
582-
583-import os
584-import tempfile
585-from unittest.mock import (
586- Mock,
587-)
588-
589-from snapcraft.plugins.ubuntu import UbuntuPlugin
590-
591-from snapcraft.tests import TestCase
592-
593-
594-class TestUbuntu(TestCase):
595-
596- def test_fix_symlinks(self):
597- tempdirObj = tempfile.TemporaryDirectory()
598- self.addCleanup(tempdirObj.cleanup)
599- tempdir = tempdirObj.name
600-
601- os.makedirs(tempdir + '/a')
602- open(tempdir + '/1', mode='w').close()
603-
604- os.symlink('a', tempdir + '/rel-to-a')
605- os.symlink('/a', tempdir + '/abs-to-a')
606- os.symlink('/b', tempdir + '/abs-to-b')
607- os.symlink('1', tempdir + '/rel-to-1')
608- os.symlink('/1', tempdir + '/abs-to-1')
609-
610- options = Mock()
611- options.packages = ['test']
612- ubuntu = UbuntuPlugin('ubuntu', options)
613- ubuntu.fix_symlinks(debdir=tempdir)
614-
615- self.assertEqual(os.readlink(tempdir + '/rel-to-a'), 'a')
616- self.assertEqual(os.readlink(tempdir + '/abs-to-a'), 'a')
617- self.assertEqual(os.readlink(tempdir + '/abs-to-b'), '/b')
618- self.assertEqual(os.readlink(tempdir + '/rel-to-1'), '1')
619- self.assertEqual(os.readlink(tempdir + '/abs-to-1'), '1')
620-
621- def test_recommends_ignored_properly(self):
622- class Options:
623- packages = ['my-excellent-package']
624- ubuntu = UbuntuPlugin('myplug', Options())
625-
626- self.assertTrue('my-excellent-package' in ubuntu.included_packages)
627- self.assertEqual(ubuntu.recommends, None)
628
629=== removed file 'snapcraft/plugins/ubuntu.py'
630--- snapcraft/plugins/ubuntu.py 2015-08-26 08:52:09 +0000
631+++ snapcraft/plugins/ubuntu.py 1970-01-01 00:00:00 +0000
632@@ -1,132 +0,0 @@
633-# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
634-#
635-# Copyright (C) 2015 Canonical Ltd
636-#
637-# This program is free software: you can redistribute it and/or modify
638-# it under the terms of the GNU General Public License version 3 as
639-# published by the Free Software Foundation.
640-#
641-# This program is distributed in the hope that it will be useful,
642-# but WITHOUT ANY WARRANTY; without even the implied warranty of
643-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
644-# GNU General Public License for more details.
645-#
646-# You should have received a copy of the GNU General Public License
647-# along with this program. If not, see <http://www.gnu.org/licenses/>.
648-
649-import itertools
650-import logging
651-import os
652-import subprocess
653-import sys
654-
655-import apt
656-
657-import snapcraft.common
658-
659-
660-logger = logging.getLogger(__name__)
661-
662-
663-class UbuntuPlugin(snapcraft.BasePlugin):
664-
665- def __init__(self, name, options):
666- super().__init__(name, options)
667- self.downloadable_packages = []
668- self.included_packages = []
669- if options.packages:
670- self.included_packages.extend(options.packages)
671- else:
672- # User didn't specify a package, use the part name
673- if name == 'ubuntu':
674- logger.error('Part %s needs either a package option or a name', name)
675- sys.exit(1)
676- self.included_packages.append(name)
677-
678- self.recommends = getattr(options, 'recommends', None)
679-
680- def pull(self):
681- self.downloadable_packages = self.get_all_dep_packages(self.included_packages)
682- return self.download_debs(self.downloadable_packages)
683-
684- def build(self):
685- if not self.downloadable_packages:
686- self.downloadable_packages = self.get_all_dep_packages(self.included_packages)
687- return self.unpack_debs(self.downloadable_packages, self.installdir) \
688- and self.fix_symlinks(debdir=self.installdir)
689-
690- def snap_files(self):
691- return (['*'], ['usr/include', 'lib/*/*.a', 'usr/lib/*/*.a', 'usr/share/doc', 'usr/share/man', 'usr/share/lintian', 'usr/share/doc-base'])
692-
693- def get_all_dep_packages(self, packages):
694- cache = apt.Cache()
695- alldeps = set()
696- manifestdeps = set()
697- skipped = set()
698-
699- with open(os.path.abspath(os.path.join(__file__, '..', 'manifest.txt'))) as f:
700- for line in f:
701- pkg = line.strip()
702- if pkg in cache:
703- manifestdeps.add(pkg)
704-
705- def add_deps(pkgs):
706- for p in pkgs:
707- if p in alldeps:
708- continue
709- if p in manifestdeps and p not in packages:
710- skipped.add(p)
711- continue
712- try:
713- deps = set()
714- candidatePkg = cache[p].candidate
715- deps = candidatePkg.dependencies
716- if self.recommends:
717- deps += candidatePkg.recommends
718- alldeps.add(p)
719- add_deps([x[0].name for x in deps])
720- except:
721- pass
722-
723- add_deps(packages)
724-
725- exit = False
726- for p in packages:
727- if p not in alldeps:
728- exit = True
729- logger.error("Package '%s' not recognized", p)
730- if exit:
731- sys.exit(1)
732-
733- return sorted(alldeps)
734-
735- def download_debs(self, pkgs, debdir=None):
736- debdir = debdir or self.builddir
737- if pkgs:
738- return self.run(['dget'] + pkgs, cwd=debdir, stdout=subprocess.DEVNULL)
739- else:
740- return True
741-
742- def unpack_debs(self, pkgs, targetDir, debdir=None):
743- debdir = debdir or self.builddir
744- for p in pkgs:
745- if not self.run(['dpkg-deb', '--extract', p + '_*.deb', targetDir], cwd=debdir):
746- return False
747- return True
748-
749- def fix_symlinks(self, debdir=None):
750- """Sometimes debs will contain absolute symlinks (e.g. if the relative
751- path would go all the way to root, they just do absolute). We can't
752- have that, so instead clean those absolute symlinks."""
753- debdir = debdir or self.builddir
754- for root, dirs, files in os.walk(debdir):
755- # Symlinks to directories will be in dirs, while symlinks to
756- # non-directories will be in files.
757- for entry in itertools.chain(files, dirs):
758- path = os.path.join(root, entry)
759- if os.path.islink(path) and os.path.isabs(os.readlink(path)):
760- target = os.path.join(debdir, os.readlink(path)[1:])
761- if os.path.exists(target):
762- os.remove(path)
763- os.symlink(os.path.relpath(target, root), path)
764- return True
765
766=== added file 'snapcraft/repo.py'
767--- snapcraft/repo.py 1970-01-01 00:00:00 +0000
768+++ snapcraft/repo.py 2015-09-08 12:03:39 +0000
769@@ -0,0 +1,132 @@
770+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
771+#
772+# Copyright (C) 2015 Canonical Ltd
773+#
774+# This program is free software: you can redistribute it and/or modify
775+# it under the terms of the GNU General Public License version 3 as
776+# published by the Free Software Foundation.
777+#
778+# This program is distributed in the hope that it will be useful,
779+# but WITHOUT ANY WARRANTY; without even the implied warranty of
780+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
781+# GNU General Public License for more details.
782+#
783+# You should have received a copy of the GNU General Public License
784+# along with this program. If not, see <http://www.gnu.org/licenses/>.
785+
786+import apt
787+import glob
788+import itertools
789+import os
790+import subprocess
791+
792+
793+class PackageNotFoundError(Exception):
794+
795+ @property
796+ def message(self):
797+ return 'The Ubuntu package \'%s\' was not found' % self.package_name
798+
799+ def __init__(self, package_name):
800+ self.package_name = package_name
801+
802+
803+class UnpackError(Exception):
804+
805+ @property
806+ def message(self):
807+ return 'Error while provisioning \'%s\'' % self.package_name
808+
809+ def __init__(self, package_name):
810+ self.package_name = package_name
811+
812+
813+class Ubuntu:
814+
815+ def __init__(self, download_dir, recommends=False):
816+ self.apt_cache = apt.Cache()
817+ self.manifest_dep_names = self._manifest_dep_names()
818+ self.recommends = recommends
819+ self.download_dir = download_dir
820+
821+ def get(self, package_names):
822+ # TODO cleanup download_dir for clean gets and unpacks
823+ self.all_dep_names = set()
824+
825+ all_package_names = self._compute_deps(package_names)
826+
827+ for pkg in all_package_names:
828+ self.apt_cache[pkg].candidate.fetch_binary(destdir=self.download_dir)
829+
830+ return all_package_names
831+
832+ def unpack(self, root_dir):
833+ pkgs_abs_path = glob.glob(os.path.join(self.download_dir, '*.deb'))
834+ for pkg in pkgs_abs_path:
835+ # TODO needs elegance and error control
836+ try:
837+ subprocess.check_call(['dpkg-deb', '--extract', pkg, root_dir])
838+ except subprocess.CalledProcessError:
839+ raise UnpackError(pkg)
840+
841+ _fix_symlinks(root_dir)
842+
843+ def _manifest_dep_names(self):
844+ manifest_dep_names = set()
845+
846+ with open(os.path.abspath(os.path.join(__file__, '..', 'manifest.txt'))) as f:
847+ for line in f:
848+ pkg = line.strip()
849+ if pkg in self.apt_cache:
850+ manifest_dep_names.add(pkg)
851+
852+ return manifest_dep_names
853+
854+ def _compute_deps(self, package_names):
855+ self._add_deps(package_names)
856+
857+ for pkg in package_names:
858+ if pkg not in self.all_dep_names:
859+ raise PackageNotFoundError(pkg)
860+
861+ return sorted(self.all_dep_names)
862+
863+ def _add_deps(self, package_names):
864+ def add_deps(packages):
865+ for pkg in packages:
866+ # Remove the :any in packages
867+ # TODO support multiarch
868+ pkg = pkg.rsplit(':', 1)[0]
869+ if pkg in self.all_dep_names:
870+ continue
871+ if pkg in self.manifest_dep_names and pkg not in package_names:
872+ continue
873+ deps = set()
874+ try:
875+ candidate_pkg = self.apt_cache[pkg].candidate
876+ except KeyError:
877+ raise PackageNotFoundError(pkg)
878+ deps = candidate_pkg.dependencies
879+ if self.recommends:
880+ deps += candidate_pkg.recommends
881+ self.all_dep_names.add(pkg)
882+ add_deps([x[0].name for x in deps])
883+ add_deps(package_names)
884+
885+
886+def _fix_symlinks(debdir):
887+ '''
888+ Sometimes debs will contain absolute symlinks (e.g. if the relative
889+ path would go all the way to root, they just do absolute). We can't
890+ have that, so instead clean those absolute symlinks.
891+ '''
892+ for root, dirs, files in os.walk(debdir):
893+ # Symlinks to directories will be in dirs, while symlinks to
894+ # non-directories will be in files.
895+ for entry in itertools.chain(files, dirs):
896+ path = os.path.join(root, entry)
897+ if os.path.islink(path) and os.path.isabs(os.readlink(path)):
898+ target = os.path.join(debdir, os.readlink(path)[1:])
899+ if os.path.exists(target):
900+ os.remove(path)
901+ os.symlink(os.path.relpath(target, root), path)
902
903=== renamed file 'snapcraft/tests/test_ubuntu_plugin.py' => 'snapcraft/tests/test_repo.py'
904--- snapcraft/tests/test_ubuntu_plugin.py 2015-08-05 20:19:47 +0000
905+++ snapcraft/tests/test_repo.py 2015-09-08 12:03:39 +0000
906@@ -14,26 +14,42 @@
907 # You should have received a copy of the GNU General Public License
908 # along with this program. If not, see <http://www.gnu.org/licenses/>.
909
910-import logging
911-
912-import fixtures
913-
914+import os
915+import tempfile
916+
917+from snapcraft import repo
918 from snapcraft import tests
919-from snapcraft.plugins import ubuntu
920-
921-
922-class UbuntuPluginTestCase(tests.TestCase):
923-
924- def test_get_all_dep_packages_with_unrecognized_package(self):
925- fake_logger = fixtures.FakeLogger(level=logging.ERROR)
926- self.useFixture(fake_logger)
927-
928- test_options = type('obj', (object,), {'packages': False, 'recommends': False})
929- plugin = ubuntu.UbuntuPlugin('test_plugin', test_options)
930-
931- with self.assertRaises(SystemExit) as raised:
932- plugin.get_all_dep_packages(['test_package'])
933-
934- self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
935- self.assertEqual(
936- "Package 'test_package' not recognized\n", fake_logger.output)
937+
938+
939+class UbuntuTestCase(tests.TestCase):
940+
941+ def test_unrecognized_package_raises_exception(self):
942+ ubuntu = repo.Ubuntu('download_dir')
943+
944+ with self.assertRaises(repo.PackageNotFoundError) as raised:
945+ ubuntu.get(['test_package'])
946+
947+ expected_message = 'The Ubuntu package \'test_package\' was not found'
948+ self.assertEqual(raised.exception.message, expected_message)
949+
950+ def test_fix_symlinks(self):
951+ tempdirObj = tempfile.TemporaryDirectory()
952+ self.addCleanup(tempdirObj.cleanup)
953+ tempdir = tempdirObj.name
954+
955+ os.makedirs(tempdir + '/a')
956+ open(tempdir + '/1', mode='w').close()
957+
958+ os.symlink('a', tempdir + '/rel-to-a')
959+ os.symlink('/a', tempdir + '/abs-to-a')
960+ os.symlink('/b', tempdir + '/abs-to-b')
961+ os.symlink('1', tempdir + '/rel-to-1')
962+ os.symlink('/1', tempdir + '/abs-to-1')
963+
964+ repo._fix_symlinks(debdir=tempdir)
965+
966+ self.assertEqual(os.readlink(tempdir + '/rel-to-a'), 'a')
967+ self.assertEqual(os.readlink(tempdir + '/abs-to-a'), 'a')
968+ self.assertEqual(os.readlink(tempdir + '/abs-to-b'), '/b')
969+ self.assertEqual(os.readlink(tempdir + '/rel-to-1'), '1')
970+ self.assertEqual(os.readlink(tempdir + '/abs-to-1'), '1')
971
972=== modified file 'snapcraft/tests/test_yaml.py'
973--- snapcraft/tests/test_yaml.py 2015-08-27 22:09:55 +0000
974+++ snapcraft/tests/test_yaml.py 2015-09-08 12:03:39 +0000
975@@ -57,12 +57,13 @@
976 icon: my-icon.png
977
978 parts:
979- ubuntu:
980- packages: [fswebcam]
981+ part1:
982+ plugin: go
983+ stage-packages: [fswebcam]
984 """)
985 snapcraft.yaml.Config()
986- mock_loadPlugin.assert_called_with("ubuntu", "ubuntu", {
987- "packages": ["fswebcam"],
988+ mock_loadPlugin.assert_called_with("part1", "go", {
989+ "stage-packages": ["fswebcam"],
990 })
991
992 def test_config_raises_on_missing_snapcraft_yaml(self):
993@@ -92,10 +93,10 @@
994
995 parts:
996 p1:
997- plugin: ubuntu
998+ plugin: go
999 after: [p2]
1000 p2:
1001- plugin: ubuntu
1002+ plugin: go
1003 after: [p1]
1004 """)
1005 with self.assertRaises(SystemExit) as raised:
1006@@ -117,8 +118,9 @@
1007 icon: my-icon.png
1008
1009 parts:
1010- ubuntu:
1011- packages: [fswebcam]
1012+ part1:
1013+ plugin: go
1014+ stage-packages: [fswebcam]
1015 """)
1016 with self.assertRaises(SystemExit) as raised:
1017 snapcraft.yaml.Config()
1018@@ -141,8 +143,9 @@
1019 icon: my-icon.png
1020
1021 parts:
1022- ubuntu:
1023- packages: [fswebcam]
1024+ part1:
1025+ plugin: go
1026+ stage-packages: [fswebcam]
1027 """)
1028 with self.assertRaises(SystemExit) as raised:
1029 snapcraft.yaml.Config()
1030@@ -165,8 +168,9 @@
1031 icon: my-icon.png
1032
1033 parts:
1034- ubuntu:
1035- packages: [fswebcam]
1036+ part1:
1037+ plugin: go
1038+ stage-packages: [fswebcam]
1039 """)
1040 with self.assertRaises(SystemExit) as raised:
1041 snapcraft.yaml.Config()
1042@@ -188,8 +192,9 @@
1043 icon: my-icon.png
1044
1045 parts:
1046- ubuntu:
1047- packages: [fswebcam]
1048+ part1:
1049+ plugin: go
1050+ stage-packages: [fswebcam]
1051 """)
1052 with self.assertRaises(SystemExit) as raised:
1053 snapcraft.yaml.Config()
1054@@ -220,7 +225,7 @@
1055 'icon': 'my-icon.png',
1056 'parts': {
1057 'part1': {
1058- 'type': 'project',
1059+ 'plugin': 'project',
1060 },
1061 },
1062 }

Subscribers

People subscribed via source and target branches