github.phpd.cn/thought-machine/please@v12.2.0+incompatible/docs/intermediate.html (about)

     1  
     2      <h1>Intermediate Please</h1>
     3  
     4      <p>Okay, you've read the <a href="basics.html">basics</a>, so what's next?</p>
     5  
     6      <h2>BUILD file format</h2>
     7      <p>We didn't talk much about the actual format of BUILD files last time, but an astute observer may
     8        have noticed that the rule invocations look rather like Python. This is not coincidence; BUILD files
     9        are interpreted as a (slightly) restricted subset of Python.</p>
    10  
    11      <p>So what can you do with them? Well, let's say you want to translate your documentation to a bunch of languages:
    12        <pre><code>
    13  	  for language in ['en_NZ', 'en_GB', 'it_IT', 'es_MX', 'el_GR']:
    14  	      genrule(
    15  	          name = 'txt_documentation_' + language,
    16  	          srcs = ['docs.txt'],
    17  	          outs = ['docs_%s.txt' % language],
    18  	          cmd = 'cat $SRC | $(exe //tools:translate_tool) --language %s > $OUT' % language,
    19  	      )
    20  
    21  	      genrule(
    22  	          name = 'documentation_' + language,
    23  	          srcs = [':txt_documentation_' + language],
    24                    outs = ['docs_%s.html' % language],
    25                    cmd = '$(exe //tools:html_doc_tool) --src $SRC --out $OUT',
    26  	          visibility = ['PUBLIC'],
    27            )
    28        </code></pre>
    29  
    30        Obviously this would be a bit repetitive if you redefined the rules separately for each language. Instead, we can take
    31        advantage of the build language to genericise them across languages; for each language we translate it and then
    32        format it as HTML.
    33      </p>
    34  
    35      <h2>Custom build rules</h2>
    36  
    37      <p>While the above is perfectly readable, having to define two rules each time is a bit tedious;
    38        maybe we'd rather define one rule to perform the translation & HTML conversion in one pass.
    39  
    40        <b>docs/documentation_rules.build_defs:</b><br/>
    41        <pre><code>
    42  	  def create_html_docs(name, language, srcs, visibility=None):
    43  	      """Converts documentation to the given language and then to HTML."""
    44  	      genrule(
    45  	          name = '_%s_%s#translate' % (name, language),
    46  	          srcs=srcs,
    47                    outs = ['_%s_%s_translated.txt' % (name, language)],
    48  	          cmd = 'cat $SRC | $(exe //tools:translate_tool) --language %s > $OUT' % language,
    49  	      )
    50  	      genrule(
    51  	          name = '%s_%s' % (name, language),
    52  	          srcs = [':_%s_%s#translate' % (name, language)],
    53                    outs = ['%s_%s.html' % (name, language)],
    54                    cmd = '$(exe //tools:html_doc_tool) --src $SRC --out $OUT',
    55  	          visibility = ['PUBLIC'],
    56                )
    57        </code></pre>
    58        <b>docs/BUILD:</b><br/>
    59        <pre><code>
    60  	  include_defs('//docs/documentation_rules.build_defs')
    61  	  for language in ['en_NZ', 'en_GB', 'it_IT', 'es_MX', 'el_GR']:
    62  	      create_html_docs(
    63  	          name = 'docs',
    64  	          language = language,
    65  	          srcs = ['docs.txt'],
    66                    visibility = ['PUBLIC'],
    67                )
    68        </code></pre>
    69      </p>
    70  
    71      <p>This example is getting a little strained, but serves to illustrate how you can create something that acts
    72        like a single build rule, but internally creates multiple steps to produce the final result. Since the BUILD
    73        files are essentially Python it's as simple as defining a function.</p>
    74  
    75      <p>Note the microformat of defining 'internal' private rules with a leading underscore and trailing hashtag;
    76        in the interactive build mode those will be omitted to make it appear to users as though they're building
    77        the rule they defined by name, even though internally it's split into multiple rules.</p>
    78  
    79      <h2>Transitive dependencies</h2>
    80  
    81      <p>Writing some rules requires that the transitive set of dependencies are available when they're built.</p>
    82  
    83      <p>For example, consider <code>cc_binary</code>; all your <code>cc_library</code> rules have created a bunch of .o files,
    84        but each of those only has its own set of symbols. The final binary rule must link all of them together to produce
    85        a working executable.</p>
    86  
    87      <p>Fortunately, this is pretty easy in Please. You can apply <code>needs_transitive_deps = True</code> to a
    88        <code>genrule</code> to make them all available at build time. This is easy to do but of course shouldn't be taken
    89        lightly since it will slow the rule down (needs more time to prepare sources) and may harm incrementality.<br/>
    90        The typical pattern is that <code>_library</code> rules don't need this but <code>_binary</code> and <code>_test</code>
    91        rules do, although this is somewhat dependent on the language.</p>
    92  
    93      <h2>gentest</h2>
    94  
    95      <p><code>gentest</code> is similar to <code>genrule</code> but defines a target that runs an arbitrary test. The
    96        <code>test_cmd</code> attribute defines the command to run; this is often simply <code>$(exe :rule_name)</code>
    97        to run its own output.</p>
    98  
    99      <p>The protocol for tests to follow is pretty simple; the test command should return zero on success or nonzero
   100        for failure (Unix FTW). The test should also write either a file called <code>test.results</code> or multiple files
   101        into a directory named the same; these are parsed as one of the formats Please understands (currently either
   102        xUnit XML or Go's test output format). Optionally a test can be marked with <code>no_test_output = True</code>
   103        to indicate that it writes no files, in which case its return value is the only indicator of success.</p>
   104  
   105      <h2>Labels</h2>
   106  
   107      <p>Rules, particularly the various <code>_test</code> rules can have an optional set of <em>labels</em> associated with
   108        them. These are essentially just a set of tags that can be used to filter them when run via <code>plz test</code>,
   109        for example <code>plz test ... --include py</code> will run all your tests labelled with 'py',
   110        and <code>plz test ... --exclude slow</code> will run all your tests except those labelled with 'slow'.</p>
   111  
   112      <p>The syntax looks like:
   113        <pre><code>
   114          go_test(
   115              name = 'my_test',
   116              srcs = ['my_test.go'],
   117              labels = ['slow', 'integration'],
   118          )
   119        </code></pre>
   120      </p>
   121  
   122      <p>There is one special label, <code>manual</code> which always excludes tests from autodetection when being run with
   123        <code>plz test //mypackage:all</code> or <code>plz test //mypackage/...</code>. This is often useful to disable tests
   124        from general usage if needed (for example, if a test starts failing, you can disable it while investigating).</p>
   125  
   126      <h2>Flaky tests</h2>
   127  
   128      <p>Tests can be marked as <em>flaky</em> which causes them to be automatically re-run several times. They are considered
   129        to pass if any one run passes.</p>
   130  
   131      <p>The syntax looks like:
   132        <pre><code>
   133          go_test(
   134              name = 'my_test',
   135              srcs = ['my_test.go'],
   136              flaky = True,
   137          )
   138        </code></pre>
   139        By default they are run three times, you can alter this on a per-test basis by passing an integer instead of a boolean.
   140      </p>
   141  
   142      <p>The <code>--max_flakes</code> flag can be used to cap the number of re-runs allowed on a single invocation.</p>
   143  
   144      <h2>Containerised tests</h2>
   145  
   146      <p>Tests can also be marked as <em>containerised</em> so they are isolated within a container for the duration of their run.
   147        One main advantage of this is for integration tests that need to open ports and start servers, which are then insulated
   148        from port clashes against one another.</p>
   149  
   150      <p>Within the container the test will have access only to the data it's declared it needs at runtime, so you will have
   151        to be correct about declaring all such dependencies (but of course one would do that anyway...).</p>
   152  
   153      <p>The syntax looks like:
   154        <pre><code>
   155          go_test(
   156              name = 'my_test',
   157              srcs = ['my_test.go'],
   158              container = True,
   159          )
   160        </code></pre>
   161      </p>
   162  
   163      <p>Currently we support Docker as a container format, we plan to support rkt containers in a future release.</p>
   164  
   165      <h2>build_rule</h2>
   166  
   167      <p><code>build_rule</code> is the fundamental unit all other build rules are built from. We discussed <code>genrule</code>
   168        just now which is very similar; <code>build_rule</code> allows control over more esoteric features of the system.</p>
   169  
   170      <p>The difference between <code>genrule</code> and <code>build_rule</code> from a user's perspective is pretty arbitrary;
   171        conventionally we use <code>genrule</code> in build files for defining arbitrary build transformations and
   172        <code>build_rule</code> for defining other rules, but there's no particularly principled reason for this.</p>
   173  
   174      <h2>What else?</h2>
   175  
   176      <p>If you're still curious about what more can be done, try <a href="advanced.html">the advanced stuff</a>.</p>