|
1 | 1 | +++
|
2 | 2 | title="Use the build plan"
|
3 |
| -weight=99 |
| 3 | +weight=2 |
4 | 4 | +++
|
5 | 5 |
|
| 6 | +The [Build Plan](https://github.com/buildpacks/spec/blob/main/buildpack.md#build-plan-toml) is a document that buildpacks can use to pass information between the `detect` and `build` phases, and between each other. |
| 7 | +The build plan is passed (by the lifecycle) as a parameter to the `detect` and `build` binaries of each buildpack. |
| 8 | + |
6 | 9 | <!--more-->
|
7 | 10 |
|
8 |
| -This page is a stub! The CNB project is applying to [Google Season of Docs](https://developers.google.com/season-of-docs/docs/timeline) to receive support for improving our documentation. Please check back soon. |
| 11 | +During the `detect` phase, each buildpack may write something it `requires` or `provides` (or both) into the Build Plan. |
| 12 | +A buildpack can `require` or `provide` multiple dependencies, and even multiple groupings of dependencies (using `or` lists). |
| 13 | +Additionally, multiple buildpacks may `require` or `provide` the same dependency. |
| 14 | +For detailed information, consult the [spec](https://github.com/buildpacks/spec/blob/main/buildpack.md#buildpack-plan-toml). |
| 15 | + |
| 16 | +The lifecycle uses the Build Plan to determine whether a particular list of buildpacks can work together, |
| 17 | +by seeing whether all dependencies required can be provided by that list. |
| 18 | + |
| 19 | +Later, during the `build` phase, each buildpack may read the Buildpack Plan (a condensed version of the Build Plan, composed by the lifecycle) to determine what it should do. |
| 20 | + |
| 21 | +Let's see how this works with an example. |
| 22 | + |
| 23 | +### Example: `node-engine` buildpack |
| 24 | + |
| 25 | +Let's walk through some possible cases a `node-engine` buildpack may consider: |
| 26 | + |
| 27 | +1. Nothing in the app explicitly calls out that it is needed |
| 28 | +2. It is explicitly referred to in some configuration file |
| 29 | + |
| 30 | +We will also consider what an `NPM` and a `JVM` buildpack may do. |
| 31 | + |
| 32 | +#### Scenario 1: No Explicit Request |
| 33 | + |
| 34 | +A `node-engine` buildpack is always happy to `provide` the `node` dependency. The build plan it will write may look something like: |
| 35 | +``` |
| 36 | +[[provides]] |
| 37 | +name = "node" |
| 38 | +``` |
| 39 | +> **NOTE:** If this was the only buildpack running, this would fail the `detect` phase. In order to pass, every `provides` must be matched up with a `requires`, whether in the same buildpack or in another buildpack. |
| 40 | +> See the [spec](https://github.com/buildpacks/spec/blob/main/buildpack.md#phase-1-detection) for particulars on how ordering buildpacks can adjust detection results. |
| 41 | +
|
| 42 | +#### Scenario 2: One Version Requested |
| 43 | + |
| 44 | +During the `detect` phase, the `node-engine` buildpack sees in one configuration file (e.g. a `.nvmrc` file in the app directory) that `node v10.x` is explicitly requested by the application. Seeing that, it may write the below text to the build plan: |
| 45 | +``` |
| 46 | +[[provides]] |
| 47 | +name = "node" |
| 48 | +
|
| 49 | +[[requires]] |
| 50 | +name = "node" |
| 51 | +version = "10.x" |
| 52 | +
|
| 53 | +[requires.metadata] |
| 54 | +version-source = ".nvmrc" |
| 55 | +``` |
| 56 | + |
| 57 | +As always, the buildpack `provides` `node`. In this particular case, a version of `node` (`10.x`) is being requested in a configuration file (`.nvmrc`). The buildpack chooses to add an additional piece of metadata (`version-source`), so that it can understand where that request came from. |
| 58 | + |
| 59 | +#### NPM Buildpack |
| 60 | + |
| 61 | +`NPM` is the default package manager for `node`. A NPM Buildpack may ensure that all the packages for the application are present (by running `npm install`), and perhaps cache those packages as well, to optimize future builds. |
| 62 | + |
| 63 | +NPM is typically distributed together with node. As a result, a NPM buildpack may require `node`, but not want to `provide` it, trusting that the `node-engine` buildpack will be in charge of `providing` `node`. |
| 64 | + |
| 65 | +The NPM buildpack could write the following to the build plan, if the buildpack sees that `npm` is necessary (e.g., it sees a `package.json` file in the app directory): |
| 66 | +``` |
| 67 | +[[requires]] |
| 68 | +name = "node" |
| 69 | +``` |
| 70 | + |
| 71 | +If, looking in the `package.json` file, the NPM buildpack sees a specific version of `node` requested in the [engines](https://docs.npmjs.com/files/package.json#engines) field (e.g. `14.1`), it may write the following to the build plan: |
| 72 | +``` |
| 73 | +[[requires]] |
| 74 | +name = "node" |
| 75 | +version = "14.1" |
| 76 | +
|
| 77 | +[requires.metadata] |
| 78 | +version-source = "package.json" |
| 79 | +``` |
| 80 | + |
| 81 | +> **NOTE:** As above, if this was the only buildpack running, this would fail the `detect` phase. In order to pass, every `provides` must be matched up with a `requires`, whether in the same buildpack or in another buildpack. |
| 82 | +> See the [spec](https://github.com/buildpacks/spec/blob/main/buildpack.md#phase-1-detection) for particulars on how ordering buildpacks can adjust detection results. |
| 83 | +
|
| 84 | +However, if the NPM Buildpack was run together with the Node Engine buildpack (which `provides` `node`), the lifecycle will see that all requirements are fulfilled, and select that group as the correct set of buildpacks. |
| 85 | + |
| 86 | +### Example: JVM buildpack |
| 87 | + |
| 88 | +Java is distributed in two formats - the `jdk` (Java Development Kit), which allows for compilation and running of Java programs, and the `jre` (Java Runtime Environment, which allows for running compiled Java programs). |
| 89 | +A very naive implementation of the buildpack may have it write several `provides` options to the build plan, detailing everything that it can provide, |
| 90 | +while later buildpacks would figure out based on the application which options it requires, and would `require` those. |
| 91 | +In this particular case, we can use the `or` operator to present different possible build plans the buildpack can follow: |
| 92 | + |
| 93 | +``` |
| 94 | +# option 1 (`jre` and `jdk`) |
| 95 | +[[provides]] |
| 96 | +name = "jre" |
| 97 | +
|
| 98 | +[[provides]] |
| 99 | +name = "jdk" |
| 100 | +
|
| 101 | +# option 2 (or just `jdk`) |
| 102 | +[[or]] |
| 103 | +[[or.provides]] |
| 104 | +name = "jdk" |
| 105 | +
|
| 106 | +# option 3 (or just `jre`) |
| 107 | +[[or]] |
| 108 | +[[or.provides]] |
| 109 | +name = "jre" |
| 110 | +``` |
| 111 | + |
| 112 | +The buildpack gives three options to the lifecycle: |
| 113 | +* It can provide a standalone `jre` |
| 114 | +* It can provide a standalone `jdk` |
| 115 | +* It can provide both the `jdk` and `jre` |
| 116 | + |
| 117 | +As with the other buildpacks, this alone will not be sufficient for the lifecycle. However, other buildpacks that follow may `require` certain things. |
9 | 118 |
|
10 |
| -If you are familiar with this content and would like to make a contribution, please feel free to open a PR :) |
| 119 | +For example, another buildpack may look into the application and, seeing that it is a Java executable, `require` the `jre` in order to run it. |
| 120 | +When the lifecycle analyzes the results of the `detect` phase, it will see that there is a buildpack which provides `jre`, and a buildpack that requires `jre`, |
| 121 | +and will therefore conclude that those options represent a valid set of buildpacks. |
0 commit comments