...

Text file src/github.com/bazelbuild/buildtools/buildifier/internal/factory.bzl

Documentation: github.com/bazelbuild/buildtools/buildifier/internal

     1"""
     2This module contains factory methods for simple rule and implementation generation
     3"""
     4
     5load("@bazel_skylib//lib:shell.bzl", "shell")
     6
     7# buildifier: disable=print
     8def _value_deprecation(ctx, attr, value):
     9    """
    10    Prints a deprecation message related to a specific value for an attr.
    11
    12    Args:
    13      ctx:      The execution context
    14      attr:     A String representing the attribute name
    15      value:    The deprecated value
    16    """
    17    print("DEPRECATION NOTICE: value '%s' for attribute '%s' will be removed in the future. Migrate '%s' to buildifier_test." % (value, attr, ctx.label))
    18
    19# buildifier: disable=print
    20def _attr_deprecation(ctx, attr):
    21    """
    22    Prints an attribute deprecation message.
    23
    24    Args:
    25      ctx:      The execution context
    26      attr:     A String representing the deprecated attribute name
    27    """
    28    print("DEPRECATION NOTICE: attribute '%s' will be removed in the future. Migrate '%s' to buildifier_test." % (attr, ctx.label))
    29
    30def buildifier_attr_factory(test_rule = False):
    31    """
    32    Helper macro to generate a struct of attrs for use in a rule() definition.
    33
    34    Args:
    35      test_rule: Whether or not to generate attrs for a test rule.
    36
    37    Returns:
    38      A dictionary of attributes relevant to the rule
    39    """
    40    attrs = {
    41        "buildifier": attr.label(
    42            default = "//buildifier",
    43            cfg = "exec",
    44            executable = True,
    45        ),
    46        "verbose": attr.bool(
    47            doc = "Print verbose information on standard error",
    48        ),
    49        "exclude_patterns": attr.string_list(
    50            allow_empty = True,
    51            doc = "A list of glob patterns passed to the find command. E.g. './vendor/*' to exclude the Go vendor directory. In test rules, this attribute requires the use of the no_sandbox attribute.",
    52        ),
    53        "mode": attr.string(
    54            default = "fix" if not test_rule else "diff",
    55            doc = "Formatting mode",
    56            values = ["check", "diff", "print_if_changed"] + ["fix"] if not test_rule else [],
    57        ),
    58        "lint_mode": attr.string(
    59            doc = "Linting mode",
    60            values = ["", "warn"] + ["fix"] if not test_rule else [],
    61        ),
    62        "lint_warnings": attr.string_list(
    63            allow_empty = True,
    64            doc = "all prefixed with +/- if you want to include in or exclude from the default set of warnings, or none prefixed with +/- if you want to override the default set, or 'all' for all available warnings",
    65        ),
    66        "diff_command": attr.string(
    67            doc = "Command to use to show diff, with mode=diff. E.g. 'diff -u'",
    68        ),
    69        "multi_diff": attr.bool(
    70            default = False,
    71            doc = "Set to True if the diff command specified by the 'diff_command' can diff multiple files in the style of 'tkdiff'",
    72        ),
    73        "add_tables": attr.label(
    74            mandatory = False,
    75            doc = "path to JSON file with custom table definitions which will be merged with the built-in tables",
    76            allow_single_file = True,
    77        ),
    78        "_runner": attr.label(
    79            default = "//buildifier:runner.bash.template",
    80            allow_single_file = True,
    81        ),
    82        "_windows_runner": attr.label(
    83            default = "@com_github_bazelbuild_buildtools//buildifier:runner.bat.template",
    84            allow_single_file = True,
    85        ),
    86    }
    87
    88    if test_rule:
    89        attrs.update({
    90            "srcs": attr.label_list(
    91                allow_files = [
    92                    ".bazel",
    93                    ".bzl",
    94                    ".oss",
    95                    ".sky",
    96                    "BUILD",
    97                    "WORKSPACE",
    98                    "WORKSPACE.bzlmod",
    99                ],
   100                doc = "A list of labels representing the starlark files to include in the test",
   101            ),
   102            "no_sandbox": attr.bool(
   103                default = False,
   104                doc = "Set to True to enable running buildifier on all files in the workspace",
   105            ),
   106            "workspace": attr.label(
   107                allow_single_file = True,
   108                doc = "Label of the WORKSPACE file; required when the no-sandbox attribute is True",
   109            ),
   110        })
   111
   112    return attrs
   113
   114def buildifier_impl_factory(ctx, test_rule = False):
   115    """
   116    Helper macro to generate a buildifier or buildifier_test rule.
   117
   118    This macro does not depend on defaults encoded in the binary, instead
   119    preferring to set explicit values for each flag.
   120
   121    Args:
   122      ctx:          The execution context.
   123      test_rule:    Whether or not to generate a test rule.
   124
   125    Returns:
   126      A DefaultInfo provider
   127    """
   128
   129    if not test_rule and ctx.attr.mode in ["check", "diff", "print_if_changed"]:
   130        _value_deprecation(ctx, "mode", ctx.attr.mode)
   131
   132    args = [
   133        "-mode=%s" % ctx.attr.mode,
   134        "-v=%s" % str(ctx.attr.verbose).lower(),
   135    ]
   136
   137    if ctx.attr.lint_mode:
   138        args.append("-lint=%s" % ctx.attr.lint_mode)
   139
   140    if ctx.attr.lint_warnings:
   141        if not ctx.attr.lint_mode:
   142            fail("Cannot pass 'lint_warnings' without a 'lint_mode'")
   143        args.append("--warnings={}".format(",".join(ctx.attr.lint_warnings)))
   144
   145    if ctx.attr.multi_diff:
   146        args.append("-multi_diff")
   147        if not test_rule:
   148            _attr_deprecation(ctx, "multi_diff")
   149
   150    if ctx.attr.diff_command:
   151        args.append("-diff_command=%s" % ctx.attr.diff_command)
   152        if not test_rule:
   153            _attr_deprecation(ctx, "diff_command")
   154
   155    if ctx.attr.add_tables:
   156        args.append("-add_tables=%s" % ctx.file.add_tables.path)
   157
   158    exclude_patterns_str = ""
   159    if ctx.attr.exclude_patterns:
   160        if test_rule and not ctx.attr.no_sandbox:
   161            fail("Cannot use 'exclude_patterns' in a test rule without 'no_sandbox'")
   162        exclude_patterns = ["\\! -path %s" % shell.quote(pattern) for pattern in ctx.attr.exclude_patterns]
   163        exclude_patterns_str = " ".join(exclude_patterns)
   164
   165    workspace = ""
   166    if test_rule and ctx.attr.no_sandbox:
   167        if not ctx.file.workspace:
   168            fail("Cannot use 'no_sandbox' without a 'workspace'")
   169        workspace = ctx.file.workspace.path
   170
   171    out_file = ctx.actions.declare_file(ctx.label.name + ".bash")
   172
   173    substitutions = {
   174        "@@ARGS@@": shell.array_literal(args),
   175        "@@BUILDIFIER_SHORT_PATH@@": shell.quote(ctx.executable.buildifier.short_path),
   176        "@@EXCLUDE_PATTERNS@@": exclude_patterns_str,
   177        "@@WORKSPACE@@": workspace,
   178    }
   179
   180    if ctx.executable.buildifier.extension.lower() == "exe":
   181        out_file = ctx.actions.declare_file(ctx.label.name + ".bat")
   182        runner_template = ctx.file._windows_runner
   183    else:
   184        out_file = ctx.actions.declare_file(ctx.label.name + ".bash")
   185        runner_template = ctx.file._runner
   186
   187    ctx.actions.expand_template(
   188        template = runner_template,
   189        output = out_file,
   190        substitutions = substitutions,
   191        is_executable = True,
   192    )
   193
   194    runfiles = [ctx.executable.buildifier]
   195    if test_rule:
   196        runfiles.extend(ctx.files.srcs)
   197        if ctx.attr.no_sandbox:
   198            runfiles.append(ctx.file.workspace)
   199
   200    return DefaultInfo(
   201        files = depset([out_file]),
   202        runfiles = ctx.runfiles(files = runfiles),
   203        executable = out_file,
   204    )

View as plain text