Update some Python machinery, create sass tools
This commit is contained in:
parent
61dc694078
commit
4c75d4694a
7 changed files with 335 additions and 1 deletions
|
@ -41,7 +41,7 @@ git_repository(
|
|||
name = "rules_python",
|
||||
remote = "https://github.com/bazelbuild/rules_python.git",
|
||||
# tag = "0.4.0",
|
||||
commit = "f0efec5cf8c0ae16483ee677a09ec70737a01bf5",
|
||||
commit = "693a1587baf055979493565933f8f40225c00c6d",
|
||||
)
|
||||
|
||||
register_toolchains("//tools/python:python3_toolchain")
|
||||
|
|
|
@ -10,6 +10,12 @@ load("//tools/python:defs.bzl",
|
|||
"py_project",
|
||||
)
|
||||
|
||||
load("//tools/sass:defs.bzl",
|
||||
"multi_sass_binary",
|
||||
"sass_binary",
|
||||
"sass_library",
|
||||
)
|
||||
|
||||
load("@arrdem_source_pypi//:requirements.bzl",
|
||||
py_requirement="requirement"
|
||||
)
|
||||
|
|
|
@ -158,6 +158,7 @@ py_resources = rule(
|
|||
def py_project(name=None,
|
||||
main=None,
|
||||
main_deps=None,
|
||||
main_data=None,
|
||||
shebang=None,
|
||||
lib_srcs=None,
|
||||
lib_deps=None,
|
||||
|
@ -218,6 +219,7 @@ def py_project(name=None,
|
|||
name=name,
|
||||
main=main,
|
||||
deps=(main_deps or []) + [lib_name],
|
||||
data=(main_data or []),
|
||||
imports=[
|
||||
"src/python",
|
||||
"src/resources",
|
||||
|
|
|
@ -17,6 +17,7 @@ icmplib
|
|||
isort
|
||||
jinja2
|
||||
lark
|
||||
libsass
|
||||
livereload
|
||||
lxml
|
||||
markdown
|
||||
|
|
|
@ -39,6 +39,7 @@ jsonschema==4.17.3
|
|||
jsonschema-spec==0.1.4
|
||||
lark==1.1.5
|
||||
lazy-object-proxy==1.9.0
|
||||
libsass==0.22.0
|
||||
livereload==2.6.3
|
||||
lxml==4.9.2
|
||||
Markdown==3.4.3
|
||||
|
|
7
tools/sass/BUILD
Normal file
7
tools/sass/BUILD
Normal file
|
@ -0,0 +1,7 @@
|
|||
load("@arrdem_source_pypi//:requirements.bzl", "entry_point")
|
||||
|
||||
alias(
|
||||
name = "sassc",
|
||||
actual = entry_point("libsass", "pysassc"),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
317
tools/sass/defs.bzl
Normal file
317
tools/sass/defs.bzl
Normal file
|
@ -0,0 +1,317 @@
|
|||
# Copyright 2018 The Bazel Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"Compile Sass files to CSS"
|
||||
|
||||
_ALLOWED_SRC_FILE_EXTENSIONS = [".sass", ".scss", ".css", ".svg", ".png", ".gif", ".cur", ".jpg", ".webp"]
|
||||
|
||||
# Documentation for switching which compiler is used
|
||||
_COMPILER_ATTR_DOC = """Choose which Sass compiler binary to use.
|
||||
|
||||
By default, we use the JavaScript-transpiled version of the
|
||||
dart-sass library, based on https://github.com/sass/dart-sass.
|
||||
This is the canonical compiler under active development by the Sass team.
|
||||
This compiler is convenient for frontend developers since it's released
|
||||
as JavaScript and can run natively in NodeJS without being locally built.
|
||||
While the compiler can be configured, there are no other implementations
|
||||
explicitly supported at this time. In the future, there will be an option
|
||||
to run Dart Sass natively in the Dart VM. This option depends on the Bazel
|
||||
rules for Dart, which are currently not actively maintained (see
|
||||
https://github.com/dart-lang/rules_dart).
|
||||
"""
|
||||
|
||||
SassInfo = provider(
|
||||
doc = "Collects files from sass_library for use in downstream sass_binary",
|
||||
fields = {
|
||||
"transitive_sources": "Sass sources for this target and its dependencies",
|
||||
},
|
||||
)
|
||||
|
||||
def _collect_transitive_sources(srcs, deps):
|
||||
"Sass compilation requires all transitive .sass source files"
|
||||
return depset(
|
||||
srcs,
|
||||
transitive = [dep[SassInfo].transitive_sources for dep in deps],
|
||||
# Provide .sass sources from dependencies first
|
||||
order = "postorder",
|
||||
)
|
||||
|
||||
def _sass_library_impl(ctx):
|
||||
"""sass_library collects all transitive sources for given srcs and deps.
|
||||
|
||||
It doesn't execute any actions.
|
||||
|
||||
Args:
|
||||
ctx: The Bazel build context
|
||||
|
||||
Returns:
|
||||
The sass_library rule.
|
||||
"""
|
||||
transitive_sources = _collect_transitive_sources(
|
||||
ctx.files.srcs,
|
||||
ctx.attr.deps,
|
||||
)
|
||||
return [
|
||||
SassInfo(transitive_sources = transitive_sources),
|
||||
DefaultInfo(
|
||||
files = transitive_sources,
|
||||
runfiles = ctx.runfiles(transitive_files = transitive_sources),
|
||||
),
|
||||
]
|
||||
|
||||
def _run_sass(ctx, input, css_output, map_output = None):
|
||||
"""run_sass performs an action to compile a single Sass file into CSS."""
|
||||
|
||||
# The Sass CLI expects inputs like
|
||||
# sass <flags> <input_filename> <output_filename>
|
||||
args = ctx.actions.args()
|
||||
|
||||
# Flags (see https://github.com/sass/dart-sass/blob/master/lib/src/executable/options.dart)
|
||||
args.add_joined(["--style", ctx.attr.output_style], join_with = "=")
|
||||
|
||||
if ctx.attr.sourcemap:
|
||||
args.add("--sourcemap")
|
||||
if ctx.attr.sourcemap_embed_sources:
|
||||
args.add("--sourcemap-contents")
|
||||
|
||||
# Sources for compilation may exist in the source tree, in bazel-bin, or bazel-genfiles.
|
||||
for prefix in [".", ctx.var["BINDIR"], ctx.var["GENDIR"]]:
|
||||
args.add("--include-path=%s/" % prefix)
|
||||
for include_path in ctx.attr.include_paths:
|
||||
args.add("--include-path=%s/%s" % (prefix, include_path))
|
||||
|
||||
# Last arguments are input and output paths
|
||||
# Note that the sourcemap is implicitly written to a path the same as the
|
||||
# css with the added .map extension.
|
||||
args.add_all([input.path, css_output.path])
|
||||
|
||||
ctx.actions.run(
|
||||
mnemonic = "SassCompiler",
|
||||
executable = ctx.executable.compiler,
|
||||
inputs = _collect_transitive_sources([input], ctx.attr.deps),
|
||||
tools = [ctx.executable.compiler],
|
||||
arguments = [args],
|
||||
outputs = [css_output, map_output] if map_output else [css_output],
|
||||
use_default_shell_env = True,
|
||||
)
|
||||
|
||||
def _sass_binary_impl(ctx):
|
||||
# Make sure the output CSS is available in runfiles if used as a data dep.
|
||||
if ctx.attr.sourcemap:
|
||||
map_file = ctx.outputs.map_file
|
||||
outputs = [ctx.outputs.css_file, map_file]
|
||||
else:
|
||||
map_file = None
|
||||
outputs = [ctx.outputs.css_file]
|
||||
|
||||
_run_sass(ctx, ctx.file.src, ctx.outputs.css_file, map_file)
|
||||
return DefaultInfo(runfiles = ctx.runfiles(files = outputs))
|
||||
|
||||
def _sass_binary_outputs(src, output_name, output_dir, sourcemap):
|
||||
"""Get map of sass_binary outputs, including generated css and sourcemaps.
|
||||
|
||||
Note that the arguments to this function are named after attributes on the rule.
|
||||
|
||||
Args:
|
||||
src: The rule's `src` attribute
|
||||
output_name: The rule's `output_name` attribute
|
||||
output_dir: The rule's `output_dir` attribute
|
||||
sourcemap: The rule's `sourcemap` attribute
|
||||
|
||||
Returns:
|
||||
Outputs for the sass_binary
|
||||
"""
|
||||
|
||||
output_name = output_name or _strip_extension(src.name) + ".css"
|
||||
css_file = "/".join([p for p in [output_dir, output_name] if p])
|
||||
|
||||
outputs = {
|
||||
"css_file": css_file,
|
||||
}
|
||||
|
||||
if sourcemap:
|
||||
outputs["map_file"] = "%s.map" % css_file
|
||||
|
||||
return outputs
|
||||
|
||||
def _strip_extension(path):
|
||||
"""Removes the final extension from a path."""
|
||||
components = path.split(".")
|
||||
components.pop()
|
||||
return ".".join(components)
|
||||
|
||||
sass_deps_attr = attr.label_list(
|
||||
doc = "sass_library targets to include in the compilation",
|
||||
providers = [SassInfo],
|
||||
allow_files = False,
|
||||
)
|
||||
|
||||
_sass_library_attrs = {
|
||||
"srcs": attr.label_list(
|
||||
doc = "Sass source files",
|
||||
allow_files = _ALLOWED_SRC_FILE_EXTENSIONS,
|
||||
allow_empty = False,
|
||||
mandatory = True,
|
||||
),
|
||||
"deps": sass_deps_attr,
|
||||
}
|
||||
|
||||
sass_library = rule(
|
||||
implementation = _sass_library_impl,
|
||||
attrs = _sass_library_attrs,
|
||||
)
|
||||
"""Defines a group of Sass include files.
|
||||
"""
|
||||
|
||||
_sass_binary_attrs = {
|
||||
"src": attr.label(
|
||||
doc = "Sass entrypoint file",
|
||||
mandatory = True,
|
||||
allow_single_file = _ALLOWED_SRC_FILE_EXTENSIONS,
|
||||
),
|
||||
"sourcemap": attr.bool(
|
||||
default = True,
|
||||
doc = "Whether source maps should be emitted.",
|
||||
),
|
||||
"sourcemap_embed_sources": attr.bool(
|
||||
default = False,
|
||||
doc = "Whether to embed source file contents in source maps.",
|
||||
),
|
||||
"include_paths": attr.string_list(
|
||||
doc = "Additional directories to search when resolving imports",
|
||||
),
|
||||
"output_dir": attr.string(
|
||||
doc = "Output directory, relative to this package.",
|
||||
default = "",
|
||||
),
|
||||
"output_name": attr.string(
|
||||
doc = """Name of the output file, including the .css extension.
|
||||
|
||||
By default, this is based on the `src` attribute: if `styles.scss` is
|
||||
the `src` then the output file is `styles.css.`.
|
||||
You can override this to be any other name.
|
||||
Note that some tooling may assume that the output name is derived from
|
||||
the input name, so use this attribute with caution.""",
|
||||
default = "",
|
||||
),
|
||||
"output_style": attr.string(
|
||||
doc = "How to style the compiled CSS",
|
||||
default = "compressed",
|
||||
values = [
|
||||
"expanded",
|
||||
"compressed",
|
||||
],
|
||||
),
|
||||
"deps": sass_deps_attr,
|
||||
"compiler": attr.label(
|
||||
doc = _COMPILER_ATTR_DOC,
|
||||
default = Label(":sassc"),
|
||||
executable = True,
|
||||
allow_files = True,
|
||||
cfg = "host",
|
||||
),
|
||||
}
|
||||
|
||||
sass_binary = rule(
|
||||
implementation = _sass_binary_impl,
|
||||
attrs = _sass_binary_attrs,
|
||||
outputs = _sass_binary_outputs,
|
||||
)
|
||||
|
||||
def _multi_sass_binary_impl(ctx):
|
||||
"""multi_sass_binary accepts a list of sources and compile all in one pass.
|
||||
|
||||
Args:
|
||||
ctx: The Bazel build context
|
||||
|
||||
Returns:
|
||||
The multi_sass_binary rule.
|
||||
"""
|
||||
|
||||
inputs = ctx.files.srcs
|
||||
outputs = []
|
||||
# Every non-partial Sass file will produce one CSS output file and,
|
||||
# optionally, one sourcemap file.
|
||||
for f in inputs:
|
||||
# Sass partial files (prefixed with an underscore) do not produce any
|
||||
# outputs.
|
||||
if f.basename.startswith("_"):
|
||||
continue
|
||||
name = _strip_extension(f.basename)
|
||||
outputs.append(ctx.actions.declare_file(
|
||||
name + ".css",
|
||||
sibling = f,
|
||||
))
|
||||
if ctx.attr.sourcemap:
|
||||
outputs.append(ctx.actions.declare_file(
|
||||
name + ".css.map",
|
||||
sibling = f,
|
||||
))
|
||||
|
||||
# Use the package directory as the compilation root given to the Sass compiler
|
||||
root_dir = (ctx.label.workspace_root + "/" if ctx.label.workspace_root else "") + ctx.label.package
|
||||
|
||||
# Declare arguments passed through to the Sass compiler.
|
||||
# Start with flags and then expected program arguments.
|
||||
args = ctx.actions.args()
|
||||
args.add("--style", ctx.attr.output_style)
|
||||
args.add("--load-path", root_dir)
|
||||
|
||||
if not ctx.attr.sourcemap:
|
||||
args.add("--no-source-map")
|
||||
|
||||
args.add(root_dir + ":" + ctx.bin_dir.path + '/' + root_dir)
|
||||
args.use_param_file("@%s", use_always = True)
|
||||
args.set_param_file_format("multiline")
|
||||
|
||||
if inputs:
|
||||
ctx.actions.run(
|
||||
inputs = inputs,
|
||||
outputs = outputs,
|
||||
executable = ctx.executable.compiler,
|
||||
arguments = [args],
|
||||
mnemonic = "SassCompiler",
|
||||
progress_message = "Compiling Sass",
|
||||
)
|
||||
|
||||
return [DefaultInfo(files = depset(outputs))]
|
||||
|
||||
multi_sass_binary = rule(
|
||||
implementation = _multi_sass_binary_impl,
|
||||
attrs = {
|
||||
"srcs": attr.label_list(
|
||||
doc = "A list of Sass files and associated assets to compile",
|
||||
allow_files = _ALLOWED_SRC_FILE_EXTENSIONS,
|
||||
allow_empty = True,
|
||||
mandatory = True,
|
||||
),
|
||||
"sourcemap": attr.bool(
|
||||
doc = "Whether sourcemaps should be emitted",
|
||||
default = True,
|
||||
),
|
||||
"output_style": attr.string(
|
||||
doc = "How to style the compiled CSS",
|
||||
default = "compressed",
|
||||
values = [
|
||||
"expanded",
|
||||
"compressed",
|
||||
],
|
||||
),
|
||||
"compiler": attr.label(
|
||||
doc = _COMPILER_ATTR_DOC,
|
||||
default = Label(":sassc"),
|
||||
executable = True,
|
||||
cfg = "host",
|
||||
),
|
||||
}
|
||||
)
|
Loading…
Reference in a new issue