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

Proposed by Sergio Schvezov
Status: Merged
Approved by: Sergio Schvezov
Approved revision: 212
Merged at revision: 247
Proposed branch: lp:~sergiusens/snapcraft/cleanup
Merge into: lp:~snappy-dev/snapcraft/core
Diff against target: 946 lines (+260/-210)
16 files modified
snapcraft/__init__.py (+63/-100)
snapcraft/plugin.py (+8/-1)
snapcraft/plugins/ant.py (+0/-4)
snapcraft/plugins/catkin.py (+25/-11)
snapcraft/plugins/jdk.py (+3/-0)
snapcraft/plugins/make.py (+0/-3)
snapcraft/plugins/maven.py (+0/-4)
snapcraft/plugins/python2.py (+1/-1)
snapcraft/plugins/python3.py (+1/-1)
snapcraft/plugins/scons.py (+0/-3)
snapcraft/repo.py (+15/-0)
snapcraft/sources.py (+48/-0)
snapcraft/tests/test_base_plugin.py (+25/-45)
snapcraft/tests/test_common.py (+7/-0)
snapcraft/tests/test_plugin.py (+1/-0)
snapcraft/tests/test_sources.py (+63/-37)
To merge this branch: bzr merge lp:~sergiusens/snapcraft/cleanup
Reviewer Review Type Date Requested Status
Leo Arias (community) Approve
John Lenton (community) Approve
Review via email: mp+274801@code.launchpad.net

Commit message

Document and cleanup the plugin base class

This cleans up the base class to only expose things plugins will need, since the basic schema includes 'source' options it makes sense for pull to implement that as well automatically if supported.

This also moves everything from the base plugin the plugin.py (which should be renamed to lifecycle.py in a future MP, this one is already too big) and any other thing to its own supporting class.

This branch also includes all the plugin cleanup required for things to keep on working.

Description of the change

This all started with trying to get the catkin plugin out of using the private implementation (setup_stage_packages)

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) wrote :

Looks good. A couple of comments on code that I know is just moved, so not a blocker to land.

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

This is a nice step forward, thanks.
I'm marking it needs fixing because of a couple of typos. Also some wording suggestions in the diff.

review: Needs Fixing
lp:~sergiusens/snapcraft/cleanup updated
210. By Sergio Schvezov

Use a dictionary for source type handlers

211. By Sergio Schvezov

Compile the tar regex only once

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

Thanks for the reviews, I've updated da things

lp:~sergiusens/snapcraft/cleanup updated
212. By Sergio Schvezov

Improve docstrings

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

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'snapcraft/__init__.py'
2--- snapcraft/__init__.py 2015-10-14 20:00:25 +0000
3+++ snapcraft/__init__.py 2015-10-19 19:01:20 +0000
4@@ -17,7 +17,6 @@
5 import contextlib
6 import logging
7 import os
8-import re
9
10 import snapcraft.common
11 import snapcraft.sources
12@@ -31,15 +30,14 @@
13
14 @classmethod
15 def schema(cls):
16- '''
17- Returns a json-schema for the plugin's properties as a dictionary.
18+ """Return a json-schema for the plugin's properties as a dictionary.
19 Of importance to plugin authors is the 'properties' keyword and
20 optionally the 'requires' keyword with a list of required
21 'properties'.
22
23 By default the the properties will be that of a standard VCS, override
24 in custom implementations if required.
25- '''
26+ """
27 return {
28 '$schema': 'http://json-schema.org/draft-04/schema#',
29 'type': 'object',
30@@ -67,6 +65,7 @@
31
32 @property
33 def PLUGIN_STAGE_SOURCES(self):
34+ """Define additional sources.list."""
35 return getattr(self, '_PLUGIN_STAGE_SOURCES', [])
36
37 def __init__(self, name, options):
38@@ -92,19 +91,74 @@
39
40 # The API
41 def pull(self):
42- return True
43+ """Pull the source code and/or internal prereqs to build the part.
44+
45+ By default, the base implementation for pull will use the following
46+ part properties to retrieve source code:
47+
48+ - source
49+ - source-branch
50+ - source-tag
51+ - source-type
52+
53+ If source is empty or does not exist, the phase will be skipped.
54+
55+ Override or inherit from this method if you need to implement or
56+ enhance with custom pull logic.
57+ """
58+ if not getattr(self.options, 'source', None):
59+ return True
60+ try:
61+ return snapcraft.sources.get(
62+ self.sourcedir, self.builddir, self.options)
63+ except ValueError as e:
64+ logger.error('Unrecognized source %r for part %r: %s.',
65+ self.options.source, self.name, e)
66+ snapcraft.common.fatal()
67+ except snapcraft.sources.IncompatibleOptionsError as e:
68+ logger.error(
69+ 'Issues while setting up sources for part \'%s\': %s.',
70+ self.name,
71+ e.message)
72+ snapcraft.common.fatal()
73
74 def build(self):
75+ """Build the source code retrieved from the pull phase.
76+
77+ The base implementation does nothing by default. Override this method
78+ if you need to process the source code to make it runnable.
79+ """
80 return True
81
82 def snap_fileset(self):
83- """Returns one iteratables of globs specific to the plugin:
84+ """Return a list of files to include or exclude in the resulting snap
85+
86+ The staging phase of a plugin's lifecycle may populate many things
87+ into the staging directory in order to succeed in building a project.
88+ During the stripping phase and in order to have a clean snap, the
89+ plugin can provide additional logic for stripping build components
90+ from the final snap and alleviate the part author from doing so for
91+ repetetive filesets.
92+
93+ These are the rules to honor when creating such list:
94+
95 - includes can be just listed
96 - excludes must be preceded by -
97- For example: (['bin', 'lib', '-include'])"""
98+
99+ For example::
100+ (['bin', 'lib', '-include'])
101+ """
102 return ([])
103
104 def env(self, root):
105+ """Return a list with the execution environment for building.
106+
107+ Plugins often need special environment variables exported to the
108+ system for some builds to take place. This is a list of strings
109+ of the form key=value. The parameter root is the path to this part.
110+
111+ :param str root: The root for the part
112+ """
113 return []
114
115 # Helpers
116@@ -113,7 +167,7 @@
117 cwd = self.builddir
118 if True:
119 print(' '.join(cmd))
120- self.makedirs(cwd)
121+ os.makedirs(cwd, exist_ok=True)
122 return snapcraft.common.run(cmd, cwd=cwd, **kwargs)
123
124 def run_output(self, cmd, cwd=None, **kwargs):
125@@ -121,96 +175,5 @@
126 cwd = self.builddir
127 if True:
128 print(' '.join(cmd))
129- self.makedirs(cwd)
130+ os.makedirs(cwd, exist_ok=True)
131 return snapcraft.common.run_output(cmd, cwd=cwd, **kwargs)
132-
133- def isurl(self, url):
134- return snapcraft.common.isurl(url)
135-
136- def get_source(self, source, source_type=None, source_tag=None,
137- source_branch=None):
138- try:
139- handler_class = _get_source_handler(source_type, source)
140- except ValueError as e:
141- logger.error('Unrecognized source %r for part %r: %s.', source,
142- self.name, e)
143- snapcraft.common.fatal()
144-
145- try:
146- handler = handler_class(source, self.sourcedir, source_tag,
147- source_branch)
148- except snapcraft.sources.IncompatibleOptionsError as e:
149- logger.error(
150- 'Issues while setting up sources for part \'%s\': %s.',
151- self.name,
152- e.message)
153- snapcraft.common.fatal()
154- if not handler.pull():
155- return False
156- return handler.provision(self.builddir)
157-
158- def handle_source_options(self):
159- stype = getattr(self.options, 'source_type', None)
160- stag = getattr(self.options, 'source_tag', None)
161- sbranch = getattr(self.options, 'source_branch', None)
162- return self.get_source(self.options.source,
163- source_type=stype,
164- source_tag=stag,
165- source_branch=sbranch)
166-
167- def makedirs(self, d):
168- os.makedirs(d, exist_ok=True)
169-
170- def setup_stage_packages(self):
171- if self.stage_packages:
172- ubuntu = snapcraft.repo.Ubuntu(self.ubuntudir,
173- sources=self.PLUGIN_STAGE_SOURCES)
174- ubuntu.get(self.stage_packages)
175- ubuntu.unpack(self.installdir)
176- self._fixup(self.installdir)
177-
178- def _fixup(self, root):
179- if os.path.isfile(os.path.join(root, 'usr', 'bin', 'xml2-config')):
180- self.run(
181- ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
182- format(root),
183- os.path.join(root, 'usr', 'bin', 'xml2-config')])
184- if os.path.isfile(os.path.join(root, 'usr', 'bin', 'xslt-config')):
185- self.run(
186- ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
187- format(root),
188- os.path.join(root, 'usr', 'bin', 'xslt-config')])
189-
190-
191-def _get_source_handler(source_type, source):
192- if not source_type:
193- source_type = _get_source_type_from_uri(source)
194-
195- if source_type == 'bzr':
196- handler = snapcraft.sources.Bazaar
197- elif source_type == 'git':
198- handler = snapcraft.sources.Git
199- elif source_type == 'mercurial' or source_type == 'hg':
200- handler = snapcraft.sources.Mercurial
201- elif source_type == 'tar':
202- handler = snapcraft.sources.Tar
203- else:
204- handler = snapcraft.sources.Local
205-
206- return handler
207-
208-
209-def _get_source_type_from_uri(source):
210- source_type = ''
211- if source.startswith("bzr:") or source.startswith("lp:"):
212- source_type = 'bzr'
213- elif source.startswith("git:"):
214- source_type = 'git'
215- elif re.compile(r'.*\.((tar\.(xz|gz|bz2))|tgz)$').match(source):
216- source_type = 'tar'
217- elif snapcraft.common.isurl(source):
218- raise ValueError('No handler to manage source')
219- elif not os.path.isdir(source):
220- raise ValueError('Local source is not a directory')
221-
222- return source_type
223
224=== modified file 'snapcraft/plugin.py'
225--- snapcraft/plugin.py 2015-10-15 17:01:43 +0000
226+++ snapcraft/plugin.py 2015-10-19 19:01:20 +0000
227@@ -137,6 +137,13 @@
228 with open(self.statefile, 'w+') as f:
229 f.write(stage)
230
231+ def _setup_stage_packages(self):
232+ if self.code.stage_packages:
233+ ubuntu = snapcraft.repo.Ubuntu(
234+ self.code.ubuntudir, sources=self.code.PLUGIN_STAGE_SOURCES)
235+ ubuntu.get(self.code.stage_packages)
236+ ubuntu.unpack(self.code.installdir)
237+
238 def pull(self, force=False):
239 if not self.should_stage_run('pull', force):
240 return True
241@@ -145,7 +152,7 @@
242 self.notify_stage("Pulling")
243
244 try:
245- self.code.setup_stage_packages()
246+ self._setup_stage_packages()
247 except repo.PackageNotFoundError as e:
248 logger.error(e.message)
249 return False
250
251=== modified file 'snapcraft/plugins/ant.py'
252--- snapcraft/plugins/ant.py 2015-10-09 17:43:20 +0000
253+++ snapcraft/plugins/ant.py 2015-10-19 19:01:20 +0000
254@@ -33,10 +33,6 @@
255 super().__init__(name, options)
256 self.build_packages.append('ant')
257
258- def pull(self):
259- super().pull()
260- return self.handle_source_options()
261-
262 def build(self):
263 super().build()
264 if not self.run(['ant']):
265
266=== modified file 'snapcraft/plugins/catkin.py'
267--- snapcraft/plugins/catkin.py 2015-10-16 19:05:42 +0000
268+++ snapcraft/plugins/catkin.py 2015-10-19 19:01:20 +0000
269@@ -20,6 +20,7 @@
270 import logging
271
272 import snapcraft
273+import snapcraft.repo
274
275 logger = logging.getLogger(__name__)
276
277@@ -61,6 +62,19 @@
278 self.dependencies = ['ros-core']
279 self.package_deps_found = False
280 self.package_local_deps = {}
281+ self._deb_packages = []
282+
283+ def pull(self):
284+ if not super().pull():
285+ return False
286+
287+ try:
288+ self._setup_deb_packages()
289+ except snapcraft.repo.PackageNotFoundError as e:
290+ logger.error(e.message)
291+ return False
292+
293+ return True
294
295 def env(self, root):
296 return [
297@@ -124,19 +138,18 @@
298 self.package_local_deps[pkg].add(dep)
299 continue
300
301- # If we're already getting this through a stage package,
302+ # If we're already getting this through a deb package,
303 # we don't need it
304- if self.options.stage_packages and (
305- dep in self.options.stage_packages or
306- dep.replace('_', '-') in self.options.stage_packages):
307+ if (dep in self._deb_packages or
308+ dep.replace('_', '-') in self._deb_packages):
309 continue
310
311 # Get the ROS package for it
312- self.stage_packages.append(
313+ self._deb_packages.append(
314 'ros-'+self.options.rosversion+'-'+dep.replace('_', '-'))
315
316 if dep == 'roscpp':
317- self.stage_packages.append('g++')
318+ self._deb_packages.append('g++')
319
320 def _find_package_deps(self):
321 if self.package_deps_found:
322@@ -158,13 +171,14 @@
323
324 self.package_deps_found = True
325
326- def setup_stage_packages(self):
327- if not self.handle_source_options():
328- return False
329-
330+ def _setup_deb_packages(self):
331 self._find_package_deps()
332
333- return super().setup_stage_packages()
334+ if self._deb_packages:
335+ ubuntu = snapcraft.repo.Ubuntu(
336+ self.ubuntudir, sources=self.PLUGIN_STAGE_SOURCES)
337+ ubuntu.get(self._deb_packages)
338+ ubuntu.unpack(self.installdir)
339
340 def _rosrun(self, commandlist, cwd=None):
341 with tempfile.NamedTemporaryFile(mode='w') as f:
342
343=== modified file 'snapcraft/plugins/jdk.py'
344--- snapcraft/plugins/jdk.py 2015-10-09 02:18:59 +0000
345+++ snapcraft/plugins/jdk.py 2015-10-19 19:01:20 +0000
346@@ -23,6 +23,9 @@
347 super().__init__(name, options)
348 self.stage_packages.append('default-jdk')
349
350+ def pull(self):
351+ return True
352+
353 def env(self, root):
354 return ['JAVA_HOME=%s/usr/lib/jvm/default-java' % root,
355 'PATH=%s/usr/lib/jvm/default-java/bin:'
356
357=== modified file 'snapcraft/plugins/make.py'
358--- snapcraft/plugins/make.py 2015-10-09 17:43:20 +0000
359+++ snapcraft/plugins/make.py 2015-10-19 19:01:20 +0000
360@@ -23,9 +23,6 @@
361 super().__init__(name, options)
362 self.build_packages.append('make')
363
364- def pull(self):
365- return self.handle_source_options()
366-
367 def build(self):
368 return self.run(['make']) and \
369 self.run(['make', 'install', 'DESTDIR=' + self.installdir])
370
371=== modified file 'snapcraft/plugins/maven.py'
372--- snapcraft/plugins/maven.py 2015-10-09 17:43:20 +0000
373+++ snapcraft/plugins/maven.py 2015-10-19 19:01:20 +0000
374@@ -32,10 +32,6 @@
375 super().__init__(name, options)
376 self.build_packages.append('maven')
377
378- def pull(self):
379- super().pull()
380- return self.handle_source_options()
381-
382 def build(self):
383 super().build()
384
385
386=== modified file 'snapcraft/plugins/python2.py'
387--- snapcraft/plugins/python2.py 2015-10-09 17:43:20 +0000
388+++ snapcraft/plugins/python2.py 2015-10-19 19:01:20 +0000
389@@ -45,7 +45,7 @@
390 root, 'usr', 'lib', self.python_version, 'dist-packages')]
391
392 def pull(self):
393- if self.options.source and not self.handle_source_options():
394+ if not super().pull():
395 return False
396
397 return self._pip()
398
399=== modified file 'snapcraft/plugins/python3.py'
400--- snapcraft/plugins/python3.py 2015-10-09 17:43:20 +0000
401+++ snapcraft/plugins/python3.py 2015-10-19 19:01:20 +0000
402@@ -45,7 +45,7 @@
403 root, 'usr', 'lib', self.python_version, 'dist-packages')]
404
405 def pull(self):
406- if self.options.source and not self.handle_source_options():
407+ if not super().pull():
408 return False
409
410 return self._pip()
411
412=== modified file 'snapcraft/plugins/scons.py'
413--- snapcraft/plugins/scons.py 2015-10-09 17:43:20 +0000
414+++ snapcraft/plugins/scons.py 2015-10-19 19:01:20 +0000
415@@ -40,9 +40,6 @@
416 super().__init__(name, options)
417 self.build_packages.append('scons')
418
419- def pull(self):
420- return self.handle_source_options()
421-
422 def build(self):
423 env = os.environ.copy()
424 env['DESTDIR'] = self.installdir
425
426=== modified file 'snapcraft/repo.py'
427--- snapcraft/repo.py 2015-10-16 20:38:56 +0000
428+++ snapcraft/repo.py 2015-10-19 19:01:20 +0000
429@@ -135,6 +135,7 @@
430 raise UnpackError(pkg)
431
432 _fix_contents(rootdir)
433+ _fix_xml_tools(rootdir)
434
435 def _manifest_dep_names(self):
436 manifest_dep_names = set()
437@@ -252,6 +253,20 @@
438 _fix_filemode(path)
439
440
441+def _fix_xml_tools(root):
442+ xml2_config_path = os.path.join(root, 'usr', 'bin', 'xml2-config')
443+ if os.path.isfile(xml2_config_path):
444+ snapcraft.common.run(
445+ ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
446+ format(root), xml2_config_path])
447+
448+ xslt_config_path = os.path.join(root, 'usr', 'bin', 'xslt-config')
449+ if os.path.isfile(xslt_config_path):
450+ snapcraft.common.run(
451+ ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
452+ format(root), xslt_config_path])
453+
454+
455 def _fix_filemode(path):
456 mode = stat.S_IMODE(os.stat(path).st_mode)
457 if mode & 0o4000 or mode & 0o2000:
458
459=== modified file 'snapcraft/sources.py'
460--- snapcraft/sources.py 2015-10-14 18:14:47 +0000
461+++ snapcraft/sources.py 2015-10-19 19:01:20 +0000
462@@ -227,3 +227,51 @@
463 os.symlink(path, dst)
464
465 return True
466+
467+
468+def get(sourcedir, builddir, options):
469+ source_type = getattr(options, 'source_type', None)
470+ source_tag = getattr(options, 'source_tag', None)
471+ source_branch = getattr(options, 'source_branch', None)
472+
473+ handler_class = _get_source_handler(source_type, options.source)
474+ handler = handler_class(options.source, sourcedir, source_tag,
475+ source_branch)
476+ if not handler.pull():
477+ return False
478+ return handler.provision(builddir)
479+
480+
481+_source_handler = {
482+ 'bzr': Bazaar,
483+ 'git': Git,
484+ 'hg': Mercurial,
485+ 'mercurial': Mercurial,
486+ 'tar': Tar,
487+}
488+
489+
490+def _get_source_handler(source_type, source):
491+ if not source_type:
492+ source_type = _get_source_type_from_uri(source)
493+
494+ return _source_handler.get(source_type, Local)
495+
496+
497+_tar_type_regex = re.compile(r'.*\.((tar\.(xz|gz|bz2))|tgz)$')
498+
499+
500+def _get_source_type_from_uri(source):
501+ source_type = ''
502+ if source.startswith("bzr:") or source.startswith("lp:"):
503+ source_type = 'bzr'
504+ elif source.startswith("git:"):
505+ source_type = 'git'
506+ elif _tar_type_regex.match(source):
507+ source_type = 'tar'
508+ elif snapcraft.common.isurl(source):
509+ raise ValueError('No handler to manage source')
510+ elif not os.path.isdir(source):
511+ raise ValueError('Local source is not a directory')
512+
513+ return source_type
514
515=== modified file 'snapcraft/tests/test_base_plugin.py'
516--- snapcraft/tests/test_base_plugin.py 2015-10-14 20:00:25 +0000
517+++ snapcraft/tests/test_base_plugin.py 2015-10-19 19:01:20 +0000
518@@ -16,30 +16,32 @@
519
520 import fixtures
521 import logging
522-import os
523 import unittest.mock
524
525 import snapcraft
526 from snapcraft import tests
527
528
529+class MockOptions:
530+
531+ def __init__(self, source, source_type=None, source_branch=None,
532+ source_tag=None):
533+ self.source = source
534+ self.source_type = source_type
535+ self.source_branch = source_branch
536+ self.source_tag = source_tag
537+
538+
539 class TestBasePlugin(tests.TestCase):
540
541- def test_isurl(self):
542- plugin = snapcraft.BasePlugin('mock', {})
543- self.assertTrue(plugin.isurl('git://'))
544- self.assertTrue(plugin.isurl('bzr://'))
545- self.assertFalse(plugin.isurl('./'))
546- self.assertFalse(plugin.isurl('/foo'))
547- self.assertFalse(plugin.isurl('/fo:o'))
548-
549 def test_get_source_with_unrecognized_source_must_raise_error(self):
550 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
551 self.useFixture(fake_logger)
552
553- plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')
554+ options = MockOptions('unrecognized://test_source')
555+ plugin = snapcraft.BasePlugin('test_plugin', options)
556 with self.assertRaises(SystemExit) as raised:
557- plugin.get_source('unrecognized://test_source')
558+ plugin.pull()
559
560 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
561 expected = (
562@@ -52,10 +54,11 @@
563 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
564 self.useFixture(fake_logger)
565
566+ options = MockOptions('file')
567 mock_isdir.return_value = False
568- plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')
569+ plugin = snapcraft.BasePlugin('test_plugin', options)
570 with self.assertRaises(SystemExit) as raised:
571- plugin.get_source('file')
572+ plugin.pull()
573
574 mock_isdir.assert_called_once_with('file')
575 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
576@@ -64,30 +67,6 @@
577 "Local source is not a directory.\n")
578 self.assertEqual(expected, fake_logger.output)
579
580- def test_makedirs_with_existing_dir(self):
581- plugin = snapcraft.BasePlugin('dummy_plugin', 'dummy_options')
582- plugin.makedirs(self.path)
583- self.assertTrue(os.path.exists(self.path))
584-
585- def test_makedirs_with_unexisting_dir(self):
586- path = os.path.join(self.path, 'unexisting')
587- plugin = snapcraft.BasePlugin('dummy_plugin', 'dummy_options')
588- plugin.makedirs(path)
589- self.assertTrue(os.path.exists(path))
590-
591- def test_get_tar_source_from_uri(self):
592- sources = [
593- 'https://golang.tar.gz',
594- 'https://golang.tar.xz',
595- 'https://golang.tar.bz2',
596- 'https://golang.tar.tgz',
597- ]
598-
599- for source in sources:
600- with self.subTest(key=source):
601- self.assertEqual(
602- snapcraft._get_source_type_from_uri(source), 'tar')
603-
604
605 class GetSourceWithBranches(tests.TestCase):
606
607@@ -108,11 +87,11 @@
608 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
609 self.useFixture(fake_logger)
610
611- plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')
612+ options = MockOptions('lp:source', self.source_type,
613+ self.source_branch, self.source_tag)
614+ plugin = snapcraft.BasePlugin('test_plugin', options)
615 with self.assertRaises(SystemExit) as raised:
616- plugin.get_source(
617- 'dummy_source', source_type=self.source_type,
618- source_branch=self.source_branch, source_tag=self.source_tag)
619+ plugin.pull()
620
621 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
622 expected = (
623@@ -146,11 +125,12 @@
624 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
625 self.useFixture(fake_logger)
626
627- plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')
628+ options = MockOptions('lp:this', self.source_type, self.source_branch,
629+ self.source_tag)
630+ plugin = snapcraft.BasePlugin('test_plugin', options)
631+
632 with self.assertRaises(SystemExit) as raised:
633- plugin.get_source(
634- 'dummy_source', source_type=self.source_type,
635- source_branch=self.source_branch, source_tag=self.source_tag)
636+ plugin.pull()
637
638 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
639 expected = (
640
641=== modified file 'snapcraft/tests/test_common.py'
642--- snapcraft/tests/test_common.py 2015-07-23 17:26:18 +0000
643+++ snapcraft/tests/test_common.py 2015-10-19 19:01:20 +0000
644@@ -40,3 +40,10 @@
645 plugindir = os.path.join(self.path, 'testplugin')
646 common.set_plugindir(plugindir)
647 self.assertEqual(plugindir, common.get_plugindir())
648+
649+ def test_isurl(self):
650+ self.assertTrue(common.isurl('git://'))
651+ self.assertTrue(common.isurl('bzr://'))
652+ self.assertFalse(common.isurl('./'))
653+ self.assertFalse(common.isurl('/foo'))
654+ self.assertFalse(common.isurl('/fo:o'))
655
656=== modified file 'snapcraft/tests/test_plugin.py'
657--- snapcraft/tests/test_plugin.py 2015-10-09 17:43:20 +0000
658+++ snapcraft/tests/test_plugin.py 2015-10-19 19:01:20 +0000
659@@ -52,6 +52,7 @@
660 p.statefile = tempfile.NamedTemporaryFile().name
661 self.addCleanup(os.remove, p.statefile)
662 p.code = Mock()
663+ p._setup_stage_packages = Mock()
664 # pull once
665 p.pull()
666 p.code.pull.assert_called()
667
668=== modified file 'snapcraft/tests/test_sources.py'
669--- snapcraft/tests/test_sources.py 2015-10-14 18:14:47 +0000
670+++ snapcraft/tests/test_sources.py 2015-10-19 19:01:20 +0000
671@@ -19,7 +19,8 @@
672 import threading
673 import unittest.mock
674
675-from snapcraft import sources
676+import snapcraft.sources
677+
678 from snapcraft import tests
679
680
681@@ -56,7 +57,7 @@
682 tar_file_name = 'test.tar'
683 source = 'http://{}:{}/{file_name}'.format(
684 *server.server_address, file_name=tar_file_name)
685- tar_source = sources.Tar(source, dest_dir)
686+ tar_source = snapcraft.sources.Tar(source, dest_dir)
687
688 self.assertTrue(tar_source.pull())
689
690@@ -87,7 +88,7 @@
691 class TestBazaar(SourceTestCase):
692
693 def test_pull(self):
694- bzr = sources.Bazaar('lp:my-source', 'source_dir')
695+ bzr = snapcraft.sources.Bazaar('lp:my-source', 'source_dir')
696
697 bzr.pull()
698
699@@ -96,7 +97,8 @@
700 ['bzr', 'branch', 'lp:my-source', 'source_dir'], cwd=os.getcwd())
701
702 def test_pull_tag(self):
703- bzr = sources.Bazaar('lp:my-source', 'source_dir', source_tag='tag')
704+ bzr = snapcraft.sources.Bazaar(
705+ 'lp:my-source', 'source_dir', source_tag='tag')
706 bzr.pull()
707
708 self.mock_run.assert_called_once_with(
709@@ -106,7 +108,8 @@
710 def test_pull_existing_with_tag(self):
711 self.mock_path_exists.return_value = True
712
713- bzr = sources.Bazaar('lp:my-source', 'source_dir', source_tag='tag')
714+ bzr = snapcraft.sources.Bazaar(
715+ 'lp:my-source', 'source_dir', source_tag='tag')
716 bzr.pull()
717
718 self.mock_run.assert_called_once_with(
719@@ -114,15 +117,17 @@
720 'source_dir'], cwd=os.getcwd())
721
722 def test_provision(self):
723- bzr = sources.Bazaar('lp:my-source', 'source_dir')
724+ bzr = snapcraft.sources.Bazaar('lp:my-source', 'source_dir')
725 bzr.provision('dst')
726
727 self.mock_run.assert_called_once_with(
728 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())
729
730 def test_init_with_source_branch_raises_exception(self):
731- with self.assertRaises(sources.IncompatibleOptionsError) as raised:
732- sources.Bazaar('lp:mysource', 'source_dir', source_branch='branch')
733+ with self.assertRaises(
734+ snapcraft.sources.IncompatibleOptionsError) as raised:
735+ snapcraft.sources.Bazaar('lp:mysource', 'source_dir',
736+ source_branch='branch')
737
738 expected_message = 'can\'t specify a source-branch for a bzr source'
739 self.assertEqual(raised.exception.message, expected_message)
740@@ -131,7 +136,7 @@
741 class TestGit(SourceTestCase):
742
743 def test_pull(self):
744- git = sources.Git('git://my-source', 'source_dir')
745+ git = snapcraft.sources.Git('git://my-source', 'source_dir')
746
747 git.pull()
748
749@@ -139,8 +144,8 @@
750 ['git', 'clone', 'git://my-source', 'source_dir'], cwd=os.getcwd())
751
752 def test_pull_branch(self):
753- git = sources.Git('git://my-source', 'source_dir',
754- source_branch='my-branch')
755+ git = snapcraft.sources.Git('git://my-source', 'source_dir',
756+ source_branch='my-branch')
757 git.pull()
758
759 self.mock_run.assert_called_once_with(
760@@ -148,7 +153,8 @@
761 'source_dir'], cwd=os.getcwd())
762
763 def test_pull_tag(self):
764- git = sources.Git('git://my-source', 'source_dir', source_tag='tag')
765+ git = snapcraft.sources.Git('git://my-source', 'source_dir',
766+ source_tag='tag')
767 git.pull()
768
769 self.mock_run.assert_called_once_with(
770@@ -158,7 +164,7 @@
771 def test_pull_existing(self):
772 self.mock_path_exists.return_value = True
773
774- git = sources.Git('git://my-source', 'source_dir')
775+ git = snapcraft.sources.Git('git://my-source', 'source_dir')
776 git.pull()
777
778 self.mock_run.assert_called_once_with(
779@@ -168,7 +174,8 @@
780 def test_pull_existing_with_tag(self):
781 self.mock_path_exists.return_value = True
782
783- git = sources.Git('git://my-source', 'source_dir', source_tag='tag')
784+ git = snapcraft.sources.Git('git://my-source', 'source_dir',
785+ source_tag='tag')
786 git.pull()
787
788 self.mock_run.assert_called_once_with(
789@@ -178,8 +185,8 @@
790 def test_pull_existing_with_branch(self):
791 self.mock_path_exists.return_value = True
792
793- git = sources.Git('git://my-source', 'source_dir',
794- source_branch='my-branch')
795+ git = snapcraft.sources.Git('git://my-source', 'source_dir',
796+ source_branch='my-branch')
797 git.pull()
798
799 self.mock_run.assert_called_once_with(
800@@ -187,16 +194,17 @@
801 'refs/heads/my-branch'], cwd=os.getcwd())
802
803 def test_provision(self):
804- bzr = sources.Git('git://my-source', 'source_dir')
805+ bzr = snapcraft.sources.Git('git://my-source', 'source_dir')
806 bzr.provision('dst')
807
808 self.mock_run.assert_called_once_with(
809 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())
810
811 def test_init_with_source_branch_and_tag_raises_exception(self):
812- with self.assertRaises(sources.IncompatibleOptionsError) as raised:
813- sources.Git('git://mysource', 'source_dir', source_tag='tag',
814- source_branch='branch')
815+ with self.assertRaises(
816+ snapcraft.sources.IncompatibleOptionsError) as raised:
817+ snapcraft.sources.Git('git://mysource', 'source_dir',
818+ source_tag='tag', source_branch='branch')
819
820 expected_message = \
821 'can\'t specify both source-tag and source-branch for a git source'
822@@ -206,15 +214,15 @@
823 class TestMercurial(SourceTestCase):
824
825 def test_pull(self):
826- hg = sources.Mercurial('hg://my-source', 'source_dir')
827+ hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir')
828 hg.pull()
829
830 self.mock_run.assert_called_once_with(
831 ['hg', 'clone', 'hg://my-source', 'source_dir'], cwd=os.getcwd())
832
833 def test_pull_branch(self):
834- hg = sources.Mercurial('hg://my-source', 'source_dir',
835- source_branch='my-branch')
836+ hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
837+ source_branch='my-branch')
838 hg.pull()
839
840 self.mock_run.assert_called_once_with(
841@@ -222,8 +230,8 @@
842 'source_dir'], cwd=os.getcwd())
843
844 def test_pull_tag(self):
845- hg = sources.Mercurial('hg://my-source', 'source_dir',
846- source_tag='tag')
847+ hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
848+ source_tag='tag')
849 hg.pull()
850
851 self.mock_run.assert_called_once_with(
852@@ -233,7 +241,7 @@
853 def test_pull_existing(self):
854 self.mock_path_exists.return_value = True
855
856- hg = sources.Mercurial('hg://my-source', 'source_dir')
857+ hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir')
858 hg.pull()
859
860 self.mock_run.assert_called_once_with(
861@@ -242,8 +250,8 @@
862 def test_pull_existing_with_tag(self):
863 self.mock_path_exists.return_value = True
864
865- hg = sources.Mercurial('hg://my-source', 'source_dir',
866- source_tag='tag')
867+ hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
868+ source_tag='tag')
869 hg.pull()
870
871 self.mock_run.assert_called_once_with(
872@@ -252,8 +260,8 @@
873 def test_pull_existing_with_branch(self):
874 self.mock_path_exists.return_value = True
875
876- hg = sources.Mercurial('hg://my-source', 'source_dir',
877- source_branch='my-branch')
878+ hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
879+ source_branch='my-branch')
880 hg.pull()
881
882 self.mock_run.assert_called_once_with(
883@@ -261,16 +269,18 @@
884 cwd=os.getcwd())
885
886 def test_provision(self):
887- bzr = sources.Mercurial('hg://my-source', 'source_dir')
888+ bzr = snapcraft.sources.Mercurial('hg://my-source', 'source_dir')
889 bzr.provision('dst')
890
891 self.mock_run.assert_called_once_with(
892 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())
893
894 def test_init_with_source_branch_and_tag_raises_exception(self):
895- with self.assertRaises(sources.IncompatibleOptionsError) as raised:
896- sources.Mercurial('hg://mysource', 'source_dir', source_tag='tag',
897- source_branch='branch')
898+ with self.assertRaises(
899+ snapcraft.sources.IncompatibleOptionsError) as raised:
900+ snapcraft.sources.Mercurial(
901+ 'hg://mysource', 'source_dir', source_tag='tag',
902+ source_branch='branch')
903
904 expected_message = (
905 'can\'t specify both source-tag and source-branch for a mercurial '
906@@ -303,11 +313,11 @@
907 self.addCleanup(patcher.stop)
908
909 def test_pull(self):
910- local = sources.Local('.', 'source_dir')
911+ local = snapcraft.sources.Local('.', 'source_dir')
912 self.assertTrue(local.pull())
913
914 def test_provision(self):
915- local = sources.Local('.', 'source_dir')
916+ local = snapcraft.sources.Local('.', 'source_dir')
917 local.provision('dst')
918
919 self.mock_rmdir.assert_called_once_with('dst')
920@@ -317,9 +327,25 @@
921 def test_provision_when_target_is_file(self):
922 self.mock_isdir.return_value = False
923
924- local = sources.Local('.', 'source_dir')
925+ local = snapcraft.sources.Local('.', 'source_dir')
926 local.provision('dst')
927
928 self.mock_remove.assert_called_once_with('dst')
929 self.mock_symlink.assert_called_once_with(
930 '/home/ubuntu/sources/snap/source', 'dst')
931+
932+
933+class TestUri(tests.TestCase):
934+
935+ def test_get_tar_source_from_uri(self):
936+ sources = [
937+ 'https://golang.tar.gz',
938+ 'https://golang.tar.xz',
939+ 'https://golang.tar.bz2',
940+ 'https://golang.tar.tgz',
941+ ]
942+
943+ for source in sources:
944+ with self.subTest(key=source):
945+ self.assertEqual(
946+ snapcraft.sources._get_source_type_from_uri(source), 'tar')

Subscribers

People subscribed via source and target branches