示例#1
0
 def compile_string(self, string, filename=None):
     compilation = self.make_compilation()
     if filename is not None:
         f = StringIO(string)
         filename = PurePath(filename)
         source = SourceFile.from_file(f, origin=filename.parent, relpath=PurePath(filename.name))
     else:
         source = SourceFile.from_string(string)
     compilation.add_source(source)
     return self.call_and_catch_errors(compilation.run)
示例#2
0
 def compile_string(self, string, filename=None):
     compilation = self.make_compilation()
     if filename is not None:
         f = StringIO(string)
         filename = PurePath(filename)
         source = SourceFile.from_file(f,
                                       origin=filename.parent,
                                       relpath=PurePath(filename.name))
     else:
         source = SourceFile.from_string(string)
     compilation.add_source(source)
     return self.call_and_catch_errors(compilation.run)
示例#3
0
 def make_source_file(resource):
     package = resource.name.split(':')[0]
     relpath = resource.name.split(':')[-1]
     filename = relpath.split('/')[-1]
     source = u'\n'.join((
             u'$current-package: "{0}";'.format(package),
             u'$current-relpath: "{0}";'.format(relpath),
             u'$current-filename: "{0}";'.format(filename),
             resource.get_source(self.context, self.request)))
     if ISCSSFileResource.providedBy(resource):
         source_file = SourceFile.from_string(
             source, Path(str(resource.path)))
         source_file.origin = Path(str(resource.path))
         return source_file
     else:
         path = 'dynamic:{0}'.format(resource.name)
         return SourceFile.from_string(source, path)
    def __init__(self, is_sass=False):
        # TODO it would be lovely to get these out of here, somehow
        self.namespace = Namespace(variables=_default_scss_vars)

        self.compiler = Compiler(namespace=self.namespace)
        self.compilation = self.compiler.make_compilation()
        self.legacy_compiler_options = {}
        self.source_file = SourceFile.from_string('', '<shell>', is_sass=is_sass)
        self.calculator = Calculator(self.namespace)
示例#5
0
文件: tool.py 项目: 7c00/staticpycon
    def __init__(self, is_sass=False):
        # TODO it would be lovely to get these out of here, somehow
        self.namespace = Namespace(variables=_default_scss_vars)

        self.compiler = Compiler(namespace=self.namespace)
        self.compilation = self.compiler.make_compilation()
        self.legacy_compiler_options = {}
        self.source_file = SourceFile.from_string('', '<shell>', is_sass=is_sass)
        self.calculator = Calculator(self.namespace)
示例#6
0
文件: core.py 项目: 7c00/staticpycon
    def handle_import(self, name, compilation, rule):
        """Implementation of the core Sass import mechanism, which just looks
        for files on disk.
        """
        # TODO virtually all of this is the same as the django stuff, except
        # for the bit that actually looks for and tries to open the file.
        # would be much easier if you could just stick an object in the search
        # path that implements the pathlib API.  the only problem is what to do
        # when one path is a child of another, so the same file has two names,
        # but tbh i'm not actually sure that's something worth protecting
        # against...?  like, the only cost is that we'll parse twice (or, later
        # on, not respect single-import), and the fix is to just Not Do That
        # TODO i think with the new origin semantics, i've made it possible to
        # import relative to the current file even if the current file isn't
        # anywhere in the search path.  is that right?
        path = PurePosixPath(name)
        if path.suffix:
            search_exts = [path.suffix]
        else:
            search_exts = ['.scss', '.sass']

        relative_to = path.parent
        basename = path.stem

        search_path = []  # tuple of (origin, start_from)
        if relative_to.is_absolute():
            relative_to = PurePosixPath(*relative_to.parts[1:])
        elif rule.source_file.origin:
            # Search relative to the current file first, only if not doing an
            # absolute import
            search_path.append(
                rule.source_file.origin / rule.source_file.relpath.parent)
        search_path.extend(compilation.compiler.search_path)

        for prefix, suffix in product(('_', ''), search_exts):
            filename = prefix + basename + suffix
            for origin in search_path:
                relpath = relative_to / filename
                # Lexically (ignoring symlinks!) eliminate .. from the part
                # of the path that exists within Sass-space.  pathlib
                # deliberately doesn't do this, but os.path does.
                relpath = PurePosixPath(os.path.normpath(str(relpath)))

                if rule.source_file.key == (origin, relpath):
                    # Avoid self-import
                    # TODO is this what ruby does?
                    continue

                path = origin / relpath
                if not path.exists():
                    continue

                # All good!
                # TODO if this file has already been imported, we'll do the
                # source preparation twice.  make it lazy.
                return SourceFile.read(origin, relpath)
示例#7
0
    def handle_import(self, name, compilation, rule):
        """Implementation of the core Sass import mechanism, which just looks
        for files on disk.
        """
        # TODO this is all not terribly well-specified by Sass.  at worst,
        # it's unclear how far "upwards" we should be allowed to go.  but i'm
        # also a little fuzzy on e.g. how relative imports work from within a
        # file that's not actually in the search path.
        # TODO i think with the new origin semantics, i've made it possible to
        # import relative to the current file even if the current file isn't
        # anywhere in the search path.  is that right?
        path = PurePosixPath(name)
        if path.suffix:
            search_exts = [path.suffix]
        else:
            search_exts = compilation.compiler.dynamic_extensions

        basename = path.stem
        relative_to = path.parent
        search_path = []  # tuple of (origin, start_from)
        if relative_to.is_absolute():
            relative_to = PurePosixPath(*relative_to.parts[1:])
        elif rule.source_file.origin:
            # Search relative to the current file first, only if not doing an
            # absolute import
            search_path.append((
                rule.source_file.origin,
                rule.source_file.relpath.parent / relative_to,
            ))
        search_path.extend(
            (origin, relative_to)
            for origin in compilation.compiler.search_path
        )

        for prefix, suffix in product(('_', ''), search_exts):
            filename = prefix + basename + suffix
            for origin, relative_to in search_path:
                relpath = relative_to / filename
                # Lexically (ignoring symlinks!) eliminate .. from the part
                # of the path that exists within Sass-space.  pathlib
                # deliberately doesn't do this, but os.path does.
                relpath = PurePosixPath(os.path.normpath(str(relpath)))

                if rule.source_file.key == (origin, relpath):
                    # Avoid self-import
                    # TODO is this what ruby does?
                    continue

                path = origin / relpath
                if not path.exists():
                    continue

                # All good!
                # TODO if this file has already been imported, we'll do the
                # source preparation twice.  make it lazy.
                return SourceFile.read(origin, relpath)
示例#8
0
    def handle_import(self, name, compilation, rule):
        """Implementation of the core Sass import mechanism, which just looks
        for files on disk.
        """
        # TODO this is all not terribly well-specified by Sass.  at worst,
        # it's unclear how far "upwards" we should be allowed to go.  but i'm
        # also a little fuzzy on e.g. how relative imports work from within a
        # file that's not actually in the search path.
        # TODO i think with the new origin semantics, i've made it possible to
        # import relative to the current file even if the current file isn't
        # anywhere in the search path.  is that right?
        path = PurePosixPath(name)

        search_exts = list(compilation.compiler.dynamic_extensions)
        if path.suffix and path.suffix in search_exts:
            basename = path.stem
        else:
            basename = path.name
        relative_to = path.parent
        search_path = []  # tuple of (origin, start_from)
        if relative_to.is_absolute():
            relative_to = PurePosixPath(*relative_to.parts[1:])
        elif rule.source_file.origin:
            # Search relative to the current file first, only if not doing an
            # absolute import
            search_path.append((
                rule.source_file.origin,
                rule.source_file.relpath.parent / relative_to,
            ))
        search_path.extend(
            (origin, relative_to)
            for origin in compilation.compiler.search_path
        )

        for prefix, suffix in product(('_', ''), search_exts):
            filename = prefix + basename + suffix
            for origin, relative_to in search_path:
                relpath = relative_to / filename
                # Lexically (ignoring symlinks!) eliminate .. from the part
                # of the path that exists within Sass-space.  pathlib
                # deliberately doesn't do this, but os.path does.
                relpath = PurePosixPath(os.path.normpath(str(relpath)))

                if rule.source_file.key == (origin, relpath):
                    # Avoid self-import
                    # TODO is this what ruby does?
                    continue

                path = origin / relpath
                if not path.exists():
                    continue

                # All good!
                # TODO if this file has already been imported, we'll do the
                # source preparation twice.  make it lazy.
                return SourceFile.read(origin, relpath)
示例#9
0
def do_build(options, args):
    if options.output is not None:
        out = open(options.output, 'wb')
    else:
        out = sys.stdout
        # Get the unencoded stream on Python 3
        out = getattr(out, 'buffer', out)

    css = Scss(
        scss_opts={
            'style': options.style,
            'debug_info': options.debug_info,
        },
        search_paths=options.load_paths,
    )
    if not args:
        args = ['-']
    source_files = []
    for path in args:
        if path == '-':
            source = SourceFile.from_file(sys.stdin,
                                          relpath="<stdin>",
                                          is_sass=options.is_sass)
        else:
            source = SourceFile.from_filename(path, is_sass=options.is_sass)
        source_files.append(source)

    encodings = set(source.encoding for source in source_files)
    if len(encodings) > 1:
        sys.stderr.write("Can't combine these files!  "
                         "They have different encodings: {0}\n".format(
                             ', '.join(encodings)))
        sys.exit(3)

    output = css.compile(source_files=source_files)
    out.write(output.encode(source_files[0].encoding))

    for f, t in profiling.items():
        sys.stderr.write("%s took %03fs" % (f, t))
示例#10
0
 def compile(self, *paths):
     compilation = self.make_compilation()
     for path in paths:
         path = PurePath(path)
         if path.is_absolute():
             path = path.relative_to('/')
         filename, storage = get_file_and_storage(str(path))
         with storage.open(filename) as f:
             source = SourceFile.from_file(f,
                                           origin=path.parent,
                                           relpath=PurePath(path.name))
         compilation.add_source(source)
     return self.call_and_catch_errors(compilation.run)
示例#11
0
文件: tool.py 项目: 7c00/staticpycon
def do_build(options, args):
    if options.output is not None:
        out = open(options.output, 'wb')
    else:
        out = sys.stdout
        # Get the unencoded stream on Python 3
        out = getattr(out, 'buffer', out)

    css = Scss(scss_opts={
        'style': options.style,
        'debug_info': options.debug_info,
    },
        search_paths=options.load_paths,
    )
    if not args:
        args = ['-']
    source_files = []
    for path in args:
        if path == '-':
            source = SourceFile.from_file(sys.stdin, relpath="<stdin>", is_sass=options.is_sass)
        else:
            source = SourceFile.from_filename(path, is_sass=options.is_sass)
        source_files.append(source)

    encodings = set(source.encoding for source in source_files)
    if len(encodings) > 1:
        sys.stderr.write(
            "Can't combine these files!  "
            "They have different encodings: {0}\n"
            .format(', '.join(encodings))
        )
        sys.exit(3)

    output = css.compile(source_files=source_files)
    out.write(output.encode(source_files[0].encoding))

    for f, t in profiling.items():
        sys.stderr.write("%s took %03fs" % (f, t))
示例#12
0
文件: core.py 项目: incidunt/pyScss
    def handle_import(self, name, compilation, rule):
        """Implementation of the core Sass import mechanism, which just looks
        for files on disk.
        """
        name, ext = os.path.splitext(name)
        if ext:
            search_exts = [ext]
        else:
            search_exts = ['.scss', '.sass']

        dirname, basename = os.path.split(name)

        # Search relative to the importing file first
        search_path = [
            os.path.normpath(os.path.abspath(
                os.path.dirname(rule.source_file.path)))]
        search_path.extend(compilation.compiler.search_path)

        for prefix, suffix in product(('_', ''), search_exts):
            filename = prefix + basename + suffix
            for directory in search_path:
                path = os.path.normpath(
                    os.path.join(directory, dirname, filename))

                if path == rule.source_file.path:
                    # Avoid self-import
                    # TODO is this what ruby does?
                    continue

                if not os.path.exists(path):
                    continue

                # Ensure that no one used .. to escape the search path
                for valid_path in compilation.compiler.search_path:
                    rel = os.path.relpath(path, start=valid_path)
                    if not rel.startswith('../'):
                        break
                else:
                    continue

                # All good!
                return SourceFile.from_filename(path)
示例#13
0
文件: core.py 项目: verysure/pyScss
    def handle_import(self, name, compilation, rule):
        """Implementation of the core Sass import mechanism, which just looks
        for files on disk.
        """
        name, ext = os.path.splitext(name)
        if ext:
            search_exts = [ext]
        else:
            search_exts = ['.scss', '.sass']

        dirname, basename = os.path.split(name)

        # Search relative to the importing file first
        search_path = [
            os.path.normpath(os.path.abspath(
                os.path.dirname(rule.source_file.path)))]
        search_path.extend(compilation.compiler.search_path)

        for prefix, suffix in product(('_', ''), search_exts):
            filename = prefix + basename + suffix
            for directory in search_path:
                path = os.path.normpath(
                    os.path.join(directory, dirname, filename))

                if path == rule.source_file.path:
                    # Avoid self-import
                    # TODO is this what ruby does?
                    continue

                if not os.path.exists(path):
                    continue

                # Ensure that no one used .. to escape the search path
                for valid_path in compilation.compiler.search_path:
                    rel = os.path.relpath(path, start=valid_path)
                    if not rel.startswith('../'):
                        break
                else:
                    continue

                # All good!
                return SourceFile.from_filename(path)
示例#14
0
    def handle_import(self, name, compilation, rule):
        """
        Re-implementation of the core Sass import mechanism, which looks for
        files using the staticfiles storage and staticfiles finders.
        """
        original_path = PurePath(name)

        search_exts = list(compilation.compiler.dynamic_extensions)
        if original_path.suffix and original_path.suffix in search_exts:
            basename = original_path.stem
        else:
            basename = original_path.name

        if original_path.is_absolute() or name[
                0] == '/':  # such that name like '/path/to/file.scss' works on Windows
            # Remove the beginning slash
            search_path = original_path.relative_to('/').parent
        elif rule.source_file.origin:
            search_path = rule.source_file.origin
            if original_path.parent:
                search_path = os.path.normpath(
                    str(search_path / original_path.parent))
        else:
            search_path = original_path.parent

        for prefix, suffix in product(('_', ''), search_exts):
            filename = PurePath(prefix + basename + suffix)

            full_filename, storage = get_file_and_storage(
                str(search_path / filename))

            if full_filename:
                with storage.open(full_filename) as f:
                    return SourceFile.from_file(f,
                                                origin=search_path,
                                                relpath=filename)
示例#15
0
    def compile(self,
                scss_string=None,
                scss_file=None,
                source_files=None,
                super_selector=None,
                filename=None,
                is_sass=None,
                line_numbers=True,
                import_static_css=False):
        """Compile Sass to CSS.  Returns a single CSS string.

        This method is DEPRECATED; see :mod:`scss.compiler` instead.
        """
        # Derive our root namespace
        self.scss_vars = _default_scss_vars.copy()
        if self._scss_vars is not None:
            self.scss_vars.update(self._scss_vars)

        root_namespace = Namespace(
            variables=self.scss_vars,
            functions=self._library,
        )

        # Figure out search paths.  Fall back from provided explicitly to
        # defined globally to just searching the current directory
        search_paths = ['.']
        if self._search_paths is not None:
            assert not isinstance(self._search_paths, six.string_types), \
                "`search_paths` should be an iterable, not a string"
            search_paths.extend(self._search_paths)
        else:
            if config.LOAD_PATHS:
                if isinstance(config.LOAD_PATHS, six.string_types):
                    # Back-compat: allow comma-delimited
                    search_paths.extend(config.LOAD_PATHS.split(','))
                else:
                    search_paths.extend(config.LOAD_PATHS)

            search_paths.extend(self._scss_opts.get('load_paths', []))

        # Normalize a few old styles of options
        output_style = self._scss_opts.get('style', config.STYLE)
        if output_style is True:
            output_style = 'compressed'
        elif output_style is False:
            output_style = 'legacy'

        fixed_search_path = []
        for path in search_paths:
            if isinstance(path, six.string_types):
                fixed_search_path.append(Path(path))
            else:
                fixed_search_path.append(path)

        # Build the compiler
        compiler = Compiler(
            namespace=root_namespace,
            extensions=[
                CoreExtension,
                ExtraExtension,
                FontsExtension,
                CompassExtension,
                BootstrapExtension,
            ],
            search_path=fixed_search_path,
            import_static_css=import_static_css,
            live_errors=self.live_errors,
            generate_source_map=self._scss_opts.get('debug_info', False),
            output_style=output_style,
            warn_unused_imports=self._scss_opts.get('warn_unused', False),
            ignore_parse_errors=config.DEBUG,
            loops_have_own_scopes=config.CONTROL_SCOPING,
            undefined_variables_fatal=config.FATAL_UNDEFINED,
            super_selector=super_selector or self.super_selector,
        )
        # Gonna add the source files manually
        compilation = compiler.make_compilation()

        # Inject the files we know about
        # TODO how does this work with the expectation of absoluteness
        if source_files is not None:
            for source in source_files:
                compilation.add_source(source)
        elif scss_string is not None:
            source = SourceFile.from_string(
                scss_string,
                relpath=filename,
                is_sass=is_sass,
            )
            compilation.add_source(source)
        elif scss_file is not None:
            # This is now the only way to allow forcibly overriding the
            # filename a source "thinks" it is
            with open(scss_file, 'rb') as f:
                source = SourceFile.from_file(
                    f,
                    relpath=filename or scss_file,
                    is_sass=is_sass,
                )
            compilation.add_source(source)

        # Plus the ones from the constructor
        if self._scss_files:
            for name, contents in list(self._scss_files.items()):
                source = SourceFile.from_string(contents, relpath=name)
                compilation.add_source(source)

        return compiler.call_and_catch_errors(compilation.run)
示例#16
0
文件: legacy.py 项目: Alpus/Eth
    def compile(
            self, scss_string=None, scss_file=None, source_files=None,
            super_selector=None, filename=None, is_sass=None,
            line_numbers=True, import_static_css=False):
        """Compile Sass to CSS.  Returns a single CSS string.

        This method is DEPRECATED; see :mod:`scss.compiler` instead.
        """
        # Derive our root namespace
        self.scss_vars = _default_scss_vars.copy()
        if self._scss_vars is not None:
            self.scss_vars.update(self._scss_vars)

        root_namespace = Namespace(
            variables=self.scss_vars,
            functions=self._library,
        )

        # Figure out search paths.  Fall back from provided explicitly to
        # defined globally to just searching the current directory
        search_paths = ['.']
        if self._search_paths is not None:
            assert not isinstance(self._search_paths, six.string_types), \
                "`search_paths` should be an iterable, not a string"
            search_paths.extend(self._search_paths)
        else:
            if config.LOAD_PATHS:
                if isinstance(config.LOAD_PATHS, six.string_types):
                    # Back-compat: allow comma-delimited
                    search_paths.extend(config.LOAD_PATHS.split(','))
                else:
                    search_paths.extend(config.LOAD_PATHS)

            search_paths.extend(self._scss_opts.get('load_paths', []))

        # Normalize a few old styles of options
        output_style = self._scss_opts.get('style', config.STYLE)
        if output_style is True:
            output_style = 'compressed'
        elif output_style is False:
            output_style = 'legacy'

        fixed_search_path = []
        for path in search_paths:
            if isinstance(path, six.string_types):
                fixed_search_path.append(Path(path))
            else:
                fixed_search_path.append(path)

        # Build the compiler
        compiler = Compiler(
            namespace=root_namespace,
            extensions=[
                CoreExtension,
                ExtraExtension,
                FontsExtension,
                CompassExtension,
                BootstrapExtension,
            ],
            search_path=fixed_search_path,
            import_static_css=import_static_css,
            live_errors=self.live_errors,
            generate_source_map=self._scss_opts.get('debug_info', False),
            output_style=output_style,
            warn_unused_imports=self._scss_opts.get('warn_unused', False),
            ignore_parse_errors=config.DEBUG,
            loops_have_own_scopes=config.CONTROL_SCOPING,
            undefined_variables_fatal=config.FATAL_UNDEFINED,
            super_selector=super_selector or self.super_selector,
        )
        # Gonna add the source files manually
        compilation = compiler.make_compilation()

        # Inject the files we know about
        # TODO how does this work with the expectation of absoluteness
        if source_files is not None:
            for source in source_files:
                compilation.add_source(source)
        elif scss_string is not None:
            source = SourceFile.from_string(
                scss_string,
                relpath=filename,
                is_sass=is_sass,
            )
            compilation.add_source(source)
        elif scss_file is not None:
            # This is now the only way to allow forcibly overriding the
            # filename a source "thinks" it is
            with open(scss_file, 'rb') as f:
                source = SourceFile.from_file(
                    f,
                    relpath=filename or scss_file,
                    is_sass=is_sass,
                )
            compilation.add_source(source)

        # Plus the ones from the constructor
        if self._scss_files:
            for name, contents in list(self._scss_files.items()):
                source = SourceFile.from_string(contents, relpath=name)
                compilation.add_source(source)

        return compiler.call_and_catch_errors(compilation.run)
示例#17
0
 def compile_scss_string(self, source, debug=False):
     source_file = SourceFile.from_string(source)
     return self._compile((source_file,), debug=debug)
示例#18
0
文件: legacy.py 项目: tkhyn/pyScss
    def compile(
            self, scss_string=None, scss_file=None, source_files=None,
            super_selector=None, filename=None, is_sass=None,
            line_numbers=True):
        """Compile Sass to CSS.  Returns a single CSS string.

        This method is DEPRECATED; see :mod:`scss.compiler` instead.
        """
        # Derive our root namespace
        self.scss_vars = _default_scss_vars.copy()
        if self._scss_vars is not None:
            self.scss_vars.update(self._scss_vars)

        root_namespace = Namespace(
            variables=self.scss_vars,
            functions=self._library,
        )

        # Figure out search paths.  Fall back from provided explicitly to
        # defined globally to just searching the current directory
        search_paths = ['.']
        if self._search_paths is not None:
            assert not isinstance(self._search_paths, six.string_types), \
                "`search_paths` should be an iterable, not a string"
            search_paths.extend(self._search_paths)
        else:
            if config.LOAD_PATHS:
                if isinstance(config.LOAD_PATHS, six.string_types):
                    # Back-compat: allow comma-delimited
                    search_paths.extend(config.LOAD_PATHS.split(','))
                else:
                    search_paths.extend(config.LOAD_PATHS)

            search_paths.extend(self._scss_opts.get('load_paths', []))

        # Normalize a few old styles of options
        output_style = self._scss_opts.get('style', config.STYLE)
        if output_style is True:
            output_style = 'compressed'
        elif output_style is False:
            output_style = 'legacy'

        # Build the compiler
        compiler = Compiler(
            namespace=root_namespace,
            search_path=search_paths,
            live_errors=self.live_errors,
            generate_source_map=self._scss_opts.get('debug_info', False),
            output_style=output_style,
            warn_unused_imports=self._scss_opts.get('warn_unused', False),
            super_selector=super_selector or self.super_selector,
        )
        # Gonna add the source files manually
        compilation = compiler.make_compilation()

        # Inject the files we know about
        # TODO how does this work with the expectation of absoluteness
        if source_files is not None:
            for source in source_files:
                compilation.add_source(source)
        elif scss_string is not None:
            source = SourceFile.from_string(
                scss_string,
                path=filename,
                is_sass=is_sass,
            )
            compilation.add_source(source)
        elif scss_file is not None:
            source = SourceFile.from_filename(
                scss_file,
                path=filename,
                is_sass=is_sass,
            )
            compilation.add_source(source)

        # Plus the ones from the constructor
        if self._scss_files:
            for name, contents in list(self._scss_files.items()):
                source = SourceFile.from_string(contents, path=name)
                compilation.add_source(source)

        return compiler.call_and_catch_errors(compilation.run)
 def handle_import(self, name, compilation, rule):
     return SourceFile.from_string(
             '',
             relpath=name
         )
示例#20
0
    def handle_import(self, name, compilation, rule):
        """Implementation of Compass's "magic" imports, which generate
        spritesheets on the fly, given either a wildcard or the name of a
        directory.
        """
        from .sprites import sprite_map

        # TODO check that the found file is actually under the root
        if callable(config.STATIC_ROOT):
            files = sorted(config.STATIC_ROOT(name))
        else:
            glob_path = os.path.join(config.STATIC_ROOT, name)
            files = glob.glob(glob_path)
            files = sorted((fn[len(config.STATIC_ROOT):], None) for fn in files)

        if not files:
            return

        # Build magic context
        calculator = compilation._make_calculator(rule.namespace)
        map_name = os.path.normpath(os.path.dirname(name)).replace('\\', '_').replace('/', '_')
        kwargs = {}

        # TODO this is all kinds of busted.  rule.context hasn't existed for
        # ages.
        def setdefault(var, val):
            _var = '$' + map_name + '-' + var
            if _var in rule.context:
                kwargs[var] = calculator.interpolate(rule.context[_var], rule, self._library)
            else:
                rule.context[_var] = val
                kwargs[var] = calculator.interpolate(val, rule, self._library)
            return rule.context[_var]

        setdefault('sprite-base-class', String('.' + map_name + '-sprite', quotes=None))
        setdefault('sprite-dimensions', Boolean(False))
        position = setdefault('position', Number(0, '%'))
        spacing = setdefault('spacing', Number(0))
        repeat = setdefault('repeat', String('no-repeat', quotes=None))
        names = tuple(os.path.splitext(os.path.basename(file))[0] for file, storage in files)
        for n in names:
            setdefault(n + '-position', position)
            setdefault(n + '-spacing', spacing)
            setdefault(n + '-repeat', repeat)
        rule.context['$' + map_name + '-' + 'sprites'] = sprite_map(name, **kwargs)
        generated_code = '''
            @import "compass/utilities/sprites/base";

            // All sprites should extend this class
            // The %(map_name)s-sprite mixin will do so for you.
            #{$%(map_name)s-sprite-base-class} {
                background: $%(map_name)s-sprites;
            }

            // Use this to set the dimensions of an element
            // based on the size of the original image.
            @mixin %(map_name)s-sprite-dimensions($name) {
                @include sprite-dimensions($%(map_name)s-sprites, $name);
            }

            // Move the background position to display the sprite.
            @mixin %(map_name)s-sprite-position($name, $offset-x: 0, $offset-y: 0) {
                @include sprite-position($%(map_name)s-sprites, $name, $offset-x, $offset-y);
            }

            // Extends the sprite base class and set the background position for the desired sprite.
            // It will also apply the image dimensions if $dimensions is true.
            @mixin %(map_name)s-sprite($name, $dimensions: $%(map_name)s-sprite-dimensions, $offset-x: 0, $offset-y: 0) {
                @extend #{$%(map_name)s-sprite-base-class};
                @include sprite($%(map_name)s-sprites, $name, $dimensions, $offset-x, $offset-y);
            }

            @mixin %(map_name)s-sprites($sprite-names, $dimensions: $%(map_name)s-sprite-dimensions) {
                @include sprites($%(map_name)s-sprites, $sprite-names, $%(map_name)s-sprite-base-class, $dimensions);
            }

            // Generates a class for each sprited image.
            @mixin all-%(map_name)s-sprites($dimensions: $%(map_name)s-sprite-dimensions) {
                @include %(map_name)s-sprites(%(sprites)s, $dimensions);
            }
        ''' % {'map_name': map_name, 'sprites': ' '.join(names)}

        return SourceFile.from_string(generated_code)
示例#21
0
    def handle_import(self, name, compilation, rule):
        """Implementation of Compass's "magic" imports, which generate
        spritesheets on the fly, given either a wildcard or the name of a
        directory.
        """
        from .sprites import sprite_map

        # TODO check that the found file is actually under the root
        if callable(config.STATIC_ROOT):
            files = sorted(config.STATIC_ROOT(name))
        else:
            glob_path = os.path.join(config.STATIC_ROOT, name)
            files = glob.glob(glob_path)
            files = sorted(
                (fn[len(config.STATIC_ROOT):], None) for fn in files)

        if not files:
            return

        # Build magic context
        calculator = compilation._make_calculator(rule.namespace)
        map_name = os.path.normpath(os.path.dirname(name)).replace(
            '\\', '_').replace('/', '_')
        kwargs = {}

        # TODO this is all kinds of busted.  rule.context hasn't existed for
        # ages.
        def setdefault(var, val):
            _var = '$' + map_name + '-' + var
            if _var in rule.context:
                kwargs[var] = calculator.interpolate(rule.context[_var], rule,
                                                     self._library)
            else:
                rule.context[_var] = val
                kwargs[var] = calculator.interpolate(val, rule, self._library)
            return rule.context[_var]

        setdefault('sprite-base-class',
                   String('.' + map_name + '-sprite', quotes=None))
        setdefault('sprite-dimensions', Boolean(False))
        position = setdefault('position', Number(0, '%'))
        spacing = setdefault('spacing', Number(0))
        repeat = setdefault('repeat', String('no-repeat', quotes=None))
        names = tuple(
            os.path.splitext(os.path.basename(file))[0]
            for file, storage in files)
        for n in names:
            setdefault(n + '-position', position)
            setdefault(n + '-spacing', spacing)
            setdefault(n + '-repeat', repeat)
        rule.context['$' + map_name + '-' + 'sprites'] = sprite_map(
            name, **kwargs)
        generated_code = '''
            @import "compass/utilities/sprites/base";

            // All sprites should extend this class
            // The %(map_name)s-sprite mixin will do so for you.
            #{$%(map_name)s-sprite-base-class} {
                background: $%(map_name)s-sprites;
            }

            // Use this to set the dimensions of an element
            // based on the size of the original image.
            @mixin %(map_name)s-sprite-dimensions($name) {
                @include sprite-dimensions($%(map_name)s-sprites, $name);
            }

            // Move the background position to display the sprite.
            @mixin %(map_name)s-sprite-position($name, $offset-x: 0, $offset-y: 0) {
                @include sprite-position($%(map_name)s-sprites, $name, $offset-x, $offset-y);
            }

            // Extends the sprite base class and set the background position for the desired sprite.
            // It will also apply the image dimensions if $dimensions is true.
            @mixin %(map_name)s-sprite($name, $dimensions: $%(map_name)s-sprite-dimensions, $offset-x: 0, $offset-y: 0) {
                @extend #{$%(map_name)s-sprite-base-class};
                @include sprite($%(map_name)s-sprites, $name, $dimensions, $offset-x, $offset-y);
            }

            @mixin %(map_name)s-sprites($sprite-names, $dimensions: $%(map_name)s-sprite-dimensions) {
                @include sprites($%(map_name)s-sprites, $sprite-names, $%(map_name)s-sprite-base-class, $dimensions);
            }

            // Generates a class for each sprited image.
            @mixin all-%(map_name)s-sprites($dimensions: $%(map_name)s-sprite-dimensions) {
                @include %(map_name)s-sprites(%(sprites)s, $dimensions);
            }
        ''' % {
            'map_name': map_name,
            'sprites': ' '.join(names)
        }

        return SourceFile.from_string(generated_code)
示例#22
-1
    def handle_import(self, name, compilation, rule):
        """
        Re-implementation of the core Sass import mechanism, which looks for
        files using the staticfiles storage and staticfiles finders.
        """
        original_path = PurePath(name)

        if original_path.suffix:
            search_exts = [original_path.suffix]
        else:
            search_exts = compilation.compiler.dynamic_extensions

        if original_path.is_absolute():
            # Remove the beginning slash
            search_path = original_path.relative_to('/').parent
        elif rule.source_file.origin:
            search_path = rule.source_file.origin
            if original_path.parent:
                search_path = search_path / original_path.parent
        else:
            search_path = original_path.parent

        basename = original_path.stem

        for prefix, suffix in product(('_', ''), search_exts):
            filename = PurePath(prefix + basename + suffix)

            full_filename, storage = get_file_and_storage(str(search_path / filename))

            if full_filename:
                with storage.open(full_filename) as f:
                    return SourceFile.from_file(f, origin=search_path, relpath=filename)
示例#23
-1
 def compile(self, *paths):
     compilation = self.make_compilation()
     for path in paths:
         path = PurePath(path)
         if path.is_absolute():
             path = path.relative_to('/')
         filename, storage = get_file_and_storage(str(path))
         with storage.open(filename) as f:
             source = SourceFile.from_file(f, origin=path.parent, relpath=PurePath(path.name))
         compilation.add_source(source)
     return self.call_and_catch_errors(compilation.run)