// Copyright 2014 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.
package com.google.devtools.build.lib.rules.filegroup;

import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
import static com.google.devtools.build.lib.packages.Type.STRING;
import static com.google.devtools.build.lib.packages.Types.STRING_LIST;

import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.util.FileTypeSet;

/** Rule object implementing "filegroup". */
public final class FilegroupRule implements RuleDefinition {
  @Override
  public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
    // filegroup ignores any filtering set with setSrcsAllowedFiles.
    return builder
        /*<!-- #BLAZE_RULE(filegroup).ATTRIBUTE(srcs) -->
        The list of targets that are members of the file group.
        <p>
          Targets named in the <code>srcs</code> attribute will be added to the
          <code>runfiles</code> of this <code>filegroup</code> rule.
        </p>
        <p>
          It is common to use the result of a <a href="${link glob}">glob</a> expression for
          the value of the <code>srcs</code> attribute.
        </p>
        <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
        .add(attr("srcs", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
        /*<!-- #BLAZE_RULE(filegroup).ATTRIBUTE(output_group) -->
        The output group from which to gather artifacts from sources.  If this attribute is
        specified, artifacts from the specified output group of the dependencies will be exported
        instead of the default output group.
        <p>An "output group" is a category of output artifacts of a target, specified in that
          rule's implementation.
        </p>
        <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
        .add(attr("output_group", STRING))
        /*<!-- #BLAZE_RULE(filegroup).ATTRIBUTE(data) -->
        The list of files needed by this rule at runtime.
        <p>
          Targets named in the <code>data</code> attribute will be added to the
          <code>runfiles</code> of this <code>filegroup</code> rule. When the
          <code>filegroup</code> is referenced in the <code>data</code> attribute of
          another rule its <code>runfiles</code> will be added to the <code>runfiles</code>
          of the depending rule. See the <a href="${link build-ref#data}">data dependencies</a>
          section and <a href="${link common-definitions#common.data}">general documentation of
          <code>data</code></a> for more information about how to depend on and use data files.
        </p>
        <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
        .add(attr("data", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE).dontCheckConstraints())
        .add(attr("output_licenses", STRING_LIST))
        /*<!-- #BLAZE_RULE(filegroup).ATTRIBUTE(path) -->
        An optional string to set a path to the files in the group, relative to the package path.
        <p>
          This attribute can be used internally by other rules depending on this
          <code>filegroup</code> to find the name of the directory holding the files.
        </p>
        <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
        .build();
  }

  @Override
  public Metadata getMetadata() {
    return RuleDefinition.Metadata.builder()
        .name("filegroup")
        .ancestors(BaseRuleClasses.NativeBuildRule.class)
        .factoryClass(Filegroup.class)
        .build();
  }
}

/*<!-- #BLAZE_RULE (NAME = filegroup, FAMILY = General)[GENERIC_RULE] -->
<p>
  Use <code>filegroup</code> to gather the outputs of a set of targets under a single
  label.
</p>

<p>
  <code>filegroup</code> is not a substitute for listing targets on the command line or
  in an attribute of another rule, because targets have many properties other than their
  outputs, which are not collected in the same way. However, it's still useful in quite
  a few cases, for example, in the <code>srcs</code> attribute of a genrule, or
  the <code>data</code> attribute of a *_binary rule.
</p>

<p>
  Using <code>filegroup</code> is encouraged instead of referencing directories directly.
  Directly referencing directories is discouraged because the build system does not have
  full knowledge of all files below the directory, so it may not rebuild when these files change.
  When combined with <a href="${link glob}">glob</a>, <code>filegroup</code> can ensure that all
  files are explicitly known to the build system.
</p>

<h4 id="filegroup_example">Examples</h4>

<p>
  To create a <code>filegroup</code> consisting of two source files, do
</p>
<pre class="code">
filegroup(
    name = "mygroup",
    srcs = [
        "a_file.txt",
        "//a/library:target",
        "//a/binary:target",
    ],
)
</pre>
<p>
  Or, use a <code>glob</code> to fully crawl a testdata directory:
</p>
<pre class="code">
filegroup(
    name = "exported_testdata",
    srcs = glob([
        "testdata/*.dat",
        "testdata/logs/**&#47;*.log",
    ]),
)
</pre>
<p>
  To make use of these definitions, reference the <code>filegroup</code> with a label from any rule:
</p>
<pre class="code">
cc_library(
    name = "my_library",
    srcs = ["foo.cc"],
    data = [
        "//my_package:exported_testdata",
        "//my_package:mygroup",
    ],
)
</pre>

<!-- #END_BLAZE_RULE -->*/
