Ejemplo n.º 1
0
  def input(self, _in, out, **kwargs):
    source = kwargs.get('source_path')

    # We need an input file for the compiler to work
    if source is None:
      raise FilterError('ember-precompile: no input file')

    # Setup the command line executable
    proc = subprocess.Popen(['ember-precompile', source],
      stdout=subprocess.PIPE,
      stderr=subprocess.PIPE
    )

    # Execute the shell command
    stdout, stderr = proc.communicate()

    if proc.returncode != 0:
      message = ("ember-precompile: error in subprocess stderr=%s, stdout=%s, "
                 "returncode=%s" % (stderr, stdout, proc.returncode))
      raise FilterError(message)

    elif stderr:
      print('ember-precompile filter has warnings:', stderr)

    out.write(stdout.decode('utf-8'))
Ejemplo n.º 2
0
    def output(self, _in, out, **kw):
        binary = self.coffee_bin or self.coffee_deprecated or 'coffee'
        if self.coffee_deprecated:
            import warnings
            warnings.warn(
                'The COFFEE_PATH option of the "coffeescript" ' +
                'filter has been deprecated and will be removed.' +
                'Use COFFEE_BIN instead.', ImminentDeprecationWarning)

        args = "-sp" + ("" if self.no_bare else 'b')
        try:
            proc = subprocess.Popen([binary, args],
                                    stdin=subprocess.PIPE,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
        except OSError as e:
            if e.errno == 2:
                raise Exception(
                    "coffeescript not installed or in system path for webassets"
                )
            raise
        stdout, stderr = proc.communicate(_in.read().encode('utf-8'))
        if proc.returncode != 0:
            raise FilterError(
                ('coffeescript: subprocess had error: stderr=%s, ' +
                 'stdout=%s, returncode=%s') %
                (stderr, stdout, proc.returncode))
        elif stderr:
            print("coffeescript filter has warnings:", stderr)
        out.write(stdout.decode('utf-8'))
Ejemplo n.º 3
0
    def input(self, _in, out, **kwargs):
        """
        Compile individual Jade templates
        """
        proc = subprocess.Popen(self.argv,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE,
                                shell=(os.name == 'nt'))
        stdout, stderr = proc.communicate(_in.read())

        if proc.returncode != 0:
            raise FilterError(('jade: subprocess returned a non-success ' +
                               'result code: %s, stdout=%s, stderr=%s') %
                              (proc.returncode, stdout, stderr))
        elif stderr:
            print('jade filter has warnings:', stderr)

        # Add a bit of JavaScript that will place our compiled Jade function
        # into an object on the `window` object. Jade files are keyed by their
        # basename.
        key = os.path.splitext(os.path.basename(kwargs['source_path']))[0]
        preamble = "window['%s']['%s'] = " % (self.js_var, key)

        out.write('%s%s' % (preamble, stdout.strip()))
Ejemplo n.º 4
0
    def process_templates(self, out, hunks, **kw):
        templates = [info['source_path'] for _, info in hunks]

        if self.root is True:
            root = self.get_config('directory')
        elif self.root:
            root = path.join(self.get_config('directory'), self.root)
        else:
            root = self._find_base_path(templates)

        args = [self.binary or 'handlebars']
        if root:
            args.extend(['-r', root])
        if self.extra_args:
            args.extend(self.extra_args)
        args.extend(templates)

        proc = subprocess.Popen(args,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()

        if proc.returncode != 0:
            raise FilterError(
                ('handlebars: subprocess had error: stderr=%s, ' +
                 'stdout=%s, returncode=%s') %
                (stderr, stdout, proc.returncode))
        out.write(stdout.strip() + ';')
Ejemplo n.º 5
0
    def output(self, _in, out, **kw):
        # The typescript compiler cannot read a file which does not have
        # the .ts extension. The output file needs to have an extension,
        # or the compiler will want to create a directory in its place.
        input_filename = tempfile.mktemp() + ".ts"
        output_filename = tempfile.mktemp() + ".js"

        with open(input_filename, 'w') as f:
            f.write(_in.read())

        args = [self.binary or 'tsc', '--out', output_filename, input_filename]
        if self.config:
            args += self.config.split()
        proc = subprocess.Popen(
            args,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            shell=(os.name == 'nt'))
        stdout, stderr = proc.communicate()
        if proc.returncode != 0:
            raise FilterError("typescript: subprocess had error: stderr=%s," % stderr +
                "stdout=%s, returncode=%s" % (stdout, proc.returncode))

        with open(output_filename, 'r') as f:
            out.write(f.read())

        os.unlink(input_filename)
        os.unlink(output_filename)
Ejemplo n.º 6
0
    def output(self, _in, out, **kw):
        # The typescript compiler cannot read a file which does not have
        # the .ts extension
        input_filename = tempfile.mktemp() + ".ts"
        output_filename = tempfile.mktemp()

        with open(input_filename, 'wb') as f:
            f.write(_in.read())

        args = [self.binary or 'tsc', '--out', output_filename, input_filename]
        proc = subprocess.Popen(args,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        if proc.returncode != 0:
            raise FilterError("typescript: subprocess had error: stderr=%s," %
                              stderr + "stdout=%s, returncode=%s" %
                              (stdout, proc.returncode))

        with open(output_filename, 'rb') as f:
            out.write(f.read())

        os.unlink(input_filename)
        os.unlink(output_filename)
Ejemplo n.º 7
0
    def _apply_sass(self, _in, out, cd=None):
        # Switch to source file directory if asked, so that  this directory
        # is by default on the load path. We could pass it via -I, but then
        # files in the (undefined) wd could shadow the correct files.
        if cd:
            old_dir = os.getcwd()
            os.chdir(cd)

        # Put together the load path.
        load_paths = self.load_paths or []
        if self.includes_dir:
            load_paths.append(self.includes_dir)
            import warnings
            warnings.warn(
                'The INCLUDES_DIR option of the "sass" filter has '
                'been deprecated and will be removed. Use LOAD_PATHS'
                'instead.', ImminentDeprecationWarning)

        try:
            args = [self.binary or 'sass',
                    '--stdin',
                    '--style', 'expanded',
                    '--line-comments']
            if isinstance(self.env.cache, FilesystemCache):
                args.extend(['--cache-location',
                             os.path.join(self.env.cache.directory, 'sass')])
            if (self.env.debug if self.debug_info is None else self.debug_info):
                args.append('--debug-info')
            if self.use_scss:
                args.append('--scss')
            if self.use_compass:
                args.append('--compass')
            for path in load_paths:
                args.extend(['-I', path])
            for lib in self.libs or []:
                args.extend(['-r', lib])

            proc = subprocess.Popen(args,
                                    stdin=subprocess.PIPE,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    # shell: necessary on windows to execute
                                    # ruby files, but doesn't work on linux.
                                    shell=(os.name == 'nt'))
            stdout, stderr = proc.communicate(_in.read())

            if proc.returncode != 0:
                raise FilterError(('sass: subprocess had error: stderr=%s, '+
                                   'stdout=%s, returncode=%s') % (
                                                stderr, stdout, proc.returncode))
            elif stderr:
                print "sass filter has warnings:", stderr

            out.write(stdout)
        finally:
            if cd:
                os.chdir(old_dir)
Ejemplo n.º 8
0
    def _apply_sass(self, _in, out, cd=None):
        # Switch to source file directory if asked, so that this directory
        # is by default on the load path. We could pass it via --include-paths, but then
        # files in the (undefined) wd could shadow the correct files.
        from tempfile import TemporaryFile

        old_dir = os.getcwd()
        if cd:
            os.chdir(cd)

        with TemporaryFile() as stdin, TemporaryFile(
        ) as stdout, TemporaryFile() as stderr:
            try:
                args = [
                    self.binary or 'node-sass', '--output-style', self.style
                    or 'expanded'
                ]

                if not self.use_scss:
                    args.append("--indented-syntax")

                if (self.ctx.environment.debug
                        if self.debug_info is None else self.debug_info):
                    args.append('--debug-info')
                for path in self.load_paths or []:
                    args.extend(['--include-path', path])

                if (self.cli_args):
                    args.extend(self.cli_args)

                stdin.write(_in.read().encode('utf-8'))
                stdin.seek(0)
                proc = subprocess.Popen(
                    args,
                    stdin=stdin,
                    stdout=stdout,
                    stderr=stderr,
                    # shell: necessary on windows to execute
                    # ruby files, but doesn't work on linux.
                    shell=(os.name == 'nt'))
                proc.wait()

                stdout.seek(0)
                stderr.seek(0)

                if proc.returncode != 0:
                    raise FilterError(
                        'sass: subprocess had error: stderr={}, stdout={}, returncode={}'
                        .format(stderr.read(), stdout.read(), proc.returncode))
                elif stderr:
                    print("node-sass filter has warnings:", stderr)

                out.write(stdout.read().decode('utf-8'))
            finally:
                if cd:
                    os.chdir(old_dir)
Ejemplo n.º 9
0
    def _apply_sass(self, _in, out, cd=None):
        # Switch to source file directory if asked, so that this directory
        # is by default on the load path. We could pass it via -I, but then
        # files in the (undefined) wd could shadow the correct files.
        orig_cwd = os.getcwd()
        child_cwd = orig_cwd
        if cd:
            child_cwd = cd

        args = [
            self.binary or 'sass', '--stdin', '--style', self.style
            or 'expanded'
        ]
        if self.line_comments is None or self.line_comments:
            args.append('--line-comments')
        if isinstance(self.ctx.cache, FilesystemCache):
            args.extend([
                '--cache-location',
                os.path.join(orig_cwd, self.ctx.cache.directory, 'sass')
            ])
        elif not cd:
            # Without a fixed working directory, the location of the cache
            # is basically undefined, so prefer not to use one at all.
            args.extend(['--no-cache'])
        if (self.ctx.environment.debug
                if self.debug_info is None else self.debug_info):
            args.append('--debug-info')
        if self.use_scss:
            args.append('--scss')
        if self.use_compass:
            args.append('--compass')
        for path in self.load_paths or []:
            args.extend(['-I', path])
        for lib in self.libs or []:
            args.extend(['-r', lib])

        proc = subprocess.Popen(
            args,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            # shell: necessary on windows to execute
            # ruby files, but doesn't work on linux.
            shell=(os.name == 'nt'),
            cwd=child_cwd)
        stdout, stderr = proc.communicate(_in.read().encode('utf-8'))

        if proc.returncode != 0:
            raise FilterError(('sass: subprocess had error: stderr=%s, ' +
                               'stdout=%s, returncode=%s') %
                              (stderr, stdout, proc.returncode))
        elif stderr:
            print("sass filter has warnings:", stderr)

        out.write(stdout.decode('utf-8'))
Ejemplo n.º 10
0
    def input(self, in_, out, **kwargs):
        h = connector.Handler(self.env, in_, out,
                              self.plugins if self.plugins else {},
                              self.imports if self.imports else [],
                              kwargs["source"])
        h.vendor_path = self.vendor_path
        if not self.compass:
            raise FilterError("Compass bin path is not set")
        h.start(self.compass)

        self.depends = h.deps
    def run_input_optimizer(source_path, output_path, **kwargs):
        """ Run Optimizer Command and return file """

        MB_MEMORY_FOR_JAVA = 256

        if not source_path.endswith(".js"):
            raise FilterError('requireJS: bundle file is not a js-file')

        base_url = kwargs.get('base_url', './')
        use_rhino = kwargs.get('use_rhino', False)

        # Use the provided name or calculate the name relative to the base_url and minus the ".js"-part
        working_dir = os.getcwd()
        relpath = os.path.relpath(source_path, working_dir)
        name = kwargs.get('name', os.path.relpath(relpath, base_url)[:-3])

        # Any extra args that should be provided to r.js
        extra_arg_string = ""
        extra_args = kwargs.get("extra_args", {})
        for key, value in extra_args.iteritems():
            extra_arg_string += "%s=%s " % (key, value)

        compiler_cmd = ''
        if use_rhino:
            compiler_cmd = "java -Xmx{memory}m -classpath {rhino_js_jar}:{closure_compiler_jar} " \
                            "org.mozilla.javascript.tools.shell.Main {require_js} " \
                            "-o baseUrl={base_url} name={name} out={require_output_path} {require_extra_args}".format(memory=MB_MEMORY_FOR_JAVA,
                                                                                                                      rhino_js_jar=RequireOptimizer._resource_path("js.jar"),
                                                                                                                      closure_compiler_jar=RequireOptimizer._resource_path("compiler.jar"),
                                                                                                                      require_js=RequireOptimizer._resource_path("r.js"),
                                                                                                                      base_url=base_url,
                                                                                                                      name=name,
                                                                                                                      require_output_path=output_path,
                                                                                                                      require_extra_args=extra_arg_string)
        else:
            compiler_cmd = 'node {require_js} -o baseUrl={base_url} name={name} ' \
                           'out={require_output_path} {require_extra_args}'.format(require_js=RequireOptimizer._resource_path("r.js"),
                                                                                   base_url=base_url,
                                                                                   name=name,
                                                                                   require_output_path=output_path,
                                                                                   require_extra_args=extra_arg_string)

        # Run the compiler.
        try:
            try:
                os.system(compiler_cmd)
            except OSError:
                print "Unable to execute {0}, is it installed?".format('java' if use_rhino else 'node')

            fo = open(output_path, "r+")

            return fo.read()
        except:
            return ''
Ejemplo n.º 12
0
    def output(self, _in, out, **kw):
        proc = subprocess.Popen([self.binary or 'cleancss'],
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate(_in.read())

        if proc.returncode != 0:
            raise FilterError(('cleancss: subprocess had error: stderr=%s, ' +
                               'stdout=%s, returncode=%s') %
                              (stderr, stdout, proc.returncode))
        out.write(stdout)
Ejemplo n.º 13
0
 def java_run(self, args):
     proc = subprocess.Popen(
         [self.java, '-jar', self.jar] + args,
         # we cannot use the in/out streams directly, as they might be
         # StringIO objects (which are not supported by subprocess)
         stdout=subprocess.PIPE,
         stdin=subprocess.PIPE,
         stderr=subprocess.PIPE)
     stdout, stderr = proc.communicate()
     if proc.returncode:
         raise FilterError(
             '%s: subprocess returned a '
             'non-success result code: %s, stdout=%s, stderr=%s' %
             (self.name, proc.returncode, stdout, stderr))
Ejemplo n.º 14
0
 def output(self, _in, out, **kw):
     args = ['iced', '-sp', '--runtime', 'inline']
     proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
     stdout, stderr = proc.communicate(_in.read().encode('utf-8'))
     if proc.returncode != 0:
         raise FilterError(
             (
                 'iced: subprocess had error: stderr=%s, ' +
                 'stdout=%s, returncode=%s'
             ) % (stderr, stdout, proc.returncode)
         )
     elif stderr:
         print("coffeescript filter has warnings:", stderr)
     out.write(stdout.decode('utf-8'))
Ejemplo n.º 15
0
    def output(self, _in, out, **kw):
        args = [self.binary]
        if self.extra_args:
            args.extend(self.extra_args)
        proc = subprocess.Popen(args,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate(_in.read())

        if proc.returncode != 0:
            raise FilterError(('uglifyjs: subprocess had error: stderr=%s, ' +
                               'stdout=%s, returncode=%s') %
                              (stderr, stdout, proc.returncode))
        out.write(stdout)
Ejemplo n.º 16
0
    def open(self, out, source_path, **kw):
        proc = subprocess.Popen(
            [self.less or 'lessc', source_path],
            stdout = subprocess.PIPE,
            stderr = subprocess.PIPE
        )
        stdout, stderr = proc.communicate()

        # At the moment (2011-12-09), there's a bug in the current version of
        # Less that always prints an error to stdout so the returncode is the
        # only way of determining if Less is actually having a compilation
        # error.
        if proc.returncode != 0:
            raise FilterError(('less: subprocess had error: stderr=%s, ' +
                               'stdout=%s, returncode=%s') % (
                stderr, stdout, proc.returncode))

        out.write(stdout)
Ejemplo n.º 17
0
    def input(self, infile, outfile, **kwargs):
        args = ['browserify']

        transforms = ['babelify']
        for transform in transforms:
            args.extend(('--transform', transform))
        # Use the resolvify module to include npm modules from the
        # vendor directory.
        args.extend(
            ('--transform', '[resolvify', 'vendor', 'vendor/node_modules]'))
        args.append(kwargs['source_path'])
        if app.config['DEBUG']:
            args.append('--debug')

        try:
            self.subprocess(args, outfile, infile)
        except FilterError as e:
            raise FilterError(str(e).replace('\\n', '\n'))
Ejemplo n.º 18
0
    def _apply_sass(self, _in, out, includes_path):
        if includes_path:
            old_dir = os.getcwd()
            os.chdir(includes_path)

        try:
            args = [
                self.binary or 'sass', '--stdin', '--style', 'expanded',
                '--line-comments'
            ]
            if isinstance(self.env.cache, FilesystemCache):
                args.extend([
                    '--cache-location',
                    os.path.join(self.env.cache.directory, 'sass')
                ])
            if (self.env.debug
                    if self.debug_info is None else self.debug_info):
                args.append('--debug-info')
            if self.use_scss:
                args.append('--scss')
            if self.use_compass:
                args.append('--compass')

            proc = subprocess.Popen(
                args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                # shell: necessary on windows to execute
                # ruby files, but doesn't work on linux.
                shell=(os.name == 'nt'))
            stdout, stderr = proc.communicate(_in.read())

            if proc.returncode != 0:
                raise FilterError(('sass: subprocess had error: stderr=%s, ' +
                                   'stdout=%s, returncode=%s') %
                                  (stderr, stdout, proc.returncode))
            elif stderr:
                print "sass filter has warnings:", stderr

            out.write(stdout)
        finally:
            if includes_path:
                os.chdir(old_dir)
Ejemplo n.º 19
0
 def input(self, _in, out, source_path, output_path):
     old_dir = os.getcwd()
     os.chdir(os.path.dirname(source_path))
     try:
         args = "-p" + ("" if self.no_bare else 'b')
         proc = subprocess.Popen([self.coffee, args, source_path],
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
         stdout, stderr = proc.communicate()
         if proc.returncode != 0:
             raise FilterError(
                 ('coffeescript: subprocess had error: stderr=%s, ' +
                  'stdout=%s, returncode=%s') %
                 (stderr, stdout, proc.returncode))
         elif stderr:
             print "coffeescript filter has warnings:", stderr
         out.write(stdout)
     finally:
         os.chdir(old_dir)
Ejemplo n.º 20
0
    def open(self, out, source_path, **kw):
        args = []
        if self.node_path:
            args += [self.node_path]
        args += [self.dusty_path or 'dusty']
        # no need for --single, as we output to STDOUT
        args += [source_path]

        proc = subprocess.Popen(args,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()

        if proc.returncode != 0:
            raise FilterError(('dusty: subprocess had error: stderr=%s,' +
                               'stdout=%s, returncode=%s') %
                              (stderr, stdout, proc.returncode))
        out.write(stdout)
Ejemplo n.º 21
0
    def input(self, _in, out, **kwargs):
        input_filename = kwargs['source_path']
        output_filename = tempfile.mktemp() + ".js"

        proc = subprocess.Popen(
            self.get_executable_list(input_filename, output_filename),
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        if proc.returncode != 0:
            raise FilterError(
                'babel: subprocess had error: stderr={},'
                'stdout={}, returncode={}'.format(
                    stderr, stdout, proc.returncode))

        with open(output_filename, 'r') as f:
            out.write(f.read())

        os.unlink(output_filename)
Ejemplo n.º 22
0
    def input(self, _in, out, source_path, output_path):
        proc = subprocess.Popen(
            [self.less or 'lessc'],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            # shell: necessary on windows to execute
            # ruby files, but doesn't work on linux.
            shell=(os.name == 'nt'))

        with open(source_path) as src:
            stdout, stderr = proc.communicate(input=src.read())

        # less only writes to stdout, as noted in the method doc, but
        # check everything anyway.
        if stderr or proc.returncode != 0:
            raise FilterError(('less: subprocess had error: stderr=%s, '
                               'stdout=%s, returncode=%s') %
                              (stderr, stdout, proc.returncode))

        out.write(stdout)
Ejemplo n.º 23
0
    def input(self, in_, out, source_path, **kw):
        # Set working directory to the source file so that includes are found
        with working_directory(filename=source_path):
            proc = subprocess.Popen(
                [self.less or 'lessc', '-'],
                stdout = subprocess.PIPE,
                stderr = subprocess.PIPE,
                stdin  = subprocess.PIPE
            )
            stdout, stderr = proc.communicate(in_.read())

            # At the moment (2011-12-09), there's a bug in the current version of
            # Less that always prints an error to stdout so the returncode is the
            # only way of determining if Less is actually having a compilation
            # error.
            if proc.returncode != 0:
                raise FilterError(('less: subprocess had error: stderr=%s, ' +
                                   'stdout=%s, returncode=%s') % (
                    stderr, stdout, proc.returncode))

            out.write(stdout)
Ejemplo n.º 24
0
    def open(self, out, sourcePath, **kw):
        """Less currently doesn't take data from stdin, and doesn't allow
        us from stdout either. Neither does it return a proper non-0 error
        code when an error occurs, or even write to stderr (stdout instead)!

        Hopefully this will improve in the future:

        http://groups.google.com/group/lesscss/browse_thread/thread/3aed033a44c51b4c/b713148afde87e81
        """
        # TODO: Use NamedTemporaryFile.
        outtemp_name = os.path.join(tempfile.gettempdir(),
                                    'assets_temp_%d.css' % int(time.time()))

        proc = subprocess.Popen(
            [self.less or 'lessc', sourcePath, outtemp_name],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            # shell: necessary on windows to execute
            # ruby files, but doesn't work on linux.
            shell=(os.name == 'nt'))
        stdout, stderr = proc.communicate()

        # less only writes to stdout, as noted in the method doc, but
        # check everything anyway.
        if stdout or stderr or proc.returncode != 0:
            if os.path.exists(outtemp_name):
                os.unlink(outtemp_name)
            raise FilterError(('less: subprocess had error: stderr=%s, '+
                               'stdout=%s, returncode=%s') % (
                                            stderr, stdout, proc.returncode))

        outtemp = open(outtemp_name)
        try:
            out.write(outtemp.read())
        finally:
            outtemp.close()

            os.unlink(outtemp_name)
Ejemplo n.º 25
0
    def input(self, _in, out, **kwargs):
        input_filename = tempfile.mktemp() + "-babel.js"
        output_filename = tempfile.mktemp() + ".js"

        with open(input_filename, 'w') as f:
            f.write(_in.getvalue())

        proc = subprocess.Popen(self.get_executable_list(
            input_filename, output_filename),
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        if proc.returncode != 0:
            raise FilterError('babel: subprocess had error: stderr=%s,'
                              'stdout=%s, returncode=%s'.format(
                                  stderr, stdout, proc.returncode))

        with open(output_filename, 'r') as f:
            out.write(f.read())

        os.unlink(input_filename)
        os.unlink(output_filename)
Ejemplo n.º 26
0
    def output(self, _in, out, **kw):
        binary = self.coffee_bin or self.coffee_deprecated or 'coffee'
        if self.coffee_deprecated:
            import warnings
            warnings.warn(
                'The COFFEE_PATH option of the "coffeescript" ' +
                'filter has been deprecated and will be removed.' +
                'Use COFFEE_BIN instead.', ImminentDeprecationWarning)

        args = "-sp" + ("" if self.no_bare else 'b')
        proc = subprocess.Popen([binary, args],
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate(_in.read())
        if proc.returncode != 0:
            raise FilterError(
                ('coffeescript: subprocess had error: stderr=%s, ' +
                 'stdout=%s, returncode=%s') %
                (stderr, stdout, proc.returncode))
        elif stderr:
            print "coffeescript filter has warnings:", stderr
        out.write(stdout)
Ejemplo n.º 27
0
    def open(self, out, source_path, **kw):
        """Compass currently doesn't take data from stdin, and doesn't allow
        us accessing the result from stdout either.

        Also, there's a bunch of other issues we need to work around:

         - compass doesn't support given an explict output file, only a
           "--css-dir" output directory.

           We have to "guess" the filename that will be created in that
           directory.

         - The output filename used is based on the input filename, and
           simply cutting of the length of the "sass_dir" (and changing
           the file extension). That is, compass expects the input
           filename to always be inside the "sass_dir" (which defaults to
           ./src), and if this is not the case, the output filename will
           be gibberish (missing characters in front). See:
           https://github.com/chriseppstein/compass/issues/304

           We fix this by setting the proper --sass-dir option.

         - Compass insists on creating a .sass-cache folder in the
           current working directory, and unlike the sass executable,
           there doesn't seem to be a way to disable it.

           The workaround is to set the working directory to our temp
           directory, so that the cache folder will be deleted at the end.
        """

        # Create temp folder one dir below output_path so sources in
        # sourcemap are correct. This will be in the project folder,
        # and as such, while exteremly unlikely, this could interfere
        # with existing files and directories.
        tempout_dir = path.normpath(
            path.join(path.dirname(kw['output_path']), '../')
        )
        tempout = tempfile.mkdtemp(dir=tempout_dir)
        # Temporarily move to "tempout", so .sass-cache will be created there
        old_wd = os.getcwd()
        os.chdir(tempout)
        try:
            # Make sure to use normpath() to not cause trouble with
            # compass' simplistic path handling, where it just assumes
            # source_path is within sassdir, and cuts off the length of
            # sassdir from the input file.
            sassdir = path.normpath(path.dirname(source_path))
            source_path = path.normpath(source_path)

            # Compass offers some helpers like image-url(), which need
            # information about the urls under which media files will be
            # available. This is hard for two reasons: First, the options in
            # question aren't supported on the command line, so we need to write
            # a temporary config file. Secondly, they assume defined and
            # separate directories for "images", "stylesheets" etc., something
            # webassets knows nothing of: we don't support the user defining
            # such directories. Because we traditionally had this
            # filter point all type-specific directories to the root media
            # directory, we will define the paths to match this. In other
            # words, in Compass, both inline-image("img/test.png) and
            # image-url("img/test.png") will find the same file, and assume it
            # to be {env.directory}/img/test.png.
            # However, this partly negates the purpose of an utility like
            # image-url() in the first place - you not having to hard code
            # the location of your images. So we allow direct modification of
            # the configuration file via the COMPASS_CONFIG setting (see
            # tickets #36 and #125).
            #
            # Note that there is also the --relative-assets option, which we
            # can't use because it calculates an actual relative path between
            # the image and the css output file, the latter being in a
            # temporary directory in our case.
            config = CompassConfig(
                project_path=self.ctx.directory,
                http_path=self.ctx.url,
                http_images_dir='',
                http_stylesheets_dir='',
                http_fonts_dir='',
                http_javascripts_dir='',
                images_dir='',
                output_style=':expanded',
            )
            # Update with the custom config dictionary, if any.
            if self.config:
                config.update(self.config)
            config_file = path.join(tempout, '.config.rb')
            f = open(config_file, 'w')
            try:
                f.write(config.to_string())
                f.flush()
            finally:
                f.close()

            command = [self.compass or 'compass', 'compile']
            for plugin in self.plugins or []:
                command.extend(('--require', plugin))
            command.extend(['--sass-dir', sassdir,
                            '--css-dir', tempout,
                            '--config', config_file,
                            '--quiet',
                            '--boring',
                            source_path])
            proc = subprocess.Popen(command,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE,
                                    # shell: necessary on windows to execute
                                    # ruby files, but doesn't work on linux.
                                    shell=(os.name == 'nt'))
            stdout, stderr = proc.communicate()

            # compass seems to always write a utf8 header? to stderr, so
            # make sure to not fail just because there's something there.
            if proc.returncode != 0:
                raise FilterError(('compass: subprocess had error: stderr=%s, '+
                                   'stdout=%s, returncode=%s') % (
                                                stderr, stdout, proc.returncode))

            guessed_outputfilename = path.splitext(path.basename(source_path))[0]
            guessed_outputfilepath = path.join(tempout, guessed_outputfilename)
            output_file = open("%s.css" % guessed_outputfilepath, encoding='utf-8')
            if config.get('sourcemap'):
                sourcemap_file = open("%s.css.map" % guessed_outputfilepath)
                sourcemap_output_filepath = path.join(
                    path.dirname(kw['output_path']),
                    path.basename(sourcemap_file.name)
                )
                if not path.exists(path.dirname(sourcemap_output_filepath)):
                    os.mkdir(path.dirname(sourcemap_output_filepath))
                sourcemap_output_file = open(sourcemap_output_filepath, 'w')
                sourcemap_output_file.write(sourcemap_file.read())
                sourcemap_file.close()
            try:
                contents = output_file.read()
                out.write(contents)
            finally:
                output_file.close()
        finally:
            # Restore previous working dir
            os.chdir(old_wd)
            # Clean up the temp dir
            shutil.rmtree(tempout)
Ejemplo n.º 28
0
    def subprocess(cls, argv, out, data=None):
        """Execute the commandline given by the list in ``argv``.

        If a byestring is given via ``data``, it is piped into data.

        ``argv`` may contain two placeholders:

        ``{input}``
            If given, ``data`` will be written to a temporary file instead
            of data. The placeholder is then replaced with that file.

        ``{output}``
            Will be replaced by a temporary filename. The return value then
            will be the content of this file, rather than stdout.
        """
        class tempfile_on_demand(object):
            def __repr__(self):
                if not hasattr(self, 'filename'):
                    self.fd, self.filename = tempfile.mkstemp()
                return self.filename

            @property
            def created(self):
                return hasattr(self, 'filename')

        # Replace input and output placeholders
        input_file = tempfile_on_demand()
        output_file = tempfile_on_demand()
        if hasattr(str, 'format'):  # Support Python 2.5 without the feature
            argv = list(
                map(
                    lambda item: item.format(input=input_file,
                                             output=output_file), argv))

        try:
            data = (data.read() if hasattr(data, 'read') else data)
            if data is not None:
                data = data.encode('utf-8')

            if input_file.created:
                if not data:
                    raise ValueError(
                        '{input} placeholder given, but no data passed')
                with os.fdopen(input_file.fd, 'wb') as f:
                    f.write(data)
                    # No longer pass to stdin
                    data = None

            proc = subprocess.Popen(
                argv,
                # we cannot use the in/out streams directly, as they might be
                # StringIO objects (which are not supported by subprocess)
                stdout=subprocess.PIPE,
                stdin=subprocess.PIPE,
                stderr=subprocess.PIPE,
                shell=os.name == 'nt')
            stdout, stderr = proc.communicate(data)
            if proc.returncode:
                raise FilterError(
                    '%s: subprocess returned a non-success result code: '
                    '%s, stdout=%s, stderr=%s' %
                    (cls.name
                     or cls.__name__, proc.returncode, stdout, stderr))
            else:
                if output_file.created:
                    with open(output_file.filename, 'rb') as f:
                        out.write(f.read().decode('utf-8'))
                else:
                    out.write(stdout.decode('utf-8'))
        finally:
            if output_file.created:
                os.unlink(output_file.filename)
            if input_file.created:
                os.unlink(input_file.filename)