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
=== modified file 'snapcraft/__init__.py'
--- snapcraft/__init__.py 2015-10-14 20:00:25 +0000
+++ snapcraft/__init__.py 2015-10-19 19:01:20 +0000
@@ -17,7 +17,6 @@
17import contextlib17import contextlib
18import logging18import logging
19import os19import os
20import re
2120
22import snapcraft.common21import snapcraft.common
23import snapcraft.sources22import snapcraft.sources
@@ -31,15 +30,14 @@
3130
32 @classmethod31 @classmethod
33 def schema(cls):32 def schema(cls):
34 '''33 """Return a json-schema for the plugin's properties as a dictionary.
35 Returns a json-schema for the plugin's properties as a dictionary.
36 Of importance to plugin authors is the 'properties' keyword and34 Of importance to plugin authors is the 'properties' keyword and
37 optionally the 'requires' keyword with a list of required35 optionally the 'requires' keyword with a list of required
38 'properties'.36 'properties'.
3937
40 By default the the properties will be that of a standard VCS, override38 By default the the properties will be that of a standard VCS, override
41 in custom implementations if required.39 in custom implementations if required.
42 '''40 """
43 return {41 return {
44 '$schema': 'http://json-schema.org/draft-04/schema#',42 '$schema': 'http://json-schema.org/draft-04/schema#',
45 'type': 'object',43 'type': 'object',
@@ -67,6 +65,7 @@
6765
68 @property66 @property
69 def PLUGIN_STAGE_SOURCES(self):67 def PLUGIN_STAGE_SOURCES(self):
68 """Define additional sources.list."""
70 return getattr(self, '_PLUGIN_STAGE_SOURCES', [])69 return getattr(self, '_PLUGIN_STAGE_SOURCES', [])
7170
72 def __init__(self, name, options):71 def __init__(self, name, options):
@@ -92,19 +91,74 @@
9291
93 # The API92 # The API
94 def pull(self):93 def pull(self):
95 return True94 """Pull the source code and/or internal prereqs to build the part.
95
96 By default, the base implementation for pull will use the following
97 part properties to retrieve source code:
98
99 - source
100 - source-branch
101 - source-tag
102 - source-type
103
104 If source is empty or does not exist, the phase will be skipped.
105
106 Override or inherit from this method if you need to implement or
107 enhance with custom pull logic.
108 """
109 if not getattr(self.options, 'source', None):
110 return True
111 try:
112 return snapcraft.sources.get(
113 self.sourcedir, self.builddir, self.options)
114 except ValueError as e:
115 logger.error('Unrecognized source %r for part %r: %s.',
116 self.options.source, self.name, e)
117 snapcraft.common.fatal()
118 except snapcraft.sources.IncompatibleOptionsError as e:
119 logger.error(
120 'Issues while setting up sources for part \'%s\': %s.',
121 self.name,
122 e.message)
123 snapcraft.common.fatal()
96124
97 def build(self):125 def build(self):
126 """Build the source code retrieved from the pull phase.
127
128 The base implementation does nothing by default. Override this method
129 if you need to process the source code to make it runnable.
130 """
98 return True131 return True
99132
100 def snap_fileset(self):133 def snap_fileset(self):
101 """Returns one iteratables of globs specific to the plugin:134 """Return a list of files to include or exclude in the resulting snap
135
136 The staging phase of a plugin's lifecycle may populate many things
137 into the staging directory in order to succeed in building a project.
138 During the stripping phase and in order to have a clean snap, the
139 plugin can provide additional logic for stripping build components
140 from the final snap and alleviate the part author from doing so for
141 repetetive filesets.
142
143 These are the rules to honor when creating such list:
144
102 - includes can be just listed145 - includes can be just listed
103 - excludes must be preceded by -146 - excludes must be preceded by -
104 For example: (['bin', 'lib', '-include'])"""147
148 For example::
149 (['bin', 'lib', '-include'])
150 """
105 return ([])151 return ([])
106152
107 def env(self, root):153 def env(self, root):
154 """Return a list with the execution environment for building.
155
156 Plugins often need special environment variables exported to the
157 system for some builds to take place. This is a list of strings
158 of the form key=value. The parameter root is the path to this part.
159
160 :param str root: The root for the part
161 """
108 return []162 return []
109163
110 # Helpers164 # Helpers
@@ -113,7 +167,7 @@
113 cwd = self.builddir167 cwd = self.builddir
114 if True:168 if True:
115 print(' '.join(cmd))169 print(' '.join(cmd))
116 self.makedirs(cwd)170 os.makedirs(cwd, exist_ok=True)
117 return snapcraft.common.run(cmd, cwd=cwd, **kwargs)171 return snapcraft.common.run(cmd, cwd=cwd, **kwargs)
118172
119 def run_output(self, cmd, cwd=None, **kwargs):173 def run_output(self, cmd, cwd=None, **kwargs):
@@ -121,96 +175,5 @@
121 cwd = self.builddir175 cwd = self.builddir
122 if True:176 if True:
123 print(' '.join(cmd))177 print(' '.join(cmd))
124 self.makedirs(cwd)178 os.makedirs(cwd, exist_ok=True)
125 return snapcraft.common.run_output(cmd, cwd=cwd, **kwargs)179 return snapcraft.common.run_output(cmd, cwd=cwd, **kwargs)
126
127 def isurl(self, url):
128 return snapcraft.common.isurl(url)
129
130 def get_source(self, source, source_type=None, source_tag=None,
131 source_branch=None):
132 try:
133 handler_class = _get_source_handler(source_type, source)
134 except ValueError as e:
135 logger.error('Unrecognized source %r for part %r: %s.', source,
136 self.name, e)
137 snapcraft.common.fatal()
138
139 try:
140 handler = handler_class(source, self.sourcedir, source_tag,
141 source_branch)
142 except snapcraft.sources.IncompatibleOptionsError as e:
143 logger.error(
144 'Issues while setting up sources for part \'%s\': %s.',
145 self.name,
146 e.message)
147 snapcraft.common.fatal()
148 if not handler.pull():
149 return False
150 return handler.provision(self.builddir)
151
152 def handle_source_options(self):
153 stype = getattr(self.options, 'source_type', None)
154 stag = getattr(self.options, 'source_tag', None)
155 sbranch = getattr(self.options, 'source_branch', None)
156 return self.get_source(self.options.source,
157 source_type=stype,
158 source_tag=stag,
159 source_branch=sbranch)
160
161 def makedirs(self, d):
162 os.makedirs(d, exist_ok=True)
163
164 def setup_stage_packages(self):
165 if self.stage_packages:
166 ubuntu = snapcraft.repo.Ubuntu(self.ubuntudir,
167 sources=self.PLUGIN_STAGE_SOURCES)
168 ubuntu.get(self.stage_packages)
169 ubuntu.unpack(self.installdir)
170 self._fixup(self.installdir)
171
172 def _fixup(self, root):
173 if os.path.isfile(os.path.join(root, 'usr', 'bin', 'xml2-config')):
174 self.run(
175 ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
176 format(root),
177 os.path.join(root, 'usr', 'bin', 'xml2-config')])
178 if os.path.isfile(os.path.join(root, 'usr', 'bin', 'xslt-config')):
179 self.run(
180 ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
181 format(root),
182 os.path.join(root, 'usr', 'bin', 'xslt-config')])
183
184
185def _get_source_handler(source_type, source):
186 if not source_type:
187 source_type = _get_source_type_from_uri(source)
188
189 if source_type == 'bzr':
190 handler = snapcraft.sources.Bazaar
191 elif source_type == 'git':
192 handler = snapcraft.sources.Git
193 elif source_type == 'mercurial' or source_type == 'hg':
194 handler = snapcraft.sources.Mercurial
195 elif source_type == 'tar':
196 handler = snapcraft.sources.Tar
197 else:
198 handler = snapcraft.sources.Local
199
200 return handler
201
202
203def _get_source_type_from_uri(source):
204 source_type = ''
205 if source.startswith("bzr:") or source.startswith("lp:"):
206 source_type = 'bzr'
207 elif source.startswith("git:"):
208 source_type = 'git'
209 elif re.compile(r'.*\.((tar\.(xz|gz|bz2))|tgz)$').match(source):
210 source_type = 'tar'
211 elif snapcraft.common.isurl(source):
212 raise ValueError('No handler to manage source')
213 elif not os.path.isdir(source):
214 raise ValueError('Local source is not a directory')
215
216 return source_type
217180
=== modified file 'snapcraft/plugin.py'
--- snapcraft/plugin.py 2015-10-15 17:01:43 +0000
+++ snapcraft/plugin.py 2015-10-19 19:01:20 +0000
@@ -137,6 +137,13 @@
137 with open(self.statefile, 'w+') as f:137 with open(self.statefile, 'w+') as f:
138 f.write(stage)138 f.write(stage)
139139
140 def _setup_stage_packages(self):
141 if self.code.stage_packages:
142 ubuntu = snapcraft.repo.Ubuntu(
143 self.code.ubuntudir, sources=self.code.PLUGIN_STAGE_SOURCES)
144 ubuntu.get(self.code.stage_packages)
145 ubuntu.unpack(self.code.installdir)
146
140 def pull(self, force=False):147 def pull(self, force=False):
141 if not self.should_stage_run('pull', force):148 if not self.should_stage_run('pull', force):
142 return True149 return True
@@ -145,7 +152,7 @@
145 self.notify_stage("Pulling")152 self.notify_stage("Pulling")
146153
147 try:154 try:
148 self.code.setup_stage_packages()155 self._setup_stage_packages()
149 except repo.PackageNotFoundError as e:156 except repo.PackageNotFoundError as e:
150 logger.error(e.message)157 logger.error(e.message)
151 return False158 return False
152159
=== modified file 'snapcraft/plugins/ant.py'
--- snapcraft/plugins/ant.py 2015-10-09 17:43:20 +0000
+++ snapcraft/plugins/ant.py 2015-10-19 19:01:20 +0000
@@ -33,10 +33,6 @@
33 super().__init__(name, options)33 super().__init__(name, options)
34 self.build_packages.append('ant')34 self.build_packages.append('ant')
3535
36 def pull(self):
37 super().pull()
38 return self.handle_source_options()
39
40 def build(self):36 def build(self):
41 super().build()37 super().build()
42 if not self.run(['ant']):38 if not self.run(['ant']):
4339
=== modified file 'snapcraft/plugins/catkin.py'
--- snapcraft/plugins/catkin.py 2015-10-16 19:05:42 +0000
+++ snapcraft/plugins/catkin.py 2015-10-19 19:01:20 +0000
@@ -20,6 +20,7 @@
20import logging20import logging
2121
22import snapcraft22import snapcraft
23import snapcraft.repo
2324
24logger = logging.getLogger(__name__)25logger = logging.getLogger(__name__)
2526
@@ -61,6 +62,19 @@
61 self.dependencies = ['ros-core']62 self.dependencies = ['ros-core']
62 self.package_deps_found = False63 self.package_deps_found = False
63 self.package_local_deps = {}64 self.package_local_deps = {}
65 self._deb_packages = []
66
67 def pull(self):
68 if not super().pull():
69 return False
70
71 try:
72 self._setup_deb_packages()
73 except snapcraft.repo.PackageNotFoundError as e:
74 logger.error(e.message)
75 return False
76
77 return True
6478
65 def env(self, root):79 def env(self, root):
66 return [80 return [
@@ -124,19 +138,18 @@
124 self.package_local_deps[pkg].add(dep)138 self.package_local_deps[pkg].add(dep)
125 continue139 continue
126140
127 # If we're already getting this through a stage package,141 # If we're already getting this through a deb package,
128 # we don't need it142 # we don't need it
129 if self.options.stage_packages and (143 if (dep in self._deb_packages or
130 dep in self.options.stage_packages or144 dep.replace('_', '-') in self._deb_packages):
131 dep.replace('_', '-') in self.options.stage_packages):
132 continue145 continue
133146
134 # Get the ROS package for it147 # Get the ROS package for it
135 self.stage_packages.append(148 self._deb_packages.append(
136 'ros-'+self.options.rosversion+'-'+dep.replace('_', '-'))149 'ros-'+self.options.rosversion+'-'+dep.replace('_', '-'))
137150
138 if dep == 'roscpp':151 if dep == 'roscpp':
139 self.stage_packages.append('g++')152 self._deb_packages.append('g++')
140153
141 def _find_package_deps(self):154 def _find_package_deps(self):
142 if self.package_deps_found:155 if self.package_deps_found:
@@ -158,13 +171,14 @@
158171
159 self.package_deps_found = True172 self.package_deps_found = True
160173
161 def setup_stage_packages(self):174 def _setup_deb_packages(self):
162 if not self.handle_source_options():
163 return False
164
165 self._find_package_deps()175 self._find_package_deps()
166176
167 return super().setup_stage_packages()177 if self._deb_packages:
178 ubuntu = snapcraft.repo.Ubuntu(
179 self.ubuntudir, sources=self.PLUGIN_STAGE_SOURCES)
180 ubuntu.get(self._deb_packages)
181 ubuntu.unpack(self.installdir)
168182
169 def _rosrun(self, commandlist, cwd=None):183 def _rosrun(self, commandlist, cwd=None):
170 with tempfile.NamedTemporaryFile(mode='w') as f:184 with tempfile.NamedTemporaryFile(mode='w') as f:
171185
=== modified file 'snapcraft/plugins/jdk.py'
--- snapcraft/plugins/jdk.py 2015-10-09 02:18:59 +0000
+++ snapcraft/plugins/jdk.py 2015-10-19 19:01:20 +0000
@@ -23,6 +23,9 @@
23 super().__init__(name, options)23 super().__init__(name, options)
24 self.stage_packages.append('default-jdk')24 self.stage_packages.append('default-jdk')
2525
26 def pull(self):
27 return True
28
26 def env(self, root):29 def env(self, root):
27 return ['JAVA_HOME=%s/usr/lib/jvm/default-java' % root,30 return ['JAVA_HOME=%s/usr/lib/jvm/default-java' % root,
28 'PATH=%s/usr/lib/jvm/default-java/bin:'31 'PATH=%s/usr/lib/jvm/default-java/bin:'
2932
=== modified file 'snapcraft/plugins/make.py'
--- snapcraft/plugins/make.py 2015-10-09 17:43:20 +0000
+++ snapcraft/plugins/make.py 2015-10-19 19:01:20 +0000
@@ -23,9 +23,6 @@
23 super().__init__(name, options)23 super().__init__(name, options)
24 self.build_packages.append('make')24 self.build_packages.append('make')
2525
26 def pull(self):
27 return self.handle_source_options()
28
29 def build(self):26 def build(self):
30 return self.run(['make']) and \27 return self.run(['make']) and \
31 self.run(['make', 'install', 'DESTDIR=' + self.installdir])28 self.run(['make', 'install', 'DESTDIR=' + self.installdir])
3229
=== modified file 'snapcraft/plugins/maven.py'
--- snapcraft/plugins/maven.py 2015-10-09 17:43:20 +0000
+++ snapcraft/plugins/maven.py 2015-10-19 19:01:20 +0000
@@ -32,10 +32,6 @@
32 super().__init__(name, options)32 super().__init__(name, options)
33 self.build_packages.append('maven')33 self.build_packages.append('maven')
3434
35 def pull(self):
36 super().pull()
37 return self.handle_source_options()
38
39 def build(self):35 def build(self):
40 super().build()36 super().build()
4137
4238
=== modified file 'snapcraft/plugins/python2.py'
--- snapcraft/plugins/python2.py 2015-10-09 17:43:20 +0000
+++ snapcraft/plugins/python2.py 2015-10-19 19:01:20 +0000
@@ -45,7 +45,7 @@
45 root, 'usr', 'lib', self.python_version, 'dist-packages')]45 root, 'usr', 'lib', self.python_version, 'dist-packages')]
4646
47 def pull(self):47 def pull(self):
48 if self.options.source and not self.handle_source_options():48 if not super().pull():
49 return False49 return False
5050
51 return self._pip()51 return self._pip()
5252
=== modified file 'snapcraft/plugins/python3.py'
--- snapcraft/plugins/python3.py 2015-10-09 17:43:20 +0000
+++ snapcraft/plugins/python3.py 2015-10-19 19:01:20 +0000
@@ -45,7 +45,7 @@
45 root, 'usr', 'lib', self.python_version, 'dist-packages')]45 root, 'usr', 'lib', self.python_version, 'dist-packages')]
4646
47 def pull(self):47 def pull(self):
48 if self.options.source and not self.handle_source_options():48 if not super().pull():
49 return False49 return False
5050
51 return self._pip()51 return self._pip()
5252
=== modified file 'snapcraft/plugins/scons.py'
--- snapcraft/plugins/scons.py 2015-10-09 17:43:20 +0000
+++ snapcraft/plugins/scons.py 2015-10-19 19:01:20 +0000
@@ -40,9 +40,6 @@
40 super().__init__(name, options)40 super().__init__(name, options)
41 self.build_packages.append('scons')41 self.build_packages.append('scons')
4242
43 def pull(self):
44 return self.handle_source_options()
45
46 def build(self):43 def build(self):
47 env = os.environ.copy()44 env = os.environ.copy()
48 env['DESTDIR'] = self.installdir45 env['DESTDIR'] = self.installdir
4946
=== modified file 'snapcraft/repo.py'
--- snapcraft/repo.py 2015-10-16 20:38:56 +0000
+++ snapcraft/repo.py 2015-10-19 19:01:20 +0000
@@ -135,6 +135,7 @@
135 raise UnpackError(pkg)135 raise UnpackError(pkg)
136136
137 _fix_contents(rootdir)137 _fix_contents(rootdir)
138 _fix_xml_tools(rootdir)
138139
139 def _manifest_dep_names(self):140 def _manifest_dep_names(self):
140 manifest_dep_names = set()141 manifest_dep_names = set()
@@ -252,6 +253,20 @@
252 _fix_filemode(path)253 _fix_filemode(path)
253254
254255
256def _fix_xml_tools(root):
257 xml2_config_path = os.path.join(root, 'usr', 'bin', 'xml2-config')
258 if os.path.isfile(xml2_config_path):
259 snapcraft.common.run(
260 ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
261 format(root), xml2_config_path])
262
263 xslt_config_path = os.path.join(root, 'usr', 'bin', 'xslt-config')
264 if os.path.isfile(xslt_config_path):
265 snapcraft.common.run(
266 ['sed', '-i', '-e', 's|prefix=/usr|prefix={}/usr|'.
267 format(root), xslt_config_path])
268
269
255def _fix_filemode(path):270def _fix_filemode(path):
256 mode = stat.S_IMODE(os.stat(path).st_mode)271 mode = stat.S_IMODE(os.stat(path).st_mode)
257 if mode & 0o4000 or mode & 0o2000:272 if mode & 0o4000 or mode & 0o2000:
258273
=== modified file 'snapcraft/sources.py'
--- snapcraft/sources.py 2015-10-14 18:14:47 +0000
+++ snapcraft/sources.py 2015-10-19 19:01:20 +0000
@@ -227,3 +227,51 @@
227 os.symlink(path, dst)227 os.symlink(path, dst)
228228
229 return True229 return True
230
231
232def get(sourcedir, builddir, options):
233 source_type = getattr(options, 'source_type', None)
234 source_tag = getattr(options, 'source_tag', None)
235 source_branch = getattr(options, 'source_branch', None)
236
237 handler_class = _get_source_handler(source_type, options.source)
238 handler = handler_class(options.source, sourcedir, source_tag,
239 source_branch)
240 if not handler.pull():
241 return False
242 return handler.provision(builddir)
243
244
245_source_handler = {
246 'bzr': Bazaar,
247 'git': Git,
248 'hg': Mercurial,
249 'mercurial': Mercurial,
250 'tar': Tar,
251}
252
253
254def _get_source_handler(source_type, source):
255 if not source_type:
256 source_type = _get_source_type_from_uri(source)
257
258 return _source_handler.get(source_type, Local)
259
260
261_tar_type_regex = re.compile(r'.*\.((tar\.(xz|gz|bz2))|tgz)$')
262
263
264def _get_source_type_from_uri(source):
265 source_type = ''
266 if source.startswith("bzr:") or source.startswith("lp:"):
267 source_type = 'bzr'
268 elif source.startswith("git:"):
269 source_type = 'git'
270 elif _tar_type_regex.match(source):
271 source_type = 'tar'
272 elif snapcraft.common.isurl(source):
273 raise ValueError('No handler to manage source')
274 elif not os.path.isdir(source):
275 raise ValueError('Local source is not a directory')
276
277 return source_type
230278
=== modified file 'snapcraft/tests/test_base_plugin.py'
--- snapcraft/tests/test_base_plugin.py 2015-10-14 20:00:25 +0000
+++ snapcraft/tests/test_base_plugin.py 2015-10-19 19:01:20 +0000
@@ -16,30 +16,32 @@
1616
17import fixtures17import fixtures
18import logging18import logging
19import os
20import unittest.mock19import unittest.mock
2120
22import snapcraft21import snapcraft
23from snapcraft import tests22from snapcraft import tests
2423
2524
25class MockOptions:
26
27 def __init__(self, source, source_type=None, source_branch=None,
28 source_tag=None):
29 self.source = source
30 self.source_type = source_type
31 self.source_branch = source_branch
32 self.source_tag = source_tag
33
34
26class TestBasePlugin(tests.TestCase):35class TestBasePlugin(tests.TestCase):
2736
28 def test_isurl(self):
29 plugin = snapcraft.BasePlugin('mock', {})
30 self.assertTrue(plugin.isurl('git://'))
31 self.assertTrue(plugin.isurl('bzr://'))
32 self.assertFalse(plugin.isurl('./'))
33 self.assertFalse(plugin.isurl('/foo'))
34 self.assertFalse(plugin.isurl('/fo:o'))
35
36 def test_get_source_with_unrecognized_source_must_raise_error(self):37 def test_get_source_with_unrecognized_source_must_raise_error(self):
37 fake_logger = fixtures.FakeLogger(level=logging.ERROR)38 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
38 self.useFixture(fake_logger)39 self.useFixture(fake_logger)
3940
40 plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')41 options = MockOptions('unrecognized://test_source')
42 plugin = snapcraft.BasePlugin('test_plugin', options)
41 with self.assertRaises(SystemExit) as raised:43 with self.assertRaises(SystemExit) as raised:
42 plugin.get_source('unrecognized://test_source')44 plugin.pull()
4345
44 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')46 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
45 expected = (47 expected = (
@@ -52,10 +54,11 @@
52 fake_logger = fixtures.FakeLogger(level=logging.ERROR)54 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
53 self.useFixture(fake_logger)55 self.useFixture(fake_logger)
5456
57 options = MockOptions('file')
55 mock_isdir.return_value = False58 mock_isdir.return_value = False
56 plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')59 plugin = snapcraft.BasePlugin('test_plugin', options)
57 with self.assertRaises(SystemExit) as raised:60 with self.assertRaises(SystemExit) as raised:
58 plugin.get_source('file')61 plugin.pull()
5962
60 mock_isdir.assert_called_once_with('file')63 mock_isdir.assert_called_once_with('file')
61 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')64 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
@@ -64,30 +67,6 @@
64 "Local source is not a directory.\n")67 "Local source is not a directory.\n")
65 self.assertEqual(expected, fake_logger.output)68 self.assertEqual(expected, fake_logger.output)
6669
67 def test_makedirs_with_existing_dir(self):
68 plugin = snapcraft.BasePlugin('dummy_plugin', 'dummy_options')
69 plugin.makedirs(self.path)
70 self.assertTrue(os.path.exists(self.path))
71
72 def test_makedirs_with_unexisting_dir(self):
73 path = os.path.join(self.path, 'unexisting')
74 plugin = snapcraft.BasePlugin('dummy_plugin', 'dummy_options')
75 plugin.makedirs(path)
76 self.assertTrue(os.path.exists(path))
77
78 def test_get_tar_source_from_uri(self):
79 sources = [
80 'https://golang.tar.gz',
81 'https://golang.tar.xz',
82 'https://golang.tar.bz2',
83 'https://golang.tar.tgz',
84 ]
85
86 for source in sources:
87 with self.subTest(key=source):
88 self.assertEqual(
89 snapcraft._get_source_type_from_uri(source), 'tar')
90
9170
92class GetSourceWithBranches(tests.TestCase):71class GetSourceWithBranches(tests.TestCase):
9372
@@ -108,11 +87,11 @@
108 fake_logger = fixtures.FakeLogger(level=logging.ERROR)87 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
109 self.useFixture(fake_logger)88 self.useFixture(fake_logger)
11089
111 plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')90 options = MockOptions('lp:source', self.source_type,
91 self.source_branch, self.source_tag)
92 plugin = snapcraft.BasePlugin('test_plugin', options)
112 with self.assertRaises(SystemExit) as raised:93 with self.assertRaises(SystemExit) as raised:
113 plugin.get_source(94 plugin.pull()
114 'dummy_source', source_type=self.source_type,
115 source_branch=self.source_branch, source_tag=self.source_tag)
11695
117 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')96 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
118 expected = (97 expected = (
@@ -146,11 +125,12 @@
146 fake_logger = fixtures.FakeLogger(level=logging.ERROR)125 fake_logger = fixtures.FakeLogger(level=logging.ERROR)
147 self.useFixture(fake_logger)126 self.useFixture(fake_logger)
148127
149 plugin = snapcraft.BasePlugin('test_plugin', 'dummy_options')128 options = MockOptions('lp:this', self.source_type, self.source_branch,
129 self.source_tag)
130 plugin = snapcraft.BasePlugin('test_plugin', options)
131
150 with self.assertRaises(SystemExit) as raised:132 with self.assertRaises(SystemExit) as raised:
151 plugin.get_source(133 plugin.pull()
152 'dummy_source', source_type=self.source_type,
153 source_branch=self.source_branch, source_tag=self.source_tag)
154134
155 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')135 self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
156 expected = (136 expected = (
157137
=== modified file 'snapcraft/tests/test_common.py'
--- snapcraft/tests/test_common.py 2015-07-23 17:26:18 +0000
+++ snapcraft/tests/test_common.py 2015-10-19 19:01:20 +0000
@@ -40,3 +40,10 @@
40 plugindir = os.path.join(self.path, 'testplugin')40 plugindir = os.path.join(self.path, 'testplugin')
41 common.set_plugindir(plugindir)41 common.set_plugindir(plugindir)
42 self.assertEqual(plugindir, common.get_plugindir())42 self.assertEqual(plugindir, common.get_plugindir())
43
44 def test_isurl(self):
45 self.assertTrue(common.isurl('git://'))
46 self.assertTrue(common.isurl('bzr://'))
47 self.assertFalse(common.isurl('./'))
48 self.assertFalse(common.isurl('/foo'))
49 self.assertFalse(common.isurl('/fo:o'))
4350
=== modified file 'snapcraft/tests/test_plugin.py'
--- snapcraft/tests/test_plugin.py 2015-10-09 17:43:20 +0000
+++ snapcraft/tests/test_plugin.py 2015-10-19 19:01:20 +0000
@@ -52,6 +52,7 @@
52 p.statefile = tempfile.NamedTemporaryFile().name52 p.statefile = tempfile.NamedTemporaryFile().name
53 self.addCleanup(os.remove, p.statefile)53 self.addCleanup(os.remove, p.statefile)
54 p.code = Mock()54 p.code = Mock()
55 p._setup_stage_packages = Mock()
55 # pull once56 # pull once
56 p.pull()57 p.pull()
57 p.code.pull.assert_called()58 p.code.pull.assert_called()
5859
=== modified file 'snapcraft/tests/test_sources.py'
--- snapcraft/tests/test_sources.py 2015-10-14 18:14:47 +0000
+++ snapcraft/tests/test_sources.py 2015-10-19 19:01:20 +0000
@@ -19,7 +19,8 @@
19import threading19import threading
20import unittest.mock20import unittest.mock
2121
22from snapcraft import sources22import snapcraft.sources
23
23from snapcraft import tests24from snapcraft import tests
2425
2526
@@ -56,7 +57,7 @@
56 tar_file_name = 'test.tar'57 tar_file_name = 'test.tar'
57 source = 'http://{}:{}/{file_name}'.format(58 source = 'http://{}:{}/{file_name}'.format(
58 *server.server_address, file_name=tar_file_name)59 *server.server_address, file_name=tar_file_name)
59 tar_source = sources.Tar(source, dest_dir)60 tar_source = snapcraft.sources.Tar(source, dest_dir)
6061
61 self.assertTrue(tar_source.pull())62 self.assertTrue(tar_source.pull())
6263
@@ -87,7 +88,7 @@
87class TestBazaar(SourceTestCase):88class TestBazaar(SourceTestCase):
8889
89 def test_pull(self):90 def test_pull(self):
90 bzr = sources.Bazaar('lp:my-source', 'source_dir')91 bzr = snapcraft.sources.Bazaar('lp:my-source', 'source_dir')
9192
92 bzr.pull()93 bzr.pull()
9394
@@ -96,7 +97,8 @@
96 ['bzr', 'branch', 'lp:my-source', 'source_dir'], cwd=os.getcwd())97 ['bzr', 'branch', 'lp:my-source', 'source_dir'], cwd=os.getcwd())
9798
98 def test_pull_tag(self):99 def test_pull_tag(self):
99 bzr = sources.Bazaar('lp:my-source', 'source_dir', source_tag='tag')100 bzr = snapcraft.sources.Bazaar(
101 'lp:my-source', 'source_dir', source_tag='tag')
100 bzr.pull()102 bzr.pull()
101103
102 self.mock_run.assert_called_once_with(104 self.mock_run.assert_called_once_with(
@@ -106,7 +108,8 @@
106 def test_pull_existing_with_tag(self):108 def test_pull_existing_with_tag(self):
107 self.mock_path_exists.return_value = True109 self.mock_path_exists.return_value = True
108110
109 bzr = sources.Bazaar('lp:my-source', 'source_dir', source_tag='tag')111 bzr = snapcraft.sources.Bazaar(
112 'lp:my-source', 'source_dir', source_tag='tag')
110 bzr.pull()113 bzr.pull()
111114
112 self.mock_run.assert_called_once_with(115 self.mock_run.assert_called_once_with(
@@ -114,15 +117,17 @@
114 'source_dir'], cwd=os.getcwd())117 'source_dir'], cwd=os.getcwd())
115118
116 def test_provision(self):119 def test_provision(self):
117 bzr = sources.Bazaar('lp:my-source', 'source_dir')120 bzr = snapcraft.sources.Bazaar('lp:my-source', 'source_dir')
118 bzr.provision('dst')121 bzr.provision('dst')
119122
120 self.mock_run.assert_called_once_with(123 self.mock_run.assert_called_once_with(
121 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())124 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())
122125
123 def test_init_with_source_branch_raises_exception(self):126 def test_init_with_source_branch_raises_exception(self):
124 with self.assertRaises(sources.IncompatibleOptionsError) as raised:127 with self.assertRaises(
125 sources.Bazaar('lp:mysource', 'source_dir', source_branch='branch')128 snapcraft.sources.IncompatibleOptionsError) as raised:
129 snapcraft.sources.Bazaar('lp:mysource', 'source_dir',
130 source_branch='branch')
126131
127 expected_message = 'can\'t specify a source-branch for a bzr source'132 expected_message = 'can\'t specify a source-branch for a bzr source'
128 self.assertEqual(raised.exception.message, expected_message)133 self.assertEqual(raised.exception.message, expected_message)
@@ -131,7 +136,7 @@
131class TestGit(SourceTestCase):136class TestGit(SourceTestCase):
132137
133 def test_pull(self):138 def test_pull(self):
134 git = sources.Git('git://my-source', 'source_dir')139 git = snapcraft.sources.Git('git://my-source', 'source_dir')
135140
136 git.pull()141 git.pull()
137142
@@ -139,8 +144,8 @@
139 ['git', 'clone', 'git://my-source', 'source_dir'], cwd=os.getcwd())144 ['git', 'clone', 'git://my-source', 'source_dir'], cwd=os.getcwd())
140145
141 def test_pull_branch(self):146 def test_pull_branch(self):
142 git = sources.Git('git://my-source', 'source_dir',147 git = snapcraft.sources.Git('git://my-source', 'source_dir',
143 source_branch='my-branch')148 source_branch='my-branch')
144 git.pull()149 git.pull()
145150
146 self.mock_run.assert_called_once_with(151 self.mock_run.assert_called_once_with(
@@ -148,7 +153,8 @@
148 'source_dir'], cwd=os.getcwd())153 'source_dir'], cwd=os.getcwd())
149154
150 def test_pull_tag(self):155 def test_pull_tag(self):
151 git = sources.Git('git://my-source', 'source_dir', source_tag='tag')156 git = snapcraft.sources.Git('git://my-source', 'source_dir',
157 source_tag='tag')
152 git.pull()158 git.pull()
153159
154 self.mock_run.assert_called_once_with(160 self.mock_run.assert_called_once_with(
@@ -158,7 +164,7 @@
158 def test_pull_existing(self):164 def test_pull_existing(self):
159 self.mock_path_exists.return_value = True165 self.mock_path_exists.return_value = True
160166
161 git = sources.Git('git://my-source', 'source_dir')167 git = snapcraft.sources.Git('git://my-source', 'source_dir')
162 git.pull()168 git.pull()
163169
164 self.mock_run.assert_called_once_with(170 self.mock_run.assert_called_once_with(
@@ -168,7 +174,8 @@
168 def test_pull_existing_with_tag(self):174 def test_pull_existing_with_tag(self):
169 self.mock_path_exists.return_value = True175 self.mock_path_exists.return_value = True
170176
171 git = sources.Git('git://my-source', 'source_dir', source_tag='tag')177 git = snapcraft.sources.Git('git://my-source', 'source_dir',
178 source_tag='tag')
172 git.pull()179 git.pull()
173180
174 self.mock_run.assert_called_once_with(181 self.mock_run.assert_called_once_with(
@@ -178,8 +185,8 @@
178 def test_pull_existing_with_branch(self):185 def test_pull_existing_with_branch(self):
179 self.mock_path_exists.return_value = True186 self.mock_path_exists.return_value = True
180187
181 git = sources.Git('git://my-source', 'source_dir',188 git = snapcraft.sources.Git('git://my-source', 'source_dir',
182 source_branch='my-branch')189 source_branch='my-branch')
183 git.pull()190 git.pull()
184191
185 self.mock_run.assert_called_once_with(192 self.mock_run.assert_called_once_with(
@@ -187,16 +194,17 @@
187 'refs/heads/my-branch'], cwd=os.getcwd())194 'refs/heads/my-branch'], cwd=os.getcwd())
188195
189 def test_provision(self):196 def test_provision(self):
190 bzr = sources.Git('git://my-source', 'source_dir')197 bzr = snapcraft.sources.Git('git://my-source', 'source_dir')
191 bzr.provision('dst')198 bzr.provision('dst')
192199
193 self.mock_run.assert_called_once_with(200 self.mock_run.assert_called_once_with(
194 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())201 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())
195202
196 def test_init_with_source_branch_and_tag_raises_exception(self):203 def test_init_with_source_branch_and_tag_raises_exception(self):
197 with self.assertRaises(sources.IncompatibleOptionsError) as raised:204 with self.assertRaises(
198 sources.Git('git://mysource', 'source_dir', source_tag='tag',205 snapcraft.sources.IncompatibleOptionsError) as raised:
199 source_branch='branch')206 snapcraft.sources.Git('git://mysource', 'source_dir',
207 source_tag='tag', source_branch='branch')
200208
201 expected_message = \209 expected_message = \
202 'can\'t specify both source-tag and source-branch for a git source'210 'can\'t specify both source-tag and source-branch for a git source'
@@ -206,15 +214,15 @@
206class TestMercurial(SourceTestCase):214class TestMercurial(SourceTestCase):
207215
208 def test_pull(self):216 def test_pull(self):
209 hg = sources.Mercurial('hg://my-source', 'source_dir')217 hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir')
210 hg.pull()218 hg.pull()
211219
212 self.mock_run.assert_called_once_with(220 self.mock_run.assert_called_once_with(
213 ['hg', 'clone', 'hg://my-source', 'source_dir'], cwd=os.getcwd())221 ['hg', 'clone', 'hg://my-source', 'source_dir'], cwd=os.getcwd())
214222
215 def test_pull_branch(self):223 def test_pull_branch(self):
216 hg = sources.Mercurial('hg://my-source', 'source_dir',224 hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
217 source_branch='my-branch')225 source_branch='my-branch')
218 hg.pull()226 hg.pull()
219227
220 self.mock_run.assert_called_once_with(228 self.mock_run.assert_called_once_with(
@@ -222,8 +230,8 @@
222 'source_dir'], cwd=os.getcwd())230 'source_dir'], cwd=os.getcwd())
223231
224 def test_pull_tag(self):232 def test_pull_tag(self):
225 hg = sources.Mercurial('hg://my-source', 'source_dir',233 hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
226 source_tag='tag')234 source_tag='tag')
227 hg.pull()235 hg.pull()
228236
229 self.mock_run.assert_called_once_with(237 self.mock_run.assert_called_once_with(
@@ -233,7 +241,7 @@
233 def test_pull_existing(self):241 def test_pull_existing(self):
234 self.mock_path_exists.return_value = True242 self.mock_path_exists.return_value = True
235243
236 hg = sources.Mercurial('hg://my-source', 'source_dir')244 hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir')
237 hg.pull()245 hg.pull()
238246
239 self.mock_run.assert_called_once_with(247 self.mock_run.assert_called_once_with(
@@ -242,8 +250,8 @@
242 def test_pull_existing_with_tag(self):250 def test_pull_existing_with_tag(self):
243 self.mock_path_exists.return_value = True251 self.mock_path_exists.return_value = True
244252
245 hg = sources.Mercurial('hg://my-source', 'source_dir',253 hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
246 source_tag='tag')254 source_tag='tag')
247 hg.pull()255 hg.pull()
248256
249 self.mock_run.assert_called_once_with(257 self.mock_run.assert_called_once_with(
@@ -252,8 +260,8 @@
252 def test_pull_existing_with_branch(self):260 def test_pull_existing_with_branch(self):
253 self.mock_path_exists.return_value = True261 self.mock_path_exists.return_value = True
254262
255 hg = sources.Mercurial('hg://my-source', 'source_dir',263 hg = snapcraft.sources.Mercurial('hg://my-source', 'source_dir',
256 source_branch='my-branch')264 source_branch='my-branch')
257 hg.pull()265 hg.pull()
258266
259 self.mock_run.assert_called_once_with(267 self.mock_run.assert_called_once_with(
@@ -261,16 +269,18 @@
261 cwd=os.getcwd())269 cwd=os.getcwd())
262270
263 def test_provision(self):271 def test_provision(self):
264 bzr = sources.Mercurial('hg://my-source', 'source_dir')272 bzr = snapcraft.sources.Mercurial('hg://my-source', 'source_dir')
265 bzr.provision('dst')273 bzr.provision('dst')
266274
267 self.mock_run.assert_called_once_with(275 self.mock_run.assert_called_once_with(
268 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())276 ['cp', '-Trfa', 'source_dir', 'dst'], cwd=os.getcwd())
269277
270 def test_init_with_source_branch_and_tag_raises_exception(self):278 def test_init_with_source_branch_and_tag_raises_exception(self):
271 with self.assertRaises(sources.IncompatibleOptionsError) as raised:279 with self.assertRaises(
272 sources.Mercurial('hg://mysource', 'source_dir', source_tag='tag',280 snapcraft.sources.IncompatibleOptionsError) as raised:
273 source_branch='branch')281 snapcraft.sources.Mercurial(
282 'hg://mysource', 'source_dir', source_tag='tag',
283 source_branch='branch')
274284
275 expected_message = (285 expected_message = (
276 'can\'t specify both source-tag and source-branch for a mercurial '286 'can\'t specify both source-tag and source-branch for a mercurial '
@@ -303,11 +313,11 @@
303 self.addCleanup(patcher.stop)313 self.addCleanup(patcher.stop)
304314
305 def test_pull(self):315 def test_pull(self):
306 local = sources.Local('.', 'source_dir')316 local = snapcraft.sources.Local('.', 'source_dir')
307 self.assertTrue(local.pull())317 self.assertTrue(local.pull())
308318
309 def test_provision(self):319 def test_provision(self):
310 local = sources.Local('.', 'source_dir')320 local = snapcraft.sources.Local('.', 'source_dir')
311 local.provision('dst')321 local.provision('dst')
312322
313 self.mock_rmdir.assert_called_once_with('dst')323 self.mock_rmdir.assert_called_once_with('dst')
@@ -317,9 +327,25 @@
317 def test_provision_when_target_is_file(self):327 def test_provision_when_target_is_file(self):
318 self.mock_isdir.return_value = False328 self.mock_isdir.return_value = False
319329
320 local = sources.Local('.', 'source_dir')330 local = snapcraft.sources.Local('.', 'source_dir')
321 local.provision('dst')331 local.provision('dst')
322332
323 self.mock_remove.assert_called_once_with('dst')333 self.mock_remove.assert_called_once_with('dst')
324 self.mock_symlink.assert_called_once_with(334 self.mock_symlink.assert_called_once_with(
325 '/home/ubuntu/sources/snap/source', 'dst')335 '/home/ubuntu/sources/snap/source', 'dst')
336
337
338class TestUri(tests.TestCase):
339
340 def test_get_tar_source_from_uri(self):
341 sources = [
342 'https://golang.tar.gz',
343 'https://golang.tar.xz',
344 'https://golang.tar.bz2',
345 'https://golang.tar.tgz',
346 ]
347
348 for source in sources:
349 with self.subTest(key=source):
350 self.assertEqual(
351 snapcraft.sources._get_source_type_from_uri(source), 'tar')

Subscribers

People subscribed via source and target branches