예제 #1
0
    def test_output_moved(self):
        class Filter(ExternalTool):
            pass

        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = ["stdout", "stderr"]

        # {output} creates an output
        # this test *moves* the file into the target location, and
        # tests the fix to issue #286
        intercepted = {}

        def fake_output_file(argv, **kw):
            intercepted["filename"] = argv[0]
            with open(argv[0] + ".tmp", "w") as f:
                f.write("bat")
            import shutil

            shutil.move(argv[0] + ".tmp", argv[0])
            return DEFAULT

        self.popen.side_effect = fake_output_file
        # We get the result we generated in the hook above
        out = StringIO()
        Filter.subprocess(["{output}"], out)
        assert out.getvalue() == "bat"
        # File has been deleted
        assert not os.path.exists(intercepted["filename"])
예제 #2
0
    def test_output_moved(self):
        class Filter(ExternalTool):
            pass

        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = ['stdout', 'stderr']

        # {output} creates an output
        # this test *moves* the file into the target location, and
        # tests the fix to issue #286
        intercepted = {}

        def fake_output_file(argv, **kw):
            intercepted['filename'] = argv[0]
            with open(argv[0] + '.tmp', 'w') as f:
                f.write('bat')
            import shutil
            shutil.move(argv[0] + '.tmp', argv[0])
            return DEFAULT

        self.popen.side_effect = fake_output_file
        # We get the result we generated in the hook above
        out = StringIO()
        Filter.subprocess(['{output}'], out)
        assert out.getvalue() == 'bat'
        # File has been deleted
        assert not os.path.exists(intercepted['filename'])
예제 #3
0
    def test_input_var(self):
        """Test {input} variable."""
        class Filter(ExternalTool):
            pass

        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = [
            b'stdout', b'stderr'
        ]

        # {input} creates an input file
        intercepted = {}

        def check_input_file(argv, **kw):
            intercepted['filename'] = argv[0]
            with open(argv[0], 'r') as f:
                # File has been generated with input data
                assert f.read().decode('utf-8') == u'fooñ'
            return DEFAULT

        self.popen.side_effect = check_input_file
        Filter.subprocess(['{input}'], StringIO(), data=u'fooñ')
        # No stdin was passed
        self.popen.return_value.communicate.assert_called_with(None)
        # File has been deleted
        assert not os.path.exists(intercepted['filename'])

        # {input} requires input data
        assert_raises(ValueError, Filter.subprocess, ['{input}'], StringIO())
예제 #4
0
 def test_method_output(self):
     """The method=output."""
     class Filter(self.MockTool):
         method = 'output'
     assert getattr(Filter, 'input') is None
     assert getattr(Filter, 'open') is None
     Filter().output(StringIO('bla'), StringIO())
     assert Filter.result == ([], 'bla')
예제 #5
0
 def test_argv_variables(self):
     """In argv, a number of placeholders can be used. Ensure they work."""
     class Filter(self.MockTool):
         argv = [
             # The filter instance
             '{self.__class__.__name__}',
             # Keyword and positional args to filter method
             '{kwarg}', '{0.closed}',
             # Special placeholders that are passed through
             '{input}', '{output}']
     Filter().output(StringIO('content'), StringIO(), kwarg='value')
     assert Filter.result == (
         ["Filter", 'value', 'False', '{input}', '{output}'], 'content')
예제 #6
0
 def test_method_open(self):
     """The method=open."""
     class Filter(self.MockTool):
         method = 'open'
     assert getattr(Filter, 'output') is None
     assert getattr(Filter, 'input') is None
     Filter().open(StringIO(), 'filename')
     assert Filter.result == ([], None)
예제 #7
0
    def test_subprocess(self):
        """Instead of the ``argv`` shortcut, subclasses can also use the
        ``subprocess`` helper manually.
        """

        class Filter(ExternalTool): pass

        # Without stdin data
        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = [b'stdout', b'stderr']
        out = StringIO()
        Filter.subprocess(['test'], out)
        assert out.getvalue() == 'stdout'
        self.popen.return_value.communicate.assert_called_with(None)

        # With stdin data
        self.popen.reset_mock()
        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = [b'stdout', b'stderr']
        out = StringIO()
        Filter.subprocess(['test'], out, data='data')
        assert out.getvalue() == 'stdout'
        self.popen.return_value.communicate.assert_called_with(b'data')

        # With error
        self.popen.return_value.returncode = 1
        self.popen.return_value.communicate.return_value = [b'stdout', b'stderr']
        assert_raises(FilterError, Filter.subprocess, ['test'], StringIO())
예제 #8
0
    def test_output_var(self):
        class Filter(ExternalTool): pass
        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = ['stdout', 'stderr']

        # {input} creates an input file
        intercepted = {}
        def fake_output_file(argv,  **kw):
            intercepted['filename'] = argv[0]
            with open(argv[0], 'w') as f:
                f.write('bat')
            return DEFAULT
        self.popen.side_effect = fake_output_file
        # We get the result we generated in the hook above
        out = StringIO()
        Filter.subprocess(['{output}'], out)
        assert out.getvalue() == 'bat'
        # File has been deleted
        assert not os.path.exists(intercepted['filename'])
예제 #9
0
    def test_output_var(self):
        class Filter(ExternalTool):
            pass

        self.popen.return_value.returncode = 0
        self.popen.return_value.communicate.return_value = ["stdout", "stderr"]

        # {output} creates an output file
        intercepted = {}

        def fake_output_file(argv, **kw):
            intercepted["filename"] = argv[0]
            with open(argv[0], "w") as f:
                f.write("bat")
            return DEFAULT

        self.popen.side_effect = fake_output_file
        # We get the result we generated in the hook above
        out = StringIO()
        Filter.subprocess(["{output}"], out)
        assert out.getvalue() == "bat"
        # File has been deleted
        assert not os.path.exists(intercepted["filename"])
예제 #10
0
    def test_assets(self):
        try:
            import PIL
            # Travis does not support PNG files, see
            # https://github.com/travis-ci/travis-ci/issues/746
            from PIL import Image
            Image.new('RGB', (10,10)).save(StringIO(), 'png')
        except (ImportError, IOError):
            raise SkipTest()
        self.create_files({'noise.scss': 'h1 {background: background-noise()}'})
        self.mkbundle('noise.scss', filters='pyscss', output='out.css').build()

        assert doctest_match(
            'h1 {\n  background: url("...png");\n}\n',
            self.get('out.css'),)
예제 #11
0
 def loader(self, text, filename=None):
     io = StringIO(textwrap.dedent(text))
     if filename:
         io.name = filename
     return YAMLLoader(io)
예제 #12
0
 def loader(self, text, filename=None):
     io = StringIO(textwrap.dedent(text))
     if filename:
         io.name = filename
     return YAMLLoader(io)
예제 #13
0
    def __call__(self, bundles=None, output=None, directory=None, no_cache=None,
              manifest=None, production=None):
        """Build assets.

        ``bundles``
            A list of bundle names. If given, only this list of bundles
            should be built.

        ``output``
            List of (bundle, filename) 2-tuples. If given, only these
            bundles will be built, using the custom output filenames.
            Cannot be used with ``bundles``.

        ``directory``
            Custom output directory to use for the bundles. The original
            basenames defined in the bundle ``output`` attribute will be
            used. If the ``output`` of the bundles are pointing to different
            directories, they will be offset by their common prefix.
            Cannot be used with ``output``.

        ``no_cache``
            If set, a cache (if one is configured) will not be used.

        ``manifest``
            If set, the given manifest instance will be used, instead of
            any that might have been configured in the Environment. The value
            passed will be resolved through ``get_manifest()``. If this fails,
            a file-based manifest will be used using the given value as the
            filename.

        ``production``
            If set to ``True``, then :attr:`Environment.debug`` will forcibly
            be disabled (set to ``False``) during the build.
        """

        # Validate arguments
        if bundles and output:
            raise CommandError(
                'When specifying explicit output filenames you must '
                'do so for all bundles you want to build.')
        if directory and output:
            raise CommandError('A custom output directory cannot be '
                               'combined with explicit output filenames '
                               'for individual bundles.')

        if production:
            # TODO: Reset again (refactor commands to be classes)
            self.environment.debug = False

        # TODO: Oh how nice it would be to use the future options stack.
        if manifest is not None:
            try:
                manifest = get_manifest(manifest, env=self.environment)
            except ValueError:
                manifest = get_manifest(
                    # abspath() is important, or this will be considered
                    # relative to Environment.directory.
                    "file:%s" % os.path.abspath(manifest),
                    env=self.environment)
            self.environment.manifest = manifest

        # Use output as a dict.
        if output:
            output = dict(output)

        # Validate bundle names
        bundle_names = bundles if bundles else (output.keys() if output else [])
        for name in bundle_names:
            if not name in self.environment:
                raise CommandError(
                    'I do not know a bundle name named "%s".' % name)

        # Make a list of bundles to build, and the filename to write to.
        if bundle_names:
            # TODO: It's not ok to use an internal property here.
            bundles = [(n,b) for n, b in self.environment._named_bundles.items()
                             if n in bundle_names]
        else:
            # Includes unnamed bundles as well.
            bundles = [(None, b) for b in self.environment]

        # Determine common prefix for use with ``directory`` option.
        if directory:
            prefix = os.path.commonprefix(
                [os.path.normpath(b.resolve_output(self.environment))
                 for _, b in bundles if b.output])
            # dirname() gives the right value for a single file.
            prefix = os.path.dirname(prefix)

        to_build = []
        for name, bundle in bundles:
            # TODO: We really should support this. This error here
            # is just in place of a less understandable error that would
            # otherwise occur.
            if bundle.is_container and directory:
                raise CommandError(
                    'A custom output directory cannot currently be '
                    'used with container bundles.')

            # Determine which filename to use, if not the default.
            overwrite_filename = None
            if output:
                overwrite_filename = output[name]
            elif directory:
                offset = os.path.normpath(
                    bundle.resolve_output(self.environment))[len(prefix)+1:]
                overwrite_filename = os.path.join(directory, offset)
            to_build.append((bundle, overwrite_filename, name,))

        # Build.
        built = []
        for bundle, overwrite_filename, name in to_build:
            if name:
                # A name is not necessary available of the bundle was
                # registered without one.
                self.log.info("Building bundle: %s (to %s)" % (
                    name, overwrite_filename or bundle.output))
            else:
                self.log.info("Building bundle: %s" % bundle.output)

            try:
                if not overwrite_filename:
                    bundle.build(force=True, env=self.environment,
                        disable_cache=no_cache)
                else:
                    # TODO: Rethink how we deal with container bundles here.
                    # As it currently stands, we write all child bundles
                    # to the target output, merged (which is also why we
                    # create and force writing to a StringIO instead of just
                    # using the ``Hunk`` objects that build() would return
                    # anyway.
                    output = StringIO()
                    bundle.build(force=True, env=self.environment, output=output,
                        disable_cache=no_cache)
                    if directory:
                        # Only auto-create directories in this mode.
                        output_dir = os.path.dirname(overwrite_filename)
                        if not os.path.exists(output_dir):
                            os.makedirs(output_dir)
                    MemoryHunk(output.getvalue()).save(overwrite_filename)
                built.append(bundle)
            except BuildError as e:
                self.log.error("Failed, error was: %s" % e)
        if len(built):
            self.event_handlers['post_build']()
        if len(built) != len(to_build):
            return 2