Merge lp:~elopio/snapcraft/fix1476452-python_log into lp:~snappy-dev/snapcraft/core

Proposed by Leo Arias on 2015-07-21
Status: Merged
Approved by: Michael Terry on 2015-07-29
Approved revision: 112
Merged at revision: 110
Proposed branch: lp:~elopio/snapcraft/fix1476452-python_log
Merge into: lp:~snappy-dev/snapcraft/core
Prerequisite: lp:~elopio/snapcraft/test_tmp_cwd
Diff against target: 669 lines (+176/-69)
14 files modified
integration-tests/units/jobs.pxu (+4/-4)
snapcraft/__init__.py (+14/-5)
snapcraft/cmds.py (+9/-5)
snapcraft/common.py (+0/-5)
snapcraft/main.py (+8/-0)
snapcraft/plugin.py (+8/-4)
snapcraft/plugins/ant_project.py (+7/-2)
snapcraft/plugins/copy.py (+5/-1)
snapcraft/plugins/ubuntu.py (+10/-4)
snapcraft/tests/test_cmds.py (+45/-8)
snapcraft/tests/test_copy_plugin.py (+15/-8)
snapcraft/tests/test_plugin.py (+17/-4)
snapcraft/tests/test_yaml.py (+23/-14)
snapcraft/yaml.py (+11/-5)
To merge this branch: bzr merge lp:~elopio/snapcraft/fix1476452-python_log
Reviewer Review Type Date Requested Status
Michael Terry (community) Approve on 2015-07-29
Michael Vogt 2015-07-21 Approve on 2015-07-22
Review via email: mp+265354@code.launchpad.net

Commit Message

Use the python logger.

Description of the Change

The python logger is nice. I've just done the basic config to keep the previous behaviour, but there are many options. At some point we should add an extra handler to send the logs to a file.

By using this logger, now it becomes testable too. I've added some tests, but to add the rest I need to learn a little more about snapcraft.

To post a comment you must log in.
Michael Vogt (mvo) wrote :

Thanks for this branch. I like it and code-wise it looks great, just two comments inline (which are the same) where a small comment might be helpful. I +1 on this branch but I will leave the top-approve to Mike.

review: Approve
Michael Terry (mterry) wrote :

A) This has conflicts now

B) Does this keep the bold text output? I thought that was rather valuable for separating the non-bold output of plugin subprocesses from the bold output of snapcraft itself (bracketing plugin output when going through the stages).

I'd prefer to keep that if possible.

review: Needs Information
Leo Arias (elopio) wrote :

> A) This has conflicts now

and it requires sergio to add fixtures to the machine :(

> B) Does this keep the bold text output? I thought that was rather valuable
> for separating the non-bold output of plugin subprocesses from the bold output
> of snapcraft itself (bracketing plugin output when going through the stages).
>
> I'd prefer to keep that if possible.

No, it doesn't. I can do it with with separate handlers and filters, I think. Let me try.

Leo Arias (elopio) wrote :

> Thanks for this branch. I like it and code-wise it looks great, just two
> comments inline (which are the same) where a small comment might be helpful. I
> +1 on this branch but I will leave the top-approve to Mike.

Thanks for the review. I added comments on all the checks for the return code.

Leo Arias (elopio) wrote :

> A) This has conflicts now

Merged and all tests passing.

> B) Does this keep the bold text output? I thought that was rather valuable
> for separating the non-bold output of plugin subprocesses from the bold output
> of snapcraft itself (bracketing plugin output when going through the stages).
>
> I'd prefer to keep that if possible.

Now the logger format has the bold wrapper. Please check if that's what you wanted.

110. By Leo Arias on 2015-07-28

Merged with trunk.

Michael Terry (mterry) wrote :

From IRC:

<mterry> elopio, looking at your branch -- now some things are bold that weren't before
<mterry> elopio, look at the diff in LP and you can see some things were just print() lines before
 elopio, specifically when we ran a subcommand, it would not be bold
 elopio, and a couple tiny other places
 elopio, what's the cleanest way to distinguish there? Use another logger command than info?

Leo Arias (elopio) wrote :

> From IRC:
>
>
> <mterry> elopio, looking at your branch -- now some things are bold that
> weren't before
> <mterry> elopio, look at the diff in LP and you can see some things were just
> print() lines before
> elopio, specifically when we ran a subcommand, it would not be bold
> elopio, and a couple tiny other places
> elopio, what's the cleanest way to distinguish there? Use another logger
> command than info?l

No, I think the correct way is to define a different logger, like:
subcommand_logger = logging.getLogger(__name__ + '.subcommand')

And then we add a handler to that subcommand_logger that has a formatter without the bold wrapper.
However, if you see at the statements that use print:

66 - print(' '.join(cmd))

141 - snapcraft.common.log("Wrote the following as snapcraft.yaml.")
142 - print()
143 - print(yaml)

170 - print("Installing required packages on the host system: " + ", ".join(newPackages))

I fail to see a pattern in there that we can generalize in a logger. So maybe instead, each call to the logger should decide if it should be wrapped in bold or not. And IMO, instead of using \bold it would be clearer to use the name of the package. Like:

snapcraft log message-1
plugin.ubuntu: ubuntu log message-1
...
plugin.ubuntu: ubuntu log message-n
snapcraft log message-last

In the end, I think we should define a logging policy so we can be consistent on how to use it, and then define the logger hierarchy so it's easy to use. For now, I'll revert those lines to use print so this branch will introduce the loggers while keeping the exact same behaviour as before. And lets start the discussion.

111. By Leo Arias on 2015-07-29

Revert to prints for now to keep the exact same behaviour as before. Pending discussion of a hierarcy of loggers for different sources.

112. By Leo Arias on 2015-07-29

Updated the cmd test.

Michael Terry (mterry) wrote :

Looks good. We can go over the bold/not-bold stuff separately. I'm sure there's a nicer way to distinguish those.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'integration-tests/units/jobs.pxu'
2--- integration-tests/units/jobs.pxu 2015-07-24 16:21:07 +0000
3+++ integration-tests/units/jobs.pxu 2015-07-29 04:38:10 +0000
4@@ -3,7 +3,7 @@
5 estimated_duration: 0.1
6 command:
7 set -x
8- OUTPUT=$(${SNAPCRAFT} pull)
9+ OUTPUT=$(${SNAPCRAFT} pull 2>&1)
10 test $? = 1 || exit 1
11 echo $OUTPUT | grep "Could not find snapcraft\.yaml\."
12
13@@ -13,7 +13,7 @@
14 command:
15 set -x
16 cp -rT $PLAINBOX_PROVIDER_DATA/assemble .
17- OUTPUT=$(${SNAPCRAFT} assemble)
18+ OUTPUT=$(${SNAPCRAFT} assemble 2>&1)
19 test $? = 1 || exit 1
20 echo $OUTPUT | grep "Missing snappy metadata file"
21
22@@ -123,7 +123,7 @@
23 command:
24 set -x
25 cp -rT $PLAINBOX_PROVIDER_DATA/conflicts .
26- OUTPUT=$(${SNAPCRAFT} stage)
27+ OUTPUT=$(${SNAPCRAFT} stage 2>&1)
28 test $? = 1 || exit 1
29 echo $OUTPUT | grep "Error: parts p1 and p2 have the following files in common: bin/test" # squished output by bash
30
31@@ -146,7 +146,7 @@
32 set -x
33 cp -rT $PLAINBOX_PROVIDER_DATA/dependencies .
34 sed -i "s/p1:/p1:\n after: [p3]/" snapcraft.yaml
35- OUTPUT=$(${SNAPCRAFT} pull)
36+ OUTPUT=$(${SNAPCRAFT} pull 2>&1)
37 test $? = 1 || exit 1
38 echo $OUTPUT | grep -i "circular dependency"
39
40
41=== modified file 'snapcraft/__init__.py'
42--- snapcraft/__init__.py 2015-07-24 01:23:44 +0000
43+++ snapcraft/__init__.py 2015-07-29 04:38:10 +0000
44@@ -14,6 +14,7 @@
45 # You should have received a copy of the GNU General Public License
46 # along with this program. If not, see <http://www.gnu.org/licenses/>.
47
48+import logging
49 import os
50 import re
51 import tarfile
52@@ -22,6 +23,9 @@
53 import snapcraft.common
54
55
56+logger = logging.getLogger(__name__)
57+
58+
59 class BasePlugin:
60
61 def __init__(self, name, options):
62@@ -73,7 +77,8 @@
63
64 def pull_git(self, source, source_tag=None, source_branch=None):
65 if source_tag and source_branch:
66- snapcraft.common.fatal("You can't specify both source-tag and source-branch for a git source (part '%s')." % self.name)
67+ logger.error("You can't specify both source-tag and source-branch for a git source (part '%s')." % self.name)
68+ snapcraft.common.fatal()
69
70 if os.path.exists(os.path.join(self.sourcedir, ".git")):
71 refspec = 'HEAD'
72@@ -143,11 +148,13 @@
73 elif source.startswith("git:"):
74 source_type = 'git'
75 elif self.isurl(source):
76- snapcraft.common.fatal("Unrecognized source '%s' for part '%s'." % (source, self.name))
77+ logger.error("Unrecognized source '%s' for part '%s'." % (source, self.name))
78+ snapcraft.common.fatal()
79
80 if source_type == 'bzr':
81 if source_branch:
82- snapcraft.common.fatal("You can't specify source-branch for a bzr source (part '%s')." % self.name)
83+ logger.error("You can't specify source-branch for a bzr source (part '%s')." % self.name)
84+ snapcraft.common.fatal()
85 if not self.pull_bzr(source, source_tag=source_tag):
86 return False
87 if not self.run(['cp', '-Trfa', self.sourcedir, self.builddir]):
88@@ -159,9 +166,11 @@
89 return False
90 elif source_type == 'tar':
91 if source_branch:
92- snapcraft.common.fatal("You can't specify source-branch for a tar source (part '%s')." % self.name)
93+ logger.error("You can't specify source-branch for a tar source (part '%s')." % self.name)
94+ snapcraft.common.fatal()
95 if source_tag:
96- snapcraft.common.fatal("You can't specify source-tag for a tar source (part '%s')." % self.name)
97+ logger.error("You can't specify source-tag for a tar source (part '%s')." % self.name)
98+ snapcraft.common.fatal()
99 if not self.pull_tarball(source):
100 return False
101 if not self.extract_tarball(source):
102
103=== modified file 'snapcraft/cmds.py'
104--- snapcraft/cmds.py 2015-07-22 21:05:20 +0000
105+++ snapcraft/cmds.py 2015-07-29 04:38:10 +0000
106@@ -15,6 +15,7 @@
107 # along with this program. If not, see <http://www.gnu.org/licenses/>.
108
109 import glob
110+import logging
111 import os
112 import shlex
113 import snapcraft.common
114@@ -27,9 +28,12 @@
115 import yaml
116
117
118+logger = logging.getLogger(__name__)
119+
120+
121 def init(args):
122 if os.path.exists("snapcraft.yaml"):
123- snapcraft.common.log("snapcraft.yaml already exists!", file=sys.stderr)
124+ logger.error('snapcraft.yaml already exists!')
125 sys.exit(1)
126 yaml = 'parts:\n'
127 for part_name in args.part:
128@@ -41,7 +45,7 @@
129 yaml = yaml.strip()
130 with open('snapcraft.yaml', mode='w+') as f:
131 f.write(yaml)
132- snapcraft.common.log("Wrote the following as snapcraft.yaml.")
133+ logger.info('Wrote the following as snapcraft.yaml.')
134 print()
135 print(yaml)
136 sys.exit(0)
137@@ -84,7 +88,7 @@
138 snapcraft.common.run(
139 ['cp', '-arvT', config.data['snappy-metadata'], snapcraft.common.snapdir + '/meta'])
140 if not os.path.exists('snap/meta/package.yaml'):
141- snapcraft.common.log("Missing snappy metadata file 'meta/package.yaml'. Try specifying 'snappy-metadata' in snapcraft.yaml, pointing to a meta directory in your source tree.")
142+ logger.error("Missing snappy metadata file 'meta/package.yaml'. Try specifying 'snappy-metadata' in snapcraft.yaml, pointing to a meta directory in your source tree.")
143 sys.exit(1)
144
145 # wrap all included commands
146@@ -186,7 +190,7 @@
147 for otherPartName in partsFiles:
148 common = partFiles & partsFiles[otherPartName]
149 if common:
150- snapcraft.common.log("Error: parts %s and %s have the following files in common:\n %s" % (otherPartName, part.names()[0], '\n '.join(sorted(common))))
151+ logger.error('Error: parts %s and %s have the following files in common:\n %s' % (otherPartName, part.names()[0], '\n '.join(sorted(common))))
152 return False
153
154 # And add our files to the list
155@@ -232,5 +236,5 @@
156 snapcraft.common.env = config.build_env_for_part(part)
157 force = forceAll or cmd == forceCommand
158 if not getattr(part, cmd)(force=force):
159- snapcraft.common.log("Failed doing %s for %s!" % (cmd, part.names()[0]))
160+ logger.error('Failed doing %s for %s!' % (cmd, part.names()[0]))
161 sys.exit(1)
162
163=== modified file 'snapcraft/common.py'
164--- snapcraft/common.py 2015-07-14 21:15:07 +0000
165+++ snapcraft/common.py 2015-07-29 04:38:10 +0000
166@@ -39,12 +39,7 @@
167 return subprocess.call(['/bin/sh', f.name] + cmd, **kwargs) == 0
168
169
170-def log(msg, file=None):
171- print('\033[01m' + msg + '\033[0m', file=None)
172-
173-
174 def fatal(msg):
175- log(msg, file=sys.stderr)
176 sys.exit(1)
177
178
179
180=== modified file 'snapcraft/main.py'
181--- snapcraft/main.py 2015-07-17 17:19:04 +0000
182+++ snapcraft/main.py 2015-07-29 04:38:10 +0000
183@@ -16,12 +16,20 @@
184 # along with this program. If not, see <http://www.gnu.org/licenses/>.
185
186 import argparse
187+import logging
188 import sys
189
190 import snapcraft.cmds
191
192
193+_COLOR_BOLD = '\033[1m'
194+_COLOR_END = '\033[0m'
195+
196+
197 def main():
198+ logging.basicConfig(
199+ format=_COLOR_BOLD + '%(message)s' + _COLOR_END, level=logging.INFO)
200+
201 root_parser = argparse.ArgumentParser()
202 subparsers = root_parser.add_subparsers(dest='cmd')
203
204
205=== modified file 'snapcraft/plugin.py'
206--- snapcraft/plugin.py 2015-07-22 18:59:28 +0000
207+++ snapcraft/plugin.py 2015-07-29 04:38:10 +0000
208@@ -16,6 +16,7 @@
209
210 import glob
211 import importlib
212+import logging
213 import os
214 import snapcraft
215 import snapcraft.common
216@@ -23,6 +24,9 @@
217 import yaml
218
219
220+logger = logging.getLogger(__name__)
221+
222+
223 def is_local_plugin(name):
224 return name.startswith("x-")
225
226@@ -69,7 +73,7 @@
227 def _load_config(self, name):
228 configPath = os.path.join(plugindir(name), name + ".yaml")
229 if not os.path.exists(configPath):
230- snapcraft.common.log("Unknown plugin %s" % name, file=sys.stderr)
231+ logger.error("Unknown plugin %s" % name)
232 raise PluginError()
233 with open(configPath, 'r') as fp:
234 self.config = yaml.load(fp) or {}
235@@ -86,7 +90,7 @@
236 setattr(options, attrname, properties[opt])
237 else:
238 if opt_parameters.get('required', False):
239- snapcraft.common.log("Required field %s missing on part %s" % (opt, name), file=sys.stderr)
240+ logger.error("Required field %s missing on part %s" % (opt, name))
241 raise PluginError()
242 setattr(options, attrname, None)
243
244@@ -147,7 +151,7 @@
245 return self.part_names
246
247 def notify_stage(self, stage, hint=''):
248- snapcraft.common.log(stage + " " + self.part_names[0] + hint)
249+ logger.info(stage + " " + self.part_names[0] + hint)
250
251 def is_dirty(self, stage):
252 try:
253@@ -274,6 +278,6 @@
254 def load_plugin(part_name, plugin_name, properties={}, load_code=True):
255 part = PluginHandler(plugin_name, part_name, properties, load_code=load_code)
256 if not part.is_valid():
257- snapcraft.common.log("Could not load part %s" % plugin_name, file=sys.stderr)
258+ logger.error("Could not load part %s" % plugin_name)
259 sys.exit(1)
260 return part
261
262=== modified file 'snapcraft/plugins/ant_project.py'
263--- snapcraft/plugins/ant_project.py 2015-07-22 18:23:16 +0000
264+++ snapcraft/plugins/ant_project.py 2015-07-29 04:38:10 +0000
265@@ -15,10 +15,15 @@
266 # along with this program. If not, see <http://www.gnu.org/licenses/>.
267
268 import glob
269+import logging
270 import os
271+import sys
272+
273 import snapcraft
274 import snapcraft.common
275-import sys
276+
277+
278+logger = logging.getLogger(__name__)
279
280
281 class AntProjectPlugin(snapcraft.BasePlugin):
282@@ -31,7 +36,7 @@
283 return False
284 files = glob.glob(os.path.join(self.builddir, 'target', '*.jar'))
285 if not files:
286- snapcraft.common.log('Could not find any built jar files for part %s' % self.name)
287+ logger.error('Could not find any built jar files for part %s' % self.name)
288 sys.exit(1)
289 jardir = os.path.join(self.installdir, 'jar')
290 return self.run(['mkdir', '-p', jardir]) and \
291
292=== modified file 'snapcraft/plugins/copy.py'
293--- snapcraft/plugins/copy.py 2015-07-22 14:55:48 +0000
294+++ snapcraft/plugins/copy.py 2015-07-29 04:38:10 +0000
295@@ -14,11 +14,15 @@
296 # You should have received a copy of the GNU General Public License
297 # along with this program. If not, see <http://www.gnu.org/licenses/>.
298
299+import logging
300 import os
301
302 import snapcraft
303
304
305+logger = logging.getLogger(__name__)
306+
307+
308 class CopyPlugin(snapcraft.BasePlugin):
309
310 def build(self):
311@@ -26,7 +30,7 @@
312 for src in sorted(self.options.files):
313 dst = self.options.files[src]
314 if not os.path.lexists(src):
315- snapcraft.common.log("WARNING: file '%s' missing" % src)
316+ logger.warning("WARNING: file '%s' missing" % src)
317 res = False
318 continue
319 dst = os.path.join(self.installdir, dst)
320
321=== modified file 'snapcraft/plugins/ubuntu.py'
322--- snapcraft/plugins/ubuntu.py 2015-07-22 18:23:16 +0000
323+++ snapcraft/plugins/ubuntu.py 2015-07-29 04:38:10 +0000
324@@ -14,12 +14,18 @@
325 # You should have received a copy of the GNU General Public License
326 # along with this program. If not, see <http://www.gnu.org/licenses/>.
327
328-import apt
329+import logging
330 import os
331-import snapcraft.common
332 import subprocess
333 import sys
334
335+import apt
336+
337+import snapcraft.common
338+
339+
340+logger = logging.getLogger(__name__)
341+
342
343 class UbuntuPlugin(snapcraft.BasePlugin):
344
345@@ -32,7 +38,7 @@
346 else:
347 # User didn't specify a package, use the part name
348 if name == 'ubuntu':
349- snapcraft.common.log("Part %s needs either a package option or a name" % name)
350+ logger.error('Part %s needs either a package option or a name' % name)
351 sys.exit(1)
352 self.included_packages.append(name)
353
354@@ -83,7 +89,7 @@
355 for p in packages:
356 if p not in alldeps:
357 exit = True
358- snapcraft.common.log("Package %s not recognized" % p, file=sys.stderr)
359+ logger.error('Package %s not recognized' % p, file=sys.stderr)
360 if exit:
361 sys.exit(1)
362
363
364=== modified file 'snapcraft/tests/test_cmds.py'
365--- snapcraft/tests/test_cmds.py 2015-07-15 09:00:46 +0000
366+++ snapcraft/tests/test_cmds.py 2015-07-29 04:38:10 +0000
367@@ -14,18 +14,23 @@
368 # You should have received a copy of the GNU General Public License
369 # along with this program. If not, see <http://www.gnu.org/licenses/>.
370
371+import logging
372 import os
373 import tempfile
374 from unittest import mock
375
376-from snapcraft.cmds import check_for_collisions
377+import fixtures
378+
379+from snapcraft import cmds
380 from snapcraft.tests import TestCase
381
382
383 class TestCommands(TestCase):
384
385- @mock.patch('snapcraft.common.log')
386- def test_check_for_collisions(self, logmock):
387+ def test_check_for_collisions(self):
388+ fake_logger = fixtures.FakeLogger(level=logging.ERROR)
389+ self.useFixture(fake_logger)
390+
391 tmpdirObject = tempfile.TemporaryDirectory()
392 self.addCleanup(tmpdirObject.cleanup)
393 tmpdir = tmpdirObject.name
394@@ -52,8 +57,40 @@
395 open(part3.installdir + '/1', mode='w').close()
396 open(part3.installdir + '/a/2', mode='w').close()
397
398- self.assertTrue(check_for_collisions([part1, part2]))
399- self.assertFalse(logmock.called)
400-
401- self.assertFalse(check_for_collisions([part1, part2, part3]))
402- logmock.assert_called_with("Error: parts part2 and part3 have the following files in common:\n 1\n a/2")
403+ self.assertTrue(cmds.check_for_collisions([part1, part2]))
404+ self.assertEqual('', fake_logger.output)
405+
406+ self.assertFalse(cmds.check_for_collisions([part1, part2, part3]))
407+ self.assertEqual(
408+ 'Error: parts part2 and part3 have the following files in common:\n'
409+ ' 1\n'
410+ ' a/2\n',
411+ fake_logger.output)
412+
413+
414+class InitTestCase(TestCase):
415+
416+ def test_init_with_existing_snapcraft_yaml_must_fail(self):
417+ fake_logger = fixtures.FakeLogger(level=logging.ERROR)
418+ self.useFixture(fake_logger)
419+
420+ open('snapcraft.yaml', 'w').close()
421+
422+ with self.assertRaises(SystemExit) as raised:
423+ cmds.init('dummy args')
424+ self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
425+ self.assertEqual(
426+ 'snapcraft.yaml already exists!\n', fake_logger.output)
427+
428+ def test_init_without_parts_must_write_snapcraft_yaml(self):
429+ fake_logger = fixtures.FakeLogger(level=logging.INFO)
430+ self.useFixture(fake_logger)
431+
432+ snap_without_parts = type('obj', (object, ), {'part': []})
433+ with self.assertRaises(SystemExit) as raised:
434+ cmds.init(snap_without_parts)
435+
436+ self.assertEqual(raised.exception.code, 0, 'Wrong exit code returned.')
437+ self.assertEqual(
438+ 'Wrote the following as snapcraft.yaml.\n',
439+ fake_logger.output)
440
441=== modified file 'snapcraft/tests/test_copy_plugin.py'
442--- snapcraft/tests/test_copy_plugin.py 2015-07-22 21:05:20 +0000
443+++ snapcraft/tests/test_copy_plugin.py 2015-07-29 04:38:10 +0000
444@@ -14,11 +14,11 @@
445 # You should have received a copy of the GNU General Public License
446 # along with this program. If not, see <http://www.gnu.org/licenses/>.
447
448+import logging
449 import os.path
450-from unittest.mock import (
451- Mock,
452- patch,
453-)
454+from unittest.mock import Mock
455+
456+import fixtures
457
458 from snapcraft.plugins.copy import CopyPlugin
459 from snapcraft.tests import TestCase
460@@ -43,12 +43,17 @@
461 }
462 open("zzz", "w").close()
463 c = CopyPlugin("copy", self.mock_options)
464- with patch("snapcraft.common.log") as mock_log:
465- res = c.build()
466- self.assertFalse(res)
467- mock_log.assert_called_with("WARNING: file 'src' missing")
468+
469+ fake_logger = fixtures.FakeLogger(level=logging.WARNING)
470+ self.useFixture(fake_logger)
471+
472+ res = c.build()
473+ self.assertFalse(res)
474+ self.assertEqual("WARNING: file 'src' missing\n", fake_logger.output)
475
476 def test_copy_plugin_copies(self):
477+ self.useFixture(fixtures.FakeLogger())
478+
479 self.mock_options.files = {
480 "src": "dst",
481 }
482@@ -59,6 +64,8 @@
483 self.assertTrue(os.path.exists(os.path.join(self.dst_prefix, "dst")))
484
485 def test_copy_plugin_creates_prefixes(self):
486+ self.useFixture(fixtures.FakeLogger())
487+
488 self.mock_options.files = {
489 "src": "dir/dst",
490 }
491
492=== modified file 'snapcraft/tests/test_plugin.py'
493--- snapcraft/tests/test_plugin.py 2015-07-22 21:05:20 +0000
494+++ snapcraft/tests/test_plugin.py 2015-07-29 04:38:10 +0000
495@@ -14,25 +14,29 @@
496 # You should have received a copy of the GNU General Public License
497 # along with this program. If not, see <http://www.gnu.org/licenses/>.
498
499+import logging
500 import os
501 import sys
502 import tempfile
503
504+import fixtures
505 from unittest.mock import (
506 Mock,
507 patch,
508 )
509
510+import snapcraft.tests.mock_plugin
511 from snapcraft.plugin import PluginHandler, PluginError
512 from snapcraft.tests import TestCase
513
514-import snapcraft.tests.mock_plugin
515-
516
517 class TestPlugin(TestCase):
518
519+ def get_test_plugin(self):
520+ return PluginHandler('mock', 'mock-part', {}, load_config=False, load_code=False)
521+
522 def test_is_dirty(self):
523- p = PluginHandler("mock", "mock-part", {}, load_config=False, load_code=False)
524+ p = self.get_test_plugin()
525 p.statefile = tempfile.NamedTemporaryFile().name
526 self.addCleanup(os.remove, p.statefile)
527 p.code = Mock()
528@@ -45,7 +49,7 @@
529 self.assertFalse(p.code.pull.called)
530
531 def test_collect_snap_files(self):
532- p = PluginHandler("mock", "mock-part", {}, load_config=False, load_code=False)
533+ p = self.get_test_plugin()
534
535 tmpdirObject = tempfile.TemporaryDirectory()
536 self.addCleanup(tmpdirObject.cleanup)
537@@ -92,6 +96,15 @@
538 set(['1', '1/1a', '1/1a/1b', '2', '2/2a']),
539 set()))
540
541+ def test_notify_stage_must_log_information(self):
542+ fake_logger = fixtures.FakeLogger(level=logging.INFO)
543+ self.useFixture(fake_logger)
544+
545+ plugin = self.get_test_plugin()
546+ plugin.notify_stage('test stage')
547+
548+ self.assertEqual('test stage mock-part\n', fake_logger.output)
549+
550 def test_local_plugins(self):
551 """Ensure local plugins are loaded from parts/plugins"""
552 def mock_import_modules(module_name):
553
554=== modified file 'snapcraft/tests/test_yaml.py'
555--- snapcraft/tests/test_yaml.py 2015-07-17 17:00:18 +0000
556+++ snapcraft/tests/test_yaml.py 2015-07-29 04:38:10 +0000
557@@ -14,15 +14,14 @@
558 # You should have received a copy of the GNU General Public License
559 # along with this program. If not, see <http://www.gnu.org/licenses/>.
560
561+import logging
562 import os
563 import tempfile
564 import unittest
565-from unittest.mock import (
566- patch,
567-)
568+
569+import fixtures
570
571 from snapcraft.yaml import Config
572-
573 from snapcraft.tests import TestCase
574
575
576@@ -46,16 +45,24 @@
577 "package": "fswebcam",
578 })
579
580- @patch("snapcraft.common.log")
581- def test_config_raises_on_missing_snapcraft_yaml(self, mock_log):
582+ def test_config_raises_on_missing_snapcraft_yaml(self):
583+ fake_logger = fixtures.FakeLogger(level=logging.ERROR)
584+ self.useFixture(fake_logger)
585+
586 # no snapcraft.yaml
587- with self.assertRaises(SystemExit):
588+ with self.assertRaises(SystemExit) as raised:
589 Config()
590- mock_log.assert_called_with("""Could not find snapcraft.yaml. Are you sure you're in the right directory?
591-To start a new project, use 'snapcraft init'""")
592-
593- @patch("snapcraft.common.log")
594- def test_config_loop(self, mock_log):
595+
596+ self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
597+ self.assertEqual(
598+ "Could not find snapcraft.yaml. Are you sure you're in the right directory?\n"
599+ "To start a new project, use 'snapcraft init'\n",
600+ fake_logger.output)
601+
602+ def test_config_loop(self):
603+ fake_logger = fixtures.FakeLogger(level=logging.ERROR)
604+ self.useFixture(fake_logger)
605+
606 self.make_snapcraft_yaml("""parts:
607 p1:
608 plugin: ubuntu
609@@ -64,6 +71,8 @@
610 plugin: ubuntu
611 after: [p1]
612 """)
613- with self.assertRaises(SystemExit):
614+ with self.assertRaises(SystemExit) as raised:
615 Config()
616- mock_log.assert_called_with("Circular dependency chain!")
617+
618+ self.assertEqual(raised.exception.code, 1, 'Wrong exit code returned.')
619+ self.assertEqual('Circular dependency chain!\n', fake_logger.output)
620
621=== modified file 'snapcraft/yaml.py'
622--- snapcraft/yaml.py 2015-07-22 13:57:19 +0000
623+++ snapcraft/yaml.py 2015-07-29 04:38:10 +0000
624@@ -14,10 +14,16 @@
625 # You should have received a copy of the GNU General Public License
626 # along with this program. If not, see <http://www.gnu.org/licenses/>.
627
628+import logging
629+import sys
630+
631+import yaml
632+
633 import snapcraft.common
634 import snapcraft.plugin
635-import sys
636-import yaml
637+
638+
639+logger = logging.getLogger(__name__)
640
641
642 class Config:
643@@ -31,7 +37,7 @@
644 with open("snapcraft.yaml", 'r') as fp:
645 self.data = yaml.load(fp)
646 except FileNotFoundError:
647- snapcraft.common.log("Could not find snapcraft.yaml. Are you sure you're in the right directory?\nTo start a new project, use 'snapcraft init'")
648+ logger.error("Could not find snapcraft.yaml. Are you sure you're in the right directory?\nTo start a new project, use 'snapcraft init'")
649 sys.exit(1)
650 self.build_tools = self.data.get('build-tools', [])
651
652@@ -75,7 +81,7 @@
653 foundIt = True
654 break
655 if not foundIt:
656- snapcraft.common.log("Could not find part name %s" % dep)
657+ logger.error("Could not find part name %s" % dep)
658 sys.exit(1)
659
660 # Now sort them (this is super inefficient, but easy-ish to follow)
661@@ -92,7 +98,7 @@
662 topPart = part
663 break
664 if not topPart:
665- snapcraft.common.log("Circular dependency chain!")
666+ logger.error("Circular dependency chain!")
667 sys.exit(1)
668 sortedParts = [topPart] + sortedParts
669 self.all_parts.remove(topPart)

Subscribers

People subscribed via source and target branches

to all changes: