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

Proposed by Sergio Schvezov
Status: Merged
Approved by: Sergio Schvezov
Approved revision: 249
Merged at revision: 236
Proposed branch: lp:~sergiusens/snapcraft/1500902
Merge into: lp:~snappy-dev/snapcraft/core
Diff against target: 1329 lines (+398/-381)
33 files modified
plugins/ant.yaml (+0/-13)
plugins/autotools.yaml (+0/-12)
plugins/cmake.yaml (+0/-12)
plugins/copy.yaml (+0/-6)
plugins/go.yaml (+0/-10)
plugins/jdk.yaml (+0/-2)
plugins/make.yaml (+0/-10)
plugins/maven.yaml (+0/-13)
plugins/python2.yaml (+0/-11)
plugins/python3.yaml (+0/-11)
plugins/readline.yaml (+0/-3)
plugins/scons.yaml (+0/-9)
plugins/tar-content.yaml (+0/-6)
setup.py (+0/-2)
snapcraft/__init__.py (+47/-7)
snapcraft/cmds.py (+7/-8)
snapcraft/plugin.py (+106/-110)
snapcraft/plugins/ant.py (+15/-5)
snapcraft/plugins/autotools.py (+21/-2)
snapcraft/plugins/cmake.py (+21/-6)
snapcraft/plugins/copy.py (+13/-0)
snapcraft/plugins/go.py (+15/-0)
snapcraft/plugins/jdk.py (+3/-3)
snapcraft/plugins/make.py (+4/-0)
snapcraft/plugins/maven.py (+9/-1)
snapcraft/plugins/python2.py (+19/-12)
snapcraft/plugins/python3.py (+19/-12)
snapcraft/plugins/qml.py (+41/-35)
snapcraft/plugins/scons.py (+19/-5)
snapcraft/plugins/tar_content.py (+13/-0)
snapcraft/tests/test_cmds.py (+3/-3)
snapcraft/tests/test_plugin.py (+18/-29)
snapcraft/yaml.py (+5/-23)
To merge this branch: bzr merge lp:~sergiusens/snapcraft/1500902
Reviewer Review Type Date Requested Status
Leo Arias (community) Approve
John Lenton (community) Approve
Review via email: mp+273444@code.launchpad.net

Commit message

Plugin yaml's are obsolete

To post a comment you must log in.
Revision history for this message
Leo Arias (elopio) wrote :

A couple of style comments inline.

This change makes sense, because now we don't split the plugins into a python and a yaml file. But I think we need to spend some time cleaning and documenting the api of the parent base plugin. Clearly mark things that are internals, constants and things that are to be extended by children. And write nice sphinxed docs.

review: Needs Fixing
lp:~sergiusens/snapcraft/1500902 updated
235. By Sergio Schvezov

Making stage-packages and build-packages regular attributes while polishing the phase in the lifecycle where it is handled

236. By Sergio Schvezov

Merging trunk

237. By Sergio Schvezov

Fix issues when using global dictionaries and plugin code polish

238. By Sergio Schvezov

The name belongs to the part, the other thing is just the plugin to use to handle it

239. By Sergio Schvezov

getattr--

240. By Sergio Schvezov

contextlib++

241. By Sergio Schvezov

More name changes

242. By Sergio Schvezov

Remove more PLUGIN_BUILD_PACKAGES refs

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

OK, except for the docs, most of this the comments have been addressed.

lp:~sergiusens/snapcraft/1500902 updated
243. By Sergio Schvezov

options is here

244. By Sergio Schvezov

import jdk for maven plugin

245. By Sergio Schvezov

missing options for scons_options

246. By Sergio Schvezov

Remove _PLUGIN_BUILD_PACKAGES from CMakePlugin

247. By Sergio Schvezov

jsonschema support

Revision history for this message
John Lenton (chipaca) :
review: Approve
lp:~sergiusens/snapcraft/1500902 updated
248. By Sergio Schvezov

Removing plugins install logic from setup.py

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

This cleans up almost everything I didn't like. Let's merge!

review: Approve
lp:~sergiusens/snapcraft/1500902 updated
249. By Sergio Schvezov

Build packages for plugins

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed directory 'plugins'
2=== removed file 'plugins/ant.yaml'
3--- plugins/ant.yaml 2015-10-01 08:54:15 +0000
4+++ plugins/ant.yaml 1970-01-01 00:00:00 +0000
5@@ -1,13 +0,0 @@
6-requires:
7- - jdk
8-options:
9- source:
10- required: true
11- source-type:
12- source-tag:
13- source-branch:
14- stage-packages:
15- snap:
16- stage:
17-build-packages:
18- - ant
19
20=== removed file 'plugins/autotools.yaml'
21--- plugins/autotools.yaml 2015-10-01 08:54:15 +0000
22+++ plugins/autotools.yaml 1970-01-01 00:00:00 +0000
23@@ -1,12 +0,0 @@
24-build-packages: [autoconf, automake, autopoint]
25-options:
26- source:
27- required: true
28- source-type:
29- source-tag:
30- source-branch:
31- configflags:
32- required: false
33- stage-packages:
34- snap:
35- stage:
36
37=== removed file 'plugins/cmake.yaml'
38--- plugins/cmake.yaml 2015-10-01 08:54:15 +0000
39+++ plugins/cmake.yaml 1970-01-01 00:00:00 +0000
40@@ -1,12 +0,0 @@
41-build-packages: [cmake]
42-options:
43- source:
44- required: true
45- source-type:
46- source-tag:
47- source-branch:
48- configflags:
49- required: false
50- stage-packages:
51- snap:
52- stage:
53
54=== removed file 'plugins/copy.yaml'
55--- plugins/copy.yaml 2015-09-08 18:06:03 +0000
56+++ plugins/copy.yaml 1970-01-01 00:00:00 +0000
57@@ -1,6 +0,0 @@
58-options:
59- files:
60- required: true
61- stage-packages:
62- snap:
63- stage:
64
65=== removed file 'plugins/go.yaml'
66--- plugins/go.yaml 2015-10-01 08:54:15 +0000
67+++ plugins/go.yaml 1970-01-01 00:00:00 +0000
68@@ -1,10 +0,0 @@
69-build-packages:
70- - golang-go
71-options:
72- source:
73- required: true
74- configflags:
75- required: false
76- stage-packages:
77- snap:
78- stage:
79
80=== removed file 'plugins/jdk.yaml'
81--- plugins/jdk.yaml 2015-10-08 18:08:29 +0000
82+++ plugins/jdk.yaml 1970-01-01 00:00:00 +0000
83@@ -1,2 +0,0 @@
84-build-packages:
85- - ca-certificates-java
86
87=== removed file 'plugins/make.yaml'
88--- plugins/make.yaml 2015-10-01 08:54:15 +0000
89+++ plugins/make.yaml 1970-01-01 00:00:00 +0000
90@@ -1,10 +0,0 @@
91-build-packages: [make]
92-options:
93- source:
94- required: true
95- source-type:
96- source-tag:
97- source-branch:
98- stage-packages:
99- snap:
100- stage:
101
102=== removed file 'plugins/maven.yaml'
103--- plugins/maven.yaml 2015-10-01 08:54:15 +0000
104+++ plugins/maven.yaml 1970-01-01 00:00:00 +0000
105@@ -1,13 +0,0 @@
106-build-packages:
107- - maven
108-requires:
109- - jdk
110-options:
111- source:
112- required: true
113- source-type:
114- source-tag:
115- source-branch:
116- stage-packages:
117- snap:
118- stage:
119
120=== removed file 'plugins/python2.yaml'
121--- plugins/python2.yaml 2015-10-01 08:54:15 +0000
122+++ plugins/python2.yaml 1970-01-01 00:00:00 +0000
123@@ -1,11 +0,0 @@
124-options:
125- requirements:
126- required: false
127- source:
128- required: false
129- source-type:
130- source-tag:
131- source-branch:
132- stage-packages:
133- snap:
134- stage:
135
136=== removed file 'plugins/python3.yaml'
137--- plugins/python3.yaml 2015-10-01 08:54:15 +0000
138+++ plugins/python3.yaml 1970-01-01 00:00:00 +0000
139@@ -1,11 +0,0 @@
140-options:
141- requirements:
142- required: false
143- source:
144- required: false
145- source-type:
146- source-tag:
147- source-branch:
148- stage-packages:
149- snap:
150- stage:
151
152=== removed file 'plugins/qml.yaml'
153=== removed file 'plugins/readline.yaml'
154--- plugins/readline.yaml 2015-10-01 08:54:15 +0000
155+++ plugins/readline.yaml 1970-01-01 00:00:00 +0000
156@@ -1,3 +0,0 @@
157-source: git://git.sv.gnu.org/readline.git
158-requires:
159- - autotools
160
161=== removed file 'plugins/scons.yaml'
162--- plugins/scons.yaml 2015-10-01 08:54:15 +0000
163+++ plugins/scons.yaml 1970-01-01 00:00:00 +0000
164@@ -1,9 +0,0 @@
165-build-packages:
166- - scons
167-options:
168- source:
169- required: true
170- scons-options:
171- source-type:
172- source-tag:
173- source-branch:
174
175=== removed file 'plugins/tar-content.yaml'
176--- plugins/tar-content.yaml 2015-09-22 03:08:07 +0000
177+++ plugins/tar-content.yaml 1970-01-01 00:00:00 +0000
178@@ -1,6 +0,0 @@
179-options:
180- source:
181- required: true
182- stage-packages:
183- snap:
184- stage:
185
186=== modified file 'setup.py'
187--- setup.py 2015-10-02 09:13:00 +0000
188+++ setup.py 2015-10-13 15:27:09 +0000
189@@ -37,8 +37,6 @@
190 package_data={'snapcraft': ['manifest.txt']},
191 scripts=['bin/snapcraft'],
192 data_files=[
193- ('share/snapcraft/plugins',
194- ['plugins/' + x for x in os.listdir('plugins')]),
195 ('share/snapcraft/schema',
196 ['schema/' + x for x in os.listdir('schema')]),
197 ],
198
199=== modified file 'snapcraft/__init__.py'
200--- snapcraft/__init__.py 2015-10-02 09:13:00 +0000
201+++ snapcraft/__init__.py 2015-10-13 15:27:09 +0000
202@@ -14,6 +14,7 @@
203 # You should have received a copy of the GNU General Public License
204 # along with this program. If not, see <http://www.gnu.org/licenses/>.
205
206+import contextlib
207 import logging
208 import os
209 import re
210@@ -28,9 +29,41 @@
211
212 class BasePlugin:
213
214- @property
215- def PLUGIN_STAGE_PACKAGES(self):
216- return getattr(self, '_PLUGIN_STAGE_PACKAGES', [])
217+ @classmethod
218+ def schema(cls):
219+ '''
220+ Returns a json-schema for the plugin's properties as a dictionary.
221+ Of importance to plugin authors is the 'properties' keyword and
222+ optionally the 'requires' keyword with a list of required
223+ 'properties'.
224+
225+ By default the the properties will be that of a standard VCS, override
226+ in custom implementations if required.
227+ '''
228+ return {
229+ '$schema': 'http://json-schema.org/draft-04/schema#',
230+ 'type': 'object',
231+ 'properties': {
232+ 'source': {
233+ 'type': 'string',
234+ },
235+ 'source-type': {
236+ 'type': 'string',
237+ 'default': '',
238+ },
239+ 'source-branch': {
240+ 'type': 'string',
241+ 'default': '',
242+ },
243+ 'source-tag': {
244+ 'type:': 'string',
245+ 'default': '',
246+ },
247+ },
248+ 'required': [
249+ 'source',
250+ ]
251+ }
252
253 @property
254 def PLUGIN_STAGE_SOURCES(self):
255@@ -38,6 +71,14 @@
256
257 def __init__(self, name, options):
258 self.name = name
259+ self.build_packages = []
260+ self.stage_packages = []
261+
262+ with contextlib.suppress(AttributeError):
263+ self.stage_packages = options.stage_packages
264+ with contextlib.suppress(AttributeError):
265+ self.build_packages = options.build_packages
266+
267 self.options = options
268 self.partdir = os.path.join(os.getcwd(), "parts", self.name)
269 self.sourcedir = os.path.join(os.getcwd(), "parts", self.name, "src")
270@@ -121,11 +162,10 @@
271 os.makedirs(d, exist_ok=True)
272
273 def setup_stage_packages(self):
274- part_stage_packages = getattr(self.options, 'stage_packages', []) or []
275- if self.PLUGIN_STAGE_PACKAGES or part_stage_packages:
276+ if self.stage_packages:
277 ubuntu = snapcraft.repo.Ubuntu(self.ubuntudir,
278 sources=self.PLUGIN_STAGE_SOURCES)
279- ubuntu.get(self.PLUGIN_STAGE_PACKAGES + part_stage_packages)
280+ ubuntu.get(self.stage_packages)
281 ubuntu.unpack(self.installdir)
282 self._fixup(self.installdir)
283
284@@ -143,7 +183,7 @@
285
286
287 def _get_source_handler(source_type, source):
288- if source_type is None:
289+ if not source_type:
290 source_type = _get_source_type_from_uri(source)
291
292 if source_type == 'bzr':
293
294=== modified file 'snapcraft/cmds.py'
295--- snapcraft/cmds.py 2015-10-05 16:16:23 +0000
296+++ snapcraft/cmds.py 2015-10-13 15:27:09 +0000
297@@ -54,9 +54,8 @@
298 if args.part:
299 yaml += 'parts:\n'
300 for part_name in args.part:
301- part = snapcraft.plugin.load_plugin(part_name, part_name,
302- load_code=False)
303- yaml += ' ' + part.names()[0] + ':\n'
304+ part = snapcraft.plugin.load_plugin(part_name, part_name)
305+ yaml += ' ' + part.name + ':\n'
306 for opt in part.config.get('options', []):
307 if part.config['options'][opt].get('required', False):
308 yaml += ' ' + opt + ':\n'
309@@ -241,7 +240,7 @@
310 config = _load_config()
311
312 for part in config.all_parts:
313- logger.info('Cleaning up for part %r', part.names()[0])
314+ logger.info('Cleaning up for part %r', part.name)
315 if os.path.exists(part.partdir):
316 shutil.rmtree(part.partdir)
317
318@@ -287,14 +286,14 @@
319 'paths in common which have different '
320 'contents:\n %s',
321 other_part_name,
322- part.names()[0],
323+ part.name,
324 '\n '.join(sorted(conflict_files)))
325
326 return False
327
328 # And add our files to the list
329- parts_files[part.names()[0]] = {'files': part_files,
330- 'installdir': part.installdir}
331+ parts_files[part.name] = {'files': part_files,
332+ 'installdir': part.installdir}
333
334 return True
335
336@@ -336,7 +335,7 @@
337 force = forceAll or cmd == forceCommand
338
339 if not getattr(part, cmd)(force=force):
340- logger.error('Failed doing %s for %s!', cmd, part.names()[0])
341+ logger.error('Failed doing %s for %s!', cmd, part.name)
342 sys.exit(1)
343
344
345
346=== modified file 'snapcraft/plugin.py'
347--- snapcraft/plugin.py 2015-10-05 16:56:10 +0000
348+++ snapcraft/plugin.py 2015-10-13 15:27:09 +0000
349@@ -14,13 +14,14 @@
350 # You should have received a copy of the GNU General Public License
351 # along with this program. If not, see <http://www.gnu.org/licenses/>.
352
353+import contextlib
354 import glob
355 import importlib
356+import jsonschema
357 import logging
358 import os
359 import sys
360 import shutil
361-import yaml
362
363 import snapcraft
364 from snapcraft import common
365@@ -30,15 +31,6 @@
366 logger = logging.getLogger(__name__)
367
368
369-_BUILTIN_OPTIONS = {
370- 'filesets': {},
371- 'snap': [],
372- 'stage': [],
373- 'stage-packages': [],
374- 'organize': {}
375-}
376-
377-
378 def _local_plugindir():
379 return os.path.abspath(os.path.join('parts', 'plugins'))
380
381@@ -49,14 +41,16 @@
382
383 class PluginHandler:
384
385- def __init__(self, name, part_name, properties, load_code=True,
386- load_config=True):
387+ @property
388+ def name(self):
389+ return self._name
390+
391+ def __init__(self, plugin_name, part_name, properties):
392 self.valid = False
393 self.code = None
394 self.config = {}
395- self.part_names = []
396+ self._name = part_name
397 self.deps = []
398- self.plugin_name = name
399
400 parts_dir = common.get_partsdir()
401 self.partdir = os.path.join(parts_dir, part_name)
402@@ -69,78 +63,46 @@
403 self.statefile = os.path.join(parts_dir, part_name, 'state')
404
405 try:
406- if load_config:
407- self._load_config(name)
408- if load_code:
409- self._load_code(name, part_name, properties)
410+ self._load_code(plugin_name, properties)
411 # only set to valid if it loads without PluginError
412- self.part_names.append(part_name)
413 self.valid = True
414 except PluginError as e:
415 logger.error(str(e))
416 return
417-
418- def _load_config(self, name):
419- config_path = os.path.join(common.get_plugindir(), name + ".yaml")
420- if not os.path.exists(config_path):
421- config_path = os.path.join(_local_plugindir(), name + ".yaml")
422- if not os.path.exists(config_path):
423- raise PluginError('Unknown plugin: {}'.format(name))
424- with open(config_path, 'r') as fp:
425- self.config = yaml.load(fp) or {}
426-
427- def _make_options(self, name, properties):
428- class Options():
429- pass
430- options = Options()
431-
432- plugin_options = self.config.get('options', {})
433- # Let's append some mandatory options, but not .update() to not lose
434- # original content
435- for key in _BUILTIN_OPTIONS:
436- if key not in plugin_options:
437- plugin_options[key] = _BUILTIN_OPTIONS[key]
438-
439- for opt in plugin_options:
440- attrname = opt.replace('-', '_')
441- opt_parameters = plugin_options[opt] or {}
442- if opt in properties:
443- setattr(options, attrname, properties[opt])
444- else:
445- if opt_parameters.get('required', False):
446- raise PluginError('Required field {} missing on part {}'.
447- format(opt, name))
448- setattr(options, attrname, None)
449-
450- return options
451-
452- def _load_code(self, name, part_name, properties):
453- options = self._make_options(name, properties)
454- module_name = name.replace('-', '_')
455-
456- try:
457- module = importlib.import_module('snapcraft.plugins.' +
458- module_name)
459- except ImportError:
460- module = None
461-
462- if not module:
463- logger.info('Searching for local plugin for %s', name)
464- sys.path = [_local_plugindir()] + sys.path
465- module = importlib.import_module(module_name)
466- sys.path.pop(0)
467-
468- for prop_name in dir(module):
469- prop = getattr(module, prop_name)
470- if issubclass(prop, snapcraft.BasePlugin):
471- self.code = prop(part_name, options)
472- break
473+ except jsonschema.ValidationError as e:
474+ logger.error('Issues while loading properties for '
475+ '{}: {}'.format(part_name, e.message))
476+ return
477+
478+ def _load_code(self, plugin_name, properties):
479+ module_name = plugin_name.replace('-', '_')
480+ module = None
481+
482+ with contextlib.suppress(ImportError):
483+ module = _load_local('x-{}'.format(plugin_name))
484+ logger.info('Loaded local plugin for %s', plugin_name)
485+
486+ if not module:
487+ with contextlib.suppress(ImportError):
488+ module = importlib.import_module(
489+ 'snapcraft.plugins.{}'.format(module_name))
490+
491+ if not module:
492+ logger.info('Searching for local plugin for %s', plugin_name)
493+ with contextlib.suppress(ImportError):
494+ module = _load_local(module_name)
495+ if not module:
496+ raise PluginError('Unknown plugin: {}'.format(plugin_name))
497+
498+ plugin = _get_plugin(module)
499+ options = _make_options(properties, plugin.schema())
500+ self.code = plugin(self.name, options)
501
502 def __str__(self):
503- return self.part_names[0]
504+ return self.name
505
506 def __repr__(self):
507- return self.part_names[0]
508+ return self.name
509
510 def makedirs(self):
511 dirs = [
512@@ -153,11 +115,8 @@
513 def is_valid(self):
514 return self.valid
515
516- def names(self):
517- return self.part_names
518-
519 def notify_stage(self, stage, hint=''):
520- logger.info(stage + " " + self.part_names[0] + hint)
521+ logger.info('%s %s %s', stage, self.name, hint)
522
523 def is_dirty(self, stage):
524 try:
525@@ -183,23 +142,16 @@
526 return True
527 self.makedirs()
528
529- run_setup_stage_packages = self.code and \
530- hasattr(self.code, 'setup_stage_packages')
531- run_pull = self.code and hasattr(self.code, 'pull')
532-
533- if run_setup_stage_packages or run_pull:
534- self.notify_stage("Pulling")
535-
536- if run_setup_stage_packages:
537- try:
538- self.code.setup_stage_packages()
539- except repo.PackageNotFoundError as e:
540- logger.error(e.message)
541- return False
542-
543- if run_pull:
544- if not getattr(self.code, 'pull')():
545- return False
546+ self.notify_stage("Pulling")
547+
548+ try:
549+ self.code.setup_stage_packages()
550+ except repo.PackageNotFoundError as e:
551+ logger.error(e.message)
552+ return False
553+
554+ if not self.code.pull():
555+ return False
556
557 self.mark_done('pull')
558 return True
559@@ -208,10 +160,9 @@
560 if not self.should_stage_run('build', force):
561 return True
562 self.makedirs()
563- if self.code and hasattr(self.code, 'build'):
564- self.notify_stage("Building")
565- if not getattr(self.code, 'build')():
566- return False
567+ self.notify_stage("Building")
568+ if not self.code.build():
569+ return False
570
571 self.mark_done('build')
572 return True
573@@ -284,14 +235,59 @@
574 return True
575
576 def env(self, root):
577- if self.code and hasattr(self.code, 'env'):
578- return getattr(self.code, 'env')(root)
579- return []
580-
581-
582-def load_plugin(part_name, plugin_name, properties={}, load_code=True):
583- part = PluginHandler(plugin_name, part_name, properties,
584- load_code=load_code)
585+ return self.code.env(root)
586+
587+
588+def _builtin_options():
589+ return {
590+ 'filesets': {},
591+ 'snap': [],
592+ 'stage': [],
593+ 'stage-packages': [],
594+ 'build-packages': [],
595+ 'organize': {}
596+ }
597+
598+
599+def _make_options(properties, schema):
600+ class Options():
601+ pass
602+ options = Options()
603+
604+ # Built in options are already validated
605+ builtin_options = _builtin_options()
606+ for key in builtin_options:
607+ value = properties.pop(key, builtin_options[key])
608+ setattr(options, key.replace('-', '_'), value)
609+
610+ jsonschema.validate(properties, schema)
611+
612+ schema_properties = schema.get('properties', {})
613+ for key in schema_properties:
614+ attr_name = key.replace('-', '_')
615+ default_value = schema_properties[key].get('default')
616+ attr_value = properties.get(key, default_value)
617+ setattr(options, attr_name, attr_value)
618+
619+ return options
620+
621+
622+def _get_plugin(module):
623+ for attr in vars(module).values():
624+ if isinstance(attr, type) and issubclass(attr, snapcraft.BasePlugin):
625+ return attr
626+
627+
628+def _load_local(module_name):
629+ sys.path = [_local_plugindir()] + sys.path
630+ module = importlib.import_module(module_name)
631+ sys.path.pop(0)
632+
633+ return module
634+
635+
636+def load_plugin(part_name, plugin_name, properties={}):
637+ part = PluginHandler(plugin_name, part_name, properties)
638 if not part.is_valid():
639 logger.error('Could not load part %s', plugin_name)
640 sys.exit(1)
641
642=== modified file 'snapcraft/plugins/ant.py'
643--- snapcraft/plugins/ant.py 2015-10-02 09:13:00 +0000
644+++ snapcraft/plugins/ant.py 2015-10-13 15:27:09 +0000
645@@ -21,17 +21,24 @@
646
647 import snapcraft
648 import snapcraft.common
649+import snapcraft.plugins.jdk
650
651
652 logger = logging.getLogger(__name__)
653
654
655-class AntPlugin(snapcraft.BasePlugin):
656+class AntPlugin(snapcraft.plugins.jdk.JdkPlugin):
657+
658+ def __init__(self, name, options):
659+ super().__init__(name, options)
660+ self.build_packages.append('ant')
661
662 def pull(self):
663+ super().pull()
664 return self.handle_source_options()
665
666 def build(self):
667+ super().build()
668 if not self.run(['ant']):
669 return False
670 files = glob.glob(os.path.join(self.builddir, 'target', '*.jar'))
671@@ -44,8 +51,11 @@
672 self.run(['cp', '-a'] + files + [jardir])
673
674 def env(self, root):
675+ env = super().env(root)
676 jars = glob.glob(os.path.join(self.installdir, 'jar', '*.jar'))
677- if not jars:
678- return []
679- jars = [os.path.join(root, 'jar', os.path.basename(x)) for x in jars]
680- return ['CLASSPATH=%s:$CLASSPATH' % ':'.join(jars)]
681+ if jars:
682+ jars = [os.path.join(root, 'jar',
683+ os.path.basename(x)) for x in jars]
684+ env.extend(
685+ ['CLASSPATH=%s:$CLASSPATH' % ':'.join(jars)])
686+ return env
687
688=== modified file 'snapcraft/plugins/autotools.py'
689--- snapcraft/plugins/autotools.py 2015-10-02 09:13:00 +0000
690+++ snapcraft/plugins/autotools.py 2015-10-13 15:27:09 +0000
691@@ -19,10 +19,29 @@
692
693
694 class AutotoolsPlugin(MakePlugin):
695+
696+ @classmethod
697+ def schema(cls):
698+ schema = super().schema()
699+ schema['properties']['configflags'] = {
700+ 'type': 'array',
701+ 'minitems': 1,
702+ 'uniqueItems': True,
703+ 'items': {
704+ 'type': 'string',
705+ },
706+ 'default': [],
707+ }
708+
709+ return schema
710+
711 def __init__(self, name, options):
712 super().__init__(name, options)
713- if self.options.configflags is None:
714- self.options.configflags = []
715+ self.build_packages.extend([
716+ 'autoconf',
717+ 'automake',
718+ 'autopoint',
719+ ])
720
721 def build(self):
722 if not os.path.exists(os.path.join(self.builddir, "configure")):
723
724=== modified file 'snapcraft/plugins/cmake.py'
725--- snapcraft/plugins/cmake.py 2015-10-02 09:13:00 +0000
726+++ snapcraft/plugins/cmake.py 2015-10-13 15:27:09 +0000
727@@ -14,14 +14,29 @@
728 # You should have received a copy of the GNU General Public License
729 # along with this program. If not, see <http://www.gnu.org/licenses/>.
730
731-from snapcraft.plugins.make import MakePlugin
732-
733-
734-class CMakePlugin(MakePlugin):
735+import snapcraft.plugins.make
736+
737+
738+class CMakePlugin(snapcraft.plugins.make.MakePlugin):
739+
740+ @classmethod
741+ def schema(cls):
742+ schema = super().schema()
743+ schema['properties']['configflags'] = {
744+ 'type': 'array',
745+ 'minitems': 1,
746+ 'uniqueItems': True,
747+ 'items': {
748+ 'type': 'string',
749+ },
750+ 'default': [],
751+ }
752+
753+ return schema
754+
755 def __init__(self, name, options):
756 super().__init__(name, options)
757- if self.options.configflags is None:
758- self.options.configflags = []
759+ self.build_packages.append('cmake')
760
761 def build(self):
762 return self.run(['cmake', '.', '-DCMAKE_INSTALL_PREFIX='] +
763
764=== modified file 'snapcraft/plugins/copy.py'
765--- snapcraft/plugins/copy.py 2015-10-02 09:13:00 +0000
766+++ snapcraft/plugins/copy.py 2015-10-13 15:27:09 +0000
767@@ -25,6 +25,19 @@
768
769 class CopyPlugin(snapcraft.BasePlugin):
770
771+ @classmethod
772+ def schema(cls):
773+ return {
774+ 'properties': {
775+ 'files': {
776+ 'type': 'object',
777+ },
778+ },
779+ 'required': [
780+ 'files',
781+ ]
782+ }
783+
784 def build(self):
785 res = True
786 for src in sorted(self.options.files):
787
788=== modified file 'snapcraft/plugins/go.py'
789--- snapcraft/plugins/go.py 2015-10-02 09:13:00 +0000
790+++ snapcraft/plugins/go.py 2015-10-13 15:27:09 +0000
791@@ -20,8 +20,23 @@
792
793 class GoPlugin(snapcraft.BasePlugin):
794
795+ @classmethod
796+ def schema(cls):
797+ return {
798+ 'properties': {
799+ 'source': {
800+ 'type': 'string',
801+ },
802+ },
803+ 'required': [
804+ 'source',
805+ ]
806+ }
807+
808 def __init__(self, name, options):
809 super().__init__(name, options)
810+ self.build_packages.append('golang-go')
811+
812 if self.options.source.startswith("lp:"):
813 self.fullname = self.options.source.split(":~")[1]
814 else:
815
816=== modified file 'snapcraft/plugins/jdk.py'
817--- snapcraft/plugins/jdk.py 2015-09-09 19:41:36 +0000
818+++ snapcraft/plugins/jdk.py 2015-10-13 15:27:09 +0000
819@@ -19,9 +19,9 @@
820
821 class JdkPlugin(snapcraft.BasePlugin):
822
823- _PLUGIN_STAGE_PACKAGES = [
824- 'default-jdk',
825- ]
826+ def __init__(self, name, options):
827+ super().__init__(name, options)
828+ self.stage_packages.append('default-jdk')
829
830 def env(self, root):
831 return ['JAVA_HOME=%s/usr/lib/jvm/default-java' % root,
832
833=== modified file 'snapcraft/plugins/make.py'
834--- snapcraft/plugins/make.py 2015-10-01 08:54:15 +0000
835+++ snapcraft/plugins/make.py 2015-10-13 15:27:09 +0000
836@@ -19,6 +19,10 @@
837
838 class MakePlugin(snapcraft.BasePlugin):
839
840+ def __init__(self, name, options):
841+ super().__init__(name, options)
842+ self.build_packages.append('make')
843+
844 def pull(self):
845 return self.handle_source_options()
846
847
848=== modified file 'snapcraft/plugins/maven.py'
849--- snapcraft/plugins/maven.py 2015-10-02 09:13:00 +0000
850+++ snapcraft/plugins/maven.py 2015-10-13 15:27:09 +0000
851@@ -20,17 +20,25 @@
852
853 import snapcraft
854 import snapcraft.common
855+import snapcraft.plugins.jdk
856
857
858 logger = logging.getLogger(__name__)
859
860
861-class MavenPlugin(snapcraft.BasePlugin):
862+class MavenPlugin(snapcraft.plugins.jdk.JdkPlugin):
863+
864+ def __init__(self, name, options):
865+ super().__init__(name, options)
866+ self.build_packages.append('maven')
867
868 def pull(self):
869+ super().pull()
870 return self.handle_source_options()
871
872 def build(self):
873+ super().build()
874+
875 if not self.run(['mvn', 'package']):
876 return False
877 jarfiles = glob.glob(os.path.join(self.builddir, 'target', '*.jar'))
878
879=== modified file 'snapcraft/plugins/python2.py'
880--- snapcraft/plugins/python2.py 2015-10-02 09:13:00 +0000
881+++ snapcraft/plugins/python2.py 2015-10-13 15:27:09 +0000
882@@ -22,23 +22,30 @@
883
884 class Python2Plugin(snapcraft.BasePlugin):
885
886- _PLUGIN_STAGE_PACKAGES = [
887- 'python-dev',
888- 'python-pkg-resources',
889- 'python-setuptools',
890- ]
891+ @classmethod
892+ def schema(cls):
893+ schema = super().schema()
894+ schema['properties']['requirements'] = {
895+ 'type': 'string',
896+ }
897+ schema.pop('required')
898+
899+ return schema
900
901 def __init__(self, name, options):
902 super().__init__(name, options)
903- self.requirements = options.requirements
904- self.source = options.source
905+ self.stage_packages.extend([
906+ 'python-dev',
907+ 'python-pkg-resources',
908+ 'python-setuptools',
909+ ])
910
911 def env(self, root):
912 return ["PYTHONPATH=%s" % os.path.join(
913 root, 'usr', 'lib', self.python_version, 'dist-packages')]
914
915 def pull(self):
916- if self.source and not self.handle_source_options():
917+ if self.options.source and not self.handle_source_options():
918 return False
919
920 return self._pip()
921@@ -48,10 +55,10 @@
922 if os.listdir(self.sourcedir):
923 setup = os.path.join(self.sourcedir, 'setup.py')
924
925- if self.requirements:
926- requirements = os.path.join(os.getcwd(), self.requirements)
927+ if self.options.requirements:
928+ requirements = os.path.join(os.getcwd(), self.options.requirements)
929
930- if not os.path.exists(setup) and not self.requirements:
931+ if not os.path.exists(setup) and not self.options.requirements:
932 return True
933
934 easy_install = os.path.join(
935@@ -73,7 +80,7 @@
936 pip_install = ['python2', pip2, 'install', '--target',
937 site_packages_dir]
938
939- if self.requirements and not self.run(
940+ if self.options.requirements and not self.run(
941 pip_install + ['--requirement', requirements]):
942 return False
943
944
945=== modified file 'snapcraft/plugins/python3.py'
946--- snapcraft/plugins/python3.py 2015-10-05 16:16:23 +0000
947+++ snapcraft/plugins/python3.py 2015-10-13 15:27:09 +0000
948@@ -22,23 +22,30 @@
949
950 class Python3Plugin(snapcraft.BasePlugin):
951
952- _PLUGIN_STAGE_PACKAGES = [
953- 'python3-dev',
954- 'python3-pkg-resources',
955- 'python3-setuptools',
956- ]
957+ @classmethod
958+ def schema(cls):
959+ schema = super().schema()
960+ schema['properties']['requirements'] = {
961+ 'type': 'string',
962+ }
963+ schema.pop('required')
964+
965+ return schema
966
967 def __init__(self, name, options):
968 super().__init__(name, options)
969- self.requirements = options.requirements
970- self.source = options.source
971+ self.stage_packages.extend([
972+ 'python3-dev',
973+ 'python3-pkg-resources',
974+ 'python3-setuptools',
975+ ])
976
977 def env(self, root):
978 return ["PYTHONPATH=%s" % os.path.join(
979 root, 'usr', 'lib', self.python_version, 'dist-packages')]
980
981 def pull(self):
982- if self.source and not self.handle_source_options():
983+ if self.options.source and not self.handle_source_options():
984 return False
985
986 return self._pip()
987@@ -48,10 +55,10 @@
988 if os.listdir(self.sourcedir):
989 setup = os.path.join(self.sourcedir, 'setup.py')
990
991- if self.requirements:
992- requirements = os.path.join(os.getcwd(), self.requirements)
993+ if self.options.requirements:
994+ requirements = os.path.join(os.getcwd(), self.options.requirements)
995
996- if not os.path.exists(setup) and not self.requirements:
997+ if not os.path.exists(setup) and not self.options.requirements:
998 return True
999
1000 easy_install = os.path.join(
1001@@ -72,7 +79,7 @@
1002 pip_install = ['python3', pip3, 'install', '--target',
1003 site_packages_dir]
1004
1005- if self.requirements and not self.run(
1006+ if self.options.requirements and not self.run(
1007 pip_install + ['--requirement', requirements]):
1008 return False
1009
1010
1011=== modified file 'snapcraft/plugins/qml.py'
1012--- snapcraft/plugins/qml.py 2015-10-02 09:13:00 +0000
1013+++ snapcraft/plugins/qml.py 2015-10-13 15:27:09 +0000
1014@@ -21,41 +21,47 @@
1015
1016 class QmlPlugin(snapcraft.BasePlugin):
1017
1018- _PLUGIN_STAGE_PACKAGES = [
1019- "qmlscene",
1020- "qtdeclarative5-qtmir-plugin",
1021- "mir-graphics-drivers-desktop",
1022- "qtubuntu-desktop",
1023- "ttf-ubuntu-font-family",
1024- # if there's a metapackage for these, please swap it in here:
1025- "qml-module-qt-labs-folderlistmodel",
1026- "qml-module-qt-labs-settings",
1027- "qml-module-qt-websockets",
1028- "qml-module-qtfeedback",
1029- "qml-module-qtgraphicaleffects",
1030- "qml-module-qtlocation",
1031- "qml-module-qtmultimedia",
1032- "qml-module-qtorganizer",
1033- "qml-module-qtpositioning",
1034- "qml-module-qtqml-models2",
1035- "qml-module-qtqml-statemachine",
1036- "qml-module-qtquick-controls",
1037- "qml-module-qtquick-dialogs",
1038- "qml-module-qtquick-layouts",
1039- "qml-module-qtquick-localstorage",
1040- "qml-module-qtquick-particles2",
1041- "qml-module-qtquick-privatewidgets",
1042- "qml-module-qtquick-window2",
1043- "qml-module-qtquick-xmllistmodel",
1044- "qml-module-qtquick2",
1045- "qml-module-qtsensors",
1046- "qml-module-qtsysteminfo",
1047- "qml-module-qttest",
1048- "qml-module-qtwebkit",
1049- "qml-module-ubuntu-connectivity",
1050- "qml-module-ubuntu-onlineaccounts",
1051- "qml-module-ubuntu-onlineaccounts-client",
1052- ]
1053+ @classmethod
1054+ def schema(cls):
1055+ return {}
1056+
1057+ def __init__(self, name, options):
1058+ super().__init__(name, options)
1059+ self.stage_packages.extend([
1060+ "qmlscene",
1061+ "qtdeclarative5-qtmir-plugin",
1062+ "mir-graphics-drivers-desktop",
1063+ "qtubuntu-desktop",
1064+ "ttf-ubuntu-font-family",
1065+ # if there's a metapackage for these, please swap it in here:
1066+ "qml-module-qt-labs-folderlistmodel",
1067+ "qml-module-qt-labs-settings",
1068+ "qml-module-qt-websockets",
1069+ "qml-module-qtfeedback",
1070+ "qml-module-qtgraphicaleffects",
1071+ "qml-module-qtlocation",
1072+ "qml-module-qtmultimedia",
1073+ "qml-module-qtorganizer",
1074+ "qml-module-qtpositioning",
1075+ "qml-module-qtqml-models2",
1076+ "qml-module-qtqml-statemachine",
1077+ "qml-module-qtquick-controls",
1078+ "qml-module-qtquick-dialogs",
1079+ "qml-module-qtquick-layouts",
1080+ "qml-module-qtquick-localstorage",
1081+ "qml-module-qtquick-particles2",
1082+ "qml-module-qtquick-privatewidgets",
1083+ "qml-module-qtquick-window2",
1084+ "qml-module-qtquick-xmllistmodel",
1085+ "qml-module-qtquick2",
1086+ "qml-module-qtsensors",
1087+ "qml-module-qtsysteminfo",
1088+ "qml-module-qttest",
1089+ "qml-module-qtwebkit",
1090+ "qml-module-ubuntu-connectivity",
1091+ "qml-module-ubuntu-onlineaccounts",
1092+ "qml-module-ubuntu-onlineaccounts-client",
1093+ ])
1094
1095 def snap_fileset(self):
1096 return ['*',
1097
1098=== modified file 'snapcraft/plugins/scons.py'
1099--- snapcraft/plugins/scons.py 2015-10-01 08:54:15 +0000
1100+++ snapcraft/plugins/scons.py 2015-10-13 15:27:09 +0000
1101@@ -21,11 +21,24 @@
1102
1103 class SconsPlugin(snapcraft.BasePlugin):
1104
1105+ @classmethod
1106+ def schema(cls):
1107+ schema = super().schema()
1108+ schema['properties']['scons-options'] = {
1109+ 'type': 'array',
1110+ 'minitems': 1,
1111+ 'uniqueItems': True,
1112+ 'items': {
1113+ 'type': 'string',
1114+ },
1115+ 'default': []
1116+ }
1117+
1118+ return schema
1119+
1120 def __init__(self, name, options):
1121 super().__init__(name, options)
1122- self.scons_options = []
1123- if options.scons_options:
1124- self.scons_options = options.scons_options
1125+ self.build_packages.append('scons')
1126
1127 def pull(self):
1128 return self.handle_source_options()
1129@@ -33,5 +46,6 @@
1130 def build(self):
1131 env = os.environ.copy()
1132 env['DESTDIR'] = self.installdir
1133- return (self.run(['scons', ] + self.scons_options) and
1134- self.run(['scons', 'install'] + self.scons_options, env=env))
1135+ return (self.run(['scons', ] + self.options.scons_options) and
1136+ self.run(['scons', 'install'] +
1137+ self.options.scons_options, env=env))
1138
1139=== modified file 'snapcraft/plugins/tar_content.py'
1140--- snapcraft/plugins/tar_content.py 2015-08-31 13:49:40 +0000
1141+++ snapcraft/plugins/tar_content.py 2015-10-13 15:27:09 +0000
1142@@ -20,6 +20,19 @@
1143
1144 class TarContentPlugin(snapcraft.BasePlugin):
1145
1146+ @classmethod
1147+ def schema(cls):
1148+ return {
1149+ 'properties': {
1150+ 'source': {
1151+ 'type': 'string',
1152+ },
1153+ },
1154+ 'required': [
1155+ 'source',
1156+ ]
1157+ }
1158+
1159 def __init__(self, name, options):
1160 super().__init__(name, options)
1161 self.tar = snapcraft.sources.Tar(self.options.source, self.builddir)
1162
1163=== modified file 'snapcraft/tests/test_cmds.py'
1164--- snapcraft/tests/test_cmds.py 2015-10-02 09:13:00 +0000
1165+++ snapcraft/tests/test_cmds.py 2015-10-13 15:27:09 +0000
1166@@ -39,14 +39,14 @@
1167 tmpdir = tmpdirObject.name
1168
1169 part1 = mock.Mock()
1170- part1.names.return_value = ['part1']
1171+ part1.name = 'part1'
1172 part1.code.options.stage = ['*']
1173 part1.installdir = tmpdir + '/install1'
1174 os.makedirs(part1.installdir + '/a')
1175 open(part1.installdir + '/a/1', mode='w').close()
1176
1177 part2 = mock.Mock()
1178- part2.names.return_value = ['part2']
1179+ part2.name = 'part2'
1180 part2.code.options.stage = ['*']
1181 part2.installdir = tmpdir + '/install2'
1182 os.makedirs(part2.installdir + '/a')
1183@@ -57,7 +57,7 @@
1184 f.write('a/2')
1185
1186 part3 = mock.Mock()
1187- part3.names.return_value = ['part3']
1188+ part3.name = 'part3'
1189 part3.code.options.stage = ['*']
1190 part3.installdir = tmpdir + '/install3'
1191 os.makedirs(part3.installdir + '/a')
1192
1193=== modified file 'snapcraft/tests/test_plugin.py'
1194--- snapcraft/tests/test_plugin.py 2015-10-02 09:13:00 +0000
1195+++ snapcraft/tests/test_plugin.py 2015-10-13 15:27:09 +0000
1196@@ -28,16 +28,12 @@
1197 plugin,
1198 tests
1199 )
1200-from snapcraft.tests import mock_plugin
1201-
1202-
1203-def get_test_plugin(name='mock', part_name='mock-part',
1204- properties=None, load_code=False, load_config=False):
1205+
1206+
1207+def get_test_plugin(name='mock', part_name='mock-part', properties=None):
1208 if properties is None:
1209 properties = {}
1210- return plugin.PluginHandler(
1211- name, part_name, properties, load_code=load_code,
1212- load_config=load_config)
1213+ return plugin.PluginHandler(name, part_name, properties)
1214
1215
1216 class PluginTestCase(tests.TestCase):
1217@@ -46,7 +42,7 @@
1218 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
1219 self.useFixture(fake_logger)
1220
1221- get_test_plugin('test_unexisting_name', load_config=True)
1222+ get_test_plugin('test_unexisting_name')
1223
1224 self.assertEqual(
1225 'Unknown plugin: test_unexisting_name\n', fake_logger.output)
1226@@ -202,24 +198,18 @@
1227
1228 self.assertEqual(expected, result)
1229
1230- def test_notify_stage_must_log_information(self):
1231- fake_logger = fixtures.FakeLogger(level=logging.INFO)
1232- self.useFixture(fake_logger)
1233-
1234- p = get_test_plugin()
1235- p.notify_stage('test stage')
1236-
1237- self.assertEqual('test stage mock-part\n', fake_logger.output)
1238-
1239- def test_non_local_plugins(self):
1240- """Ensure regular plugins are loaded from snapcraft only"""
1241- def mock_import_modules(module_name):
1242- # called with the full snapcraft path
1243- self.assertEqual(module_name, "snapcraft.plugins.mock")
1244- return mock_plugin
1245- with patch("importlib.import_module", side_effect=mock_import_modules):
1246- plugin.PluginHandler(
1247- "mock", "mock-part", {}, load_config=False, load_code=True)
1248+ @patch('importlib.import_module')
1249+ @patch('snapcraft.plugin._load_local')
1250+ @patch('snapcraft.plugin._get_plugin')
1251+ def test_non_local_plugins(self, plugin_mock,
1252+ local_load_mock, import_mock):
1253+ mock_plugin = Mock()
1254+ mock_plugin.schema.return_value = {}
1255+ plugin_mock.return_value = mock_plugin
1256+ local_load_mock.side_effect = ImportError()
1257+ plugin.PluginHandler('mock', 'mock-part', {})
1258+ import_mock.assert_called_with('snapcraft.plugins.mock')
1259+ local_load_mock.assert_called_with('x-mock')
1260
1261 def test_filesets_includes_without_relative_paths(self):
1262 with self.assertRaises(plugin.PluginError) as raised:
1263@@ -240,8 +230,7 @@
1264 self.useFixture(fake_logger)
1265
1266 with self.assertRaises(SystemExit) as raised:
1267- plugin.load_plugin(
1268- 'dummy-part', 'test_unexisting_name', load_code=False)
1269+ plugin.load_plugin('dummy-part', 'test_unexisting_name')
1270
1271 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
1272 self.assertEqual(
1273
1274=== modified file 'snapcraft/yaml.py'
1275--- snapcraft/yaml.py 2015-10-05 16:56:10 +0000
1276+++ snapcraft/yaml.py 2015-10-13 15:27:09 +0000
1277@@ -129,36 +129,19 @@
1278
1279 self.load_plugin(part_name, plugin_name, properties)
1280
1281- self._load_missing_part_plugins()
1282 self._compute_part_dependencies(after_requests)
1283 self.all_parts = self._sort_parts()
1284
1285- def _load_missing_part_plugins(self):
1286- new_parts = self.all_parts.copy()
1287- while new_parts:
1288- part = new_parts.pop(0)
1289- requires = part.config.get('requires', [])
1290- for required_part in requires:
1291- present = False
1292- for p in self.all_parts:
1293- if required_part in p.names():
1294- present = True
1295- break
1296- if not present:
1297- new_parts.append(self.load_plugin(required_part,
1298- required_part, {}))
1299-
1300 def _compute_part_dependencies(self, after_requests):
1301 '''Gather the lists of dependencies and adds to all_parts.'''
1302 w = snapcraft.wiki.Wiki()
1303
1304 for part in self.all_parts:
1305- dep_names = part.config.get('requires', []) + \
1306- after_requests.get(part.names()[0], [])
1307+ dep_names = after_requests.get(part.name, [])
1308 for dep in dep_names:
1309 found = False
1310 for i in range(len(self.all_parts)):
1311- if dep in self.all_parts[i].names():
1312+ if dep in self.all_parts[i].name:
1313 part.deps.append(self.all_parts[i])
1314 found = True
1315 break
1316@@ -195,11 +178,10 @@
1317
1318 return sorted_parts
1319
1320- def load_plugin(self, part_name, plugin_name, properties, load_code=True):
1321- part = snapcraft.plugin.load_plugin(part_name, plugin_name,
1322- properties, load_code=load_code)
1323+ def load_plugin(self, part_name, plugin_name, properties):
1324+ part = snapcraft.plugin.load_plugin(part_name, plugin_name, properties)
1325
1326- self.build_tools += part.config.get('build-packages', [])
1327+ self.build_tools += part.code.build_packages
1328 self.all_parts.append(part)
1329 return part
1330

Subscribers

People subscribed via source and target branches