Exemplo n.º 1
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())
Exemplo n.º 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"])
Exemplo n.º 3
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'])
Exemplo n.º 4
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'])
Exemplo n.º 5
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"])
Exemplo n.º 6
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