# Copyright 2016 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.

"""Rule for testing the struct returned by a rule."""

def _strip_prefix(prefix, string):
  if not string.startswith(prefix):
    fail("%s does not start with %s" % (string, prefix))
  return string[len(prefix):len(string)]

def _success_target(ctx, msg):
  exe = ctx.outputs.executable
  dat = ctx.new_file(ctx.configuration.genfiles_dir, exe, ".dat")
  ctx.file_action(
      output=dat,
      content=msg)
  ctx.file_action(
      output=exe,
      content="cat " + dat.path + " ; echo",
      executable=True)
  return struct(runfiles=ctx.runfiles([exe, dat]))

def _impl(ctx):
  rule_ = ctx.attr.rule
  rule_name = str(rule_.label)
  exe = ctx.outputs.executable
  if ctx.attr.generates:
    prefix = rule_.label.package + "/"
    generates = sorted(ctx.attr.generates)
    generated = sorted([_strip_prefix(prefix, f.short_path)
                        for f in rule_.files])
    if generates != generated:
      fail("rule %s generates %s not %s"
           % (rule_name, repr(generated), repr(generates)))
  provides = ctx.attr.provides
  if provides:
    files = []
    commands = []
    for k in provides.keys():
      if _hasattr(rule_, k):
        v = repr(_getattr(rule_, k))
      else:
        fail(("rule %s doesn't provide attribute %s. "
              + "Its list of attributes is: %s")
             % (rule_name, k, dir(rule_)))
      file_ = ctx.new_file(ctx.configuration.genfiles_dir, exe, "." + k)
      files += [file_]
      regexp = provides[k]
      commands += [
          "if ! grep %s %s ; then echo 'bad %s:' ; cat %s ; echo ; exit 1 ; fi"
          % (repr(regexp), file_.short_path, k, file_.short_path)]
      ctx.file_action(output=file_, content=v)
    script = "\n".join(commands + ["true"])
    ctx.file_action(output=exe, content=script, executable=True)
    return struct(runfiles=ctx.runfiles([exe] + files))
  else:
    return _success_target(ctx, "success")

def _hasattr(obj, name):
  for label in name.split("."):
    if not hasattr(obj, label):
      return False
    obj = getattr(obj, label)
  return True

def _getattr(obj, name):
  for label in name.split("."):
    if not hasattr(obj, label):
      return False
    obj = getattr(obj, label)
  return obj

rule_test = rule(
    attrs = {
        "rule": attr.label(mandatory = True),
        "generates": attr.string_list(),
        "provides": attr.string_dict(),
    },
    executable = True,
    implementation = _impl,
    test = True)
