The Pants Build System

Overview

Today we’re learning the essentials. Practical knowledge that will help you get stuff done.

  • We assume you write code and have used build systems - just not pants.
  • Quick review of what build systems do, and what they don’t do.
  • High-level overview of how pants works.
  • Learn how to use and configure pants.
  • Demo of using pants.

10,000-Foot View of Pants

Targets - "nouns" of the build

pants_essentials_techtalk__1.png
  • Targets describe things that can be built.
  • They’re typed.
  • They typically have dependencies.
  • Each language has its own types: java_library vs python_library

Goals - "verbs" of the build

pants_essentials_techtalk__2.png
  • You give Pants one or more goals, like test
  • Within a goal might be a few tasks. E.g., test has junit, pytest.
  • Many tasks are no-ops. E.g., pytest for java code.
  • One task can require the product of another. E.g., junit needs classes from jvm compile.
  • Thus, Pants figures out order of operations.

Let’s Walk Through a Build

./pants goal test
  examples/src/java/com/pants/examples/hello/main
  examples/tests/java/com/pants/examples/hello/greet
pants_essentials_techtalk__3.png
pants_essentials_techtalk__4.png
  • gen sees our thrift, generates Java.
  • resolve fetches jars from maven repo
  • compile compiles our source, plus generated from thrift
  • test runs tests
  • Not much happens to the jvm_binary.

Anatomy of a Pants Command-Line

Pants is exclusively controlled via its command-line interface. Learn to use it well.

./pants goal goalname [flags] [goalname ...] [flags] target [target ...]
./pants goal goals
./pants goal mygoal -h
  • Command lines specify one or more goals, one or more targets, and options.

Target Addresses

An address is filesystem path to a BUILD file combined with a target name

path/to/mybird:mybird
path/to/mybird  (target with same name as dir)
:mybird  (in the same build file)

Command Line-only conveniences:

path/to/mybird/:mybird
path/to/mybird/
path/to/mybird: (wildcard)
path/to/mybird:: (recursive wildcard)
path/to/mybird/BUILD:

Targets

Here’s a simple library target. You might find this in src/java/com/twitter/mybird/BUILD.

java_library(name='mybird',
  dependencies=[
    '3rdparty/jvm:guava',
    'src/java/com/mycom/otherbird/common',
  ],
  sources=globs('*.java'),
)

Common JVM Targets

When developing on the JVM, the following target types are most frequently used:

Every Day Commands

IntelliJ

Pants Patterns

  • Talk about common pants patterns users will find themselves doing regularly.
  • Patterns (or "recipes") are the best way we know to use a number of primitives together to best achieve a specific outcome.

External Dependencies

You probably use code from outside the repo.

# 3rdparty/jvm/com/twitter/mybird:mybird
jar_library(name='mybird',
  jars=[
    jar(org='com.twitter.mybird', name='mybird', rev='1.0.0')
  ]
)
  • Recommended target addresses 3rdparty/$LANG/$ORG:$NAME
  • All internal sources use same external library version. Catch many diamond dependency issues.
  • Aids discoverability, git log "detective work"
  • Per-language conventions within language subdir. Use JVM for Java/Scala.

External (Diamond) Dependencies

What should happen here? Avoid this by all internal sources using the same 3rdparty library version.

pants_essentials_techtalk__5.png
  • Ask what version of Guava should be on the foobird classpath?
  • Note most likely the highest version number will end up on the classpath, which could lead to runtime errors due to missing classes, methods, etc.
  • Pants does not solve this. It does simplify dependency management.
  • Instead, use this convention: Define each external jar once. Use this internal dependency in projects that need it.

Pants and Thrift

java_thrift_library(name='mybird-scala',
  sources=globs('*.thrift'),
  dependencies=['src/thrift/included:includedbird-scala',],
  compiler='scrooge',
  language='scala',
  rpc_style='finagle',
)

Need to generate a few languages?
Use a few *_thrift_library targets.
(If your org has a standard set of languages to generate, might have a plugin with a BUILD helper function for this.)

Deploy Bundles, jar-only case

Want to upload something runnable to a server? Generate a bundle:

# in mybird/BUILD
jvm_binary(name='mybird-bin',
  dependencies=['src/java/com/twitter/mybird'], ...
)

jvm_app(name='mybird-app',
  binary=':mybird-bin',
  bundles=[bundle(relative_to='common').add(rglobs('common/*')),
])
./pants goal bundle mybird:mybird-app --bundle-archive=zip
  • relative_to means that common/foo.ini gets bundled at ./foo.ini
  • The raw bundle and zip are created in the dist dir.

Getting Help

/

#