Skip to content

Commit f82f17a

Browse files
committed
Modernize README for Go-based buildpack architecture
- Remove all Python buildpack references (PyEnv, virtualenv, pip, Python 2.6.6) - Update build instructions to use buildpack-packager and direnv - Change testing framework documentation from Cutlass to Switchblade - Update project structure to reflect Go source layout (src/php/*) - Document complete buildpack lifecycle with build-time and runtime phases - Add detailed documentation for rewrite phase (config templating) - Modernize extensions section with Go interface examples - Remove obsolete python_unit_specs_test.go that referenced non-existent Python test infrastructure
1 parent 6c43c65 commit f82f17a

File tree

2 files changed

+110
-244
lines changed

2 files changed

+110
-244
lines changed

README.md

Lines changed: 110 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -10,261 +10,174 @@ Official buildpack documentation can be found here: [php buildpack docs](http://
1010

1111
### Building the Buildpack
1212

13-
#### Option 1: Using the `package.sh` script
14-
1. Run `./scripts/package.sh [ --uncached | --cached ] [ --stack=STACK ]`
13+
To build this buildpack, run the following commands from the buildpack's directory:
1514

16-
This script automatically installs the Go-based `buildpack-packager` and builds the buildpack.
17-
18-
#### Option 2: Manually use the `buildpack-packager`
19-
1. Make sure you have fetched submodules
15+
1. Source the .envrc file in the buildpack directory.
2016

2117
```bash
22-
git submodule update --init
18+
source .envrc
2319
```
20+
To simplify the process in the future, install [direnv](https://direnv.net/) which will automatically source `.envrc` when you change directories.
2421

25-
1. Check out a tagged release. It is not recommended to bundle buildpacks based on master or develop as these are moving targets.
22+
1. Install buildpack-packager
2623

27-
```bash
28-
git checkout v4.4.2 # or whatever version you want, see releases page for available versions
29-
```
24+
```bash
25+
go install github.com/cloudfoundry/libbuildpack/packager/buildpack-packager@latest
26+
```
3027

31-
1. Install the Go-based buildpack-packager
28+
1. Build the buildpack
3229

33-
```shell
34-
go install github.com/cloudfoundry/libbuildpack/packager/buildpack-packager@latest
35-
```
30+
```bash
31+
buildpack-packager build [ --cached ]
32+
```
3633

37-
1. Build the buildpack
34+
Alternatively, use the package script:
3835

39-
```shell
40-
buildpack-packager build [ -uncached | -cached ] [ -any-stack | -stack=STACK ]
41-
```
36+
```bash
37+
./scripts/package.sh [ --cached ]
38+
```
4239

4340
1. Use in Cloud Foundry
4441

45-
Upload the buildpack to your Cloud Foundry instance and optionally specify it by name
42+
Upload the buildpack to your Cloud Foundry and optionally specify it by name
4643

4744
```bash
48-
cf create-buildpack custom_php_buildpack php_buildpack-cached-custom.zip 1
49-
cf push my_app -b custom_php_buildpack
45+
cf create-buildpack [BUILDPACK_NAME] [BUILDPACK_ZIP_FILE_PATH] 1
46+
cf push my_app [-b BUILDPACK_NAME]
5047
```
5148

5249
### Contributing
5350
Find our guidelines [here](https://github.com/cloudfoundry/php-buildpack/blob/develop/CONTRIBUTING.md).
5451

55-
### Integration Tests
56-
Buildpacks use the [Cutlass](https://github.com/cloudfoundry/libbuildpack/tree/master/cutlass) framework for running integration tests.
57-
58-
To run integration tests, run the following command:
59-
60-
```
61-
./scripts/integration.sh
62-
```
63-
64-
### Unit Tests
65-
66-
To run unit tests, run the following command:
67-
68-
```bash
69-
./scripts/unit
70-
```
52+
### Testing
7153

72-
### Requirements
73-
1. [PyEnv] - This will allow you to easily install Python 2.6.6, which is the same version available through the staging environment of CloudFoundry.
74-
1. [virtualenv] & [pip] - The buildpack uses virtualenv and pip to setup the [required packages]. These are used by the unit test and not required by the buildpack itself.
54+
Buildpacks use the [Switchblade](https://github.com/cloudfoundry/switchblade) framework for running integration tests against Cloud Foundry. Before running the integration tests, you need to login to your Cloud Foundry using the [cf cli](https://github.com/cloudfoundry/cli):
7555

76-
### Setup
7756
```bash
78-
git clone https://github.com/cloudfoundry/php-buildpack
79-
cd php-buildpack
80-
python -V # should report 2.6.6, if not fix PyEnv before creating the virtualenv
81-
virtualenv `pwd`/env
82-
. ./env/bin/activate
83-
pip install -r requirements.txt
84-
```
85-
86-
### Project Structure
87-
88-
The project is broken down into the following directories:
89-
90-
- `bin` contains executable scripts, including `compile`, `release` and `detect`
91-
- `defaults` contains the default configuration
92-
- `docs` contains project documentation
93-
- `extensions` contains non-core extensions
94-
- `env` virtualenv environment
95-
- `lib` contains core extensions, helper code and the buildpack utils
96-
- `scripts` contains the Python scripts that run on compile, release and detect
97-
- `tests` contains test scripts and test data
98-
- `run_tests.sh` a convenience script for running the full suite of tests
99-
100-
### Understanding the Buildpack
101-
102-
The easiest way to understand the buildpack is to trace the flow of the scripts. The buildpack system calls the `compile`, `release` and `detect` scripts provided by the buildpack. These are located under the `bin` directory and are generic. They simply redirect to the corresponding Python script under the `scripts` directory.
103-
104-
Of these, the `detect` and `release` scripts are straightforward, providing the minimal functionality required by a buildpack. The `compile` script is more complicated but works like this.
105-
106-
- load configuration
107-
- setup the `WEBDIR` directory
108-
- install the buildpack utils and the core extensions (HTTPD, Nginx & PHP)
109-
- install other extensions
110-
- install the `rewrite` and `start` scripts
111-
- setup the runtime environment and process manager
112-
- generate a startup.sh script
113-
114-
### Extensions
115-
116-
The buildpack relies heavily on extensions. An extension is simply a set of Python methods that will get called at various times during the staging process.
117-
118-
Included non-core extensions:
119-
- [`composer`](extensions/composer) - [Downloads, installs and runs Composer](http://docs.cloudfoundry.org/buildpacks/php/gsg-php-composer.html)
120-
- [`dynatrace`](extensions/dynatrace) - Downloads and configures Dynatrace OneAgent
121-
- Looks for a bound service with name `dynatrace` and value `credentials` with sub-keys
122-
- `apiurl`
123-
- `environmentid`
124-
- `apitoken`
125-
- [`newrelic`](extensions/newrelic) - [Downloads, installs and configures the NewRelic agent for PHP](http://docs.cloudfoundry.org/buildpacks/php/gsg-php-newrelic.html)
126-
- [`sessions`](extensions/sessions) - [Configures PHP to store session information in a bound Redis or Memcached service instance](http://docs.cloudfoundry.org/buildpacks/php/gsg-php-sessions.html)
127-
128-
### Adding extensions
129-
130-
In general, you shouldn't need to modify the buildpack itself. Instead creating your own extension should be the way to go.
131-
132-
To create an extension, simply create a folder. The name of the folder will be the name of the extension. Inside that folder, create a file called `extension.py`. That file will contain your code. Inside that file, put your extension methods and any additional required code.
133-
134-
It's not necessary to fork the buildpack to add extensions for your app. The buildpack will notice and use extensions if you place them in a `.extensions` folder at your application root. See the [extensions directory in the this example](./fixtures/custom_extension/.extensions/phpmyadmin/extension.py) for a sample.
135-
136-
#### Methods
137-
138-
Here is an explanation of the methods offered to an extension developer. All of them are optional and if a method is not implemented, it is simply skipped.
139-
140-
```python
141-
def configure(ctx):
142-
pass
57+
cf login -a https://api.your-cf.com -u name@example.com -p pa55woRD
14358
```
14459

145-
The `configure` method gives extension authors a chance to adjust the configuration of the buildpack prior to *any* extensions running. The method is called very early on in the lifecycle of the buildpack, so keep this in mind when using this method. The purpose of this method is to allow an extension author the opportunity to modify the configuration for PHP, the web server or another extension prior to those components being installed.
60+
Note that your user requires permissions to run `cf create-buildpack` and `cf update-buildpack`. To run the integration tests, run the following commands from the buildpack's directory:
14661
147-
An example of when to use this method would be to adjust the list of PHP extensions that are going to be installed.
148-
149-
The method takes one argument, which is the buildpack context. You can edit the context to update the state of the buildpack. Return value is ignore / not necessary.
62+
1. Source the .envrc file in the buildpack directory.
15063
64+
```bash
65+
source .envrc
66+
```
67+
To simplify the process in the future, install [direnv](https://direnv.net/) which will automatically source .envrc when you change directories.
15168
152-
```python
153-
def preprocess_commands(ctx):
154-
return ()
155-
```
69+
1. Run unit tests
15670
157-
The `preprocess_commands` method gives extension authors the ability to contribute a list of commands that should be run prior to the services. These commands are run in the execution environment, not the staging environment and should execute and complete quickly. The purpose of these commands is to give extension authors the chance to run any last-minute code to adjust to the environment.
71+
```bash
72+
./scripts/unit.sh
73+
```
15874
159-
As an example, this is used by the core extensions rewrite configuration files with information that is specific to the runtime environment.
75+
1. Run integration tests
16076
161-
The method takes the context as an argument and should return a tuple of tuples (i.e. list of commands to run).
77+
```bash
78+
./scripts/integration.sh
79+
```
16280
163-
```python
164-
def service_commands(ctx):
165-
return {}
166-
```
81+
More information can be found on Github [switchblade](https://github.com/cloudfoundry/switchblade).
16782
168-
The `service_commands` method gives extension authors the ability to contribute a set of services that need to be run. These commands are run and should continue to run. If any service exits, the process manager will halt all of the other services and the application will be restarted by Cloud Foundry.
83+
### Project Structure
16984
170-
The method takes the context as an argument and should return a dictionary of services to run. The key should be the service name and the value should be a tuple which is the command and arguments.
85+
The project is broken down into the following directories:
17186
172-
```python
173-
def service_environment(ctx):
174-
return {}
175-
```
87+
- `bin/` - Executable shell scripts for buildpack lifecycle: `detect`, `supply`, `finalize`, `release`, `start`, `rewrite`
88+
- `src/php/` - Go source code for the buildpack
89+
- `detect/` - Detection logic
90+
- `supply/` - Dependency installation (PHP, HTTPD, Nginx)
91+
- `finalize/` - Final configuration and setup
92+
- `release/` - Release information
93+
- `extensions/` - Extension system (composer, newrelic, dynatrace, appdynamics, sessions)
94+
- `config/` - Configuration management
95+
- `options/` - Options parsing
96+
- `hooks/` - Lifecycle hooks
97+
- `integration/` - Integration tests
98+
- `unit/` - Unit tests
99+
- `defaults/` - Default configuration files
100+
- `fixtures/` - Test fixtures and sample applications
101+
- `scripts/` - Build and test scripts
176102
177-
The `service_environment` method gives extension authors the ability to contribute environment variables that will be set and available to the services.
103+
### Understanding the Buildpack
178104
179-
The method takes the buildpack context as its argument and should return a dictionary of the environment variables to be added to the environment where services (see `service_commands`) are executed.
105+
This buildpack uses Cloud Foundry's [libbuildpack](https://github.com/cloudfoundry/libbuildpack) framework and is written in Go. The buildpack lifecycle consists of:
180106

181-
The key should be the variable name and the value should be the value. The value can either be a string, in which case the environment variable will be set with the value of the string or it can be a list.
107+
#### Build-Time Phases
182108

183-
If it's a list, the contents will be combined into a string and separated by the path separation character (i.e. ':' on Unix / Linux or ';' on Windows). Keys that are set multiple times by the same or different extensions are automatically combined into one environment variable using the same path separation character. This is helpful when two extensions both want to contribute to the same variable, for example LD_LIBRARY_PATH.
109+
1. **Detect** (`bin/detect``src/php/detect/`) - Determines if the buildpack should be used by checking for PHP files or `composer.json`
184110

185-
Please note that environment variables are not evaluated as they are set. This would not work because they are set in the staging environment which is different than the execution environment. This means you cannot do things like `PATH=$PATH:/new/path` or `NEWPATH=$HOME/some/path`. To work around this, the buildpack will rewrite the environment variable file before it's processed. This process will replace any `@<env-var>` markers with the value of the environment variable from the execution environment. Thus if you do `PATH=@PATH:/new/path` or `NEWPATH=@HOME/some/path`, the service end up with a correctly set `PATH` or `NEWPATH`.
111+
2. **Supply** (`bin/supply``src/php/supply/`) - Installs dependencies:
112+
- Downloads and installs PHP
113+
- Downloads and installs web server (HTTPD or Nginx)
114+
- Runs extensions in "configure" and "compile" phases
115+
- Installs PHP extensions
116+
- Runs Composer to install application dependencies
186117

187-
```python
188-
def compile(install):
189-
return 0
190-
```
118+
3. **Finalize** (`bin/finalize``src/php/finalize/`) - Final configuration:
119+
- Configures web server (HTTPD or Nginx)
120+
- Sets up PHP and PHP-FPM configuration
121+
- Copies rewrite and start binaries to `.bp/bin/`
122+
- Generates preprocess scripts that will run at startup
123+
- Prepares runtime environment
191124

192-
The `compile` method is the main method and where extension authors should perform the bulk of their logic. This method is called by the buildpack while it's installing extensions.
125+
4. **Release** (`bin/release``src/php/release/`) - Provides process types and metadata
193126

194-
The method is given one argument which is an Installer builder object. The object can be used to install packages, configuration files or access the context (for examples of all this, see the core extensions like [HTTPD], [Nginx], [PHP], [Dynatrace] and [NewRelic]). The method should return 0 when successful or any other number when it fails. Optionally, the extension can raise an exception. This will also signal a failure and it can provide more details about why something failed.
127+
#### Runtime Phases
195128

196-
#### Method Order
129+
5. **Rewrite** (`bin/rewrite``src/php/rewrite/cli/`) - Configuration templating at runtime:
130+
- Called during application startup (before services start)
131+
- Replaces template patterns in configuration files with runtime environment variables
132+
- Supports patterns: `@{VAR}`, `#{VAR}`, `@VAR@`, `#VAR`
133+
- Allows configuration to adapt to the actual runtime environment (ports, paths, etc.)
134+
- Rewrites PHP, PHP-FPM, and web server configs
197135

198-
It is sometimes useful to know what order the buildpack will use to call the methods in an extension. They are called in the following order.
136+
6. **Start** (`bin/start``src/php/start/cli/`) - Process management:
137+
- Runs preprocess commands (including rewrite operations)
138+
- Launches all configured services (PHP-FPM, web server, etc.) from `.procs` file
139+
- Monitors all processes
140+
- If any process exits, terminates all others and restarts the application
199141

200-
1. `configure`
201-
2. `compile`
202-
3. `service_environment`
203-
4. `service_commands`
204-
5. `preprocess_commands`
142+
### Extensions
205143

206-
#### Example
144+
The buildpack includes several built-in extensions written in Go:
207145

208-
Here is an example extension. While technically correct, it doesn't actually do anything.
146+
- **[composer](src/php/extensions/composer/)** - [Downloads, installs and runs Composer](http://docs.cloudfoundry.org/buildpacks/php/gsg-php-composer.html). Automatically detects PHP version requirements from `composer.json` and validates against locked dependencies.
147+
- **[newrelic](src/php/extensions/newrelic/)** - [Downloads, installs and configures the NewRelic agent for PHP](http://docs.cloudfoundry.org/buildpacks/php/gsg-php-newrelic.html)
148+
- **[dynatrace](src/php/extensions/dynatrace/)** - Downloads and configures Dynatrace OneAgent. Looks for a bound service with name `dynatrace` and credentials containing `apiurl`, `environmentid`, and `apitoken`.
149+
- **[appdynamics](src/php/extensions/appdynamics/)** - Downloads and configures AppDynamics agent
150+
- **[sessions](src/php/extensions/sessions/)** - [Configures PHP to store session information in a bound Redis or Memcached service instance](http://docs.cloudfoundry.org/buildpacks/php/gsg-php-sessions.html)
209151

210-
Here's the directory.
152+
### Extension Architecture
211153

212-
```bash
213-
$ ls -lRh
214-
total 0
215-
drwxr-xr-x 3 daniel staff 102B Mar 3 10:57 testextn
154+
Extensions implement the `Extension` interface defined in [`src/php/extensions/extension.go`](src/php/extensions/extension.go):
216155

217-
./testextn:
218-
total 8
219-
-rw-r--r-- 1 daniel staff 321B Mar 3 11:03 extension.py
156+
```go
157+
type Extension interface {
158+
Name() string
159+
ShouldCompile(ctx *Context) (bool, error)
160+
Configure(ctx *Context) error
161+
Compile(installer Installer) error
162+
PreprocessCommands(ctx *Context) ([]string, error)
163+
ServiceCommands(ctx *Context) (map[string]string, error)
164+
ServiceEnvironment(ctx *Context) (map[string]string, error)
165+
}
220166
```
221167

222-
Here's the code.
168+
**Extension Lifecycle:**
223169

224-
```python
225-
import logging
170+
1. **Configure** - Called early to modify buildpack configuration (e.g., set PHP version, add extensions)
171+
2. **Compile** - Main extension logic, downloads and installs components
172+
3. **ServiceEnvironment** - Contributes environment variables
173+
4. **ServiceCommands** - Contributes long-running services
174+
5. **PreprocessCommands** - Contributes commands to run before services start
226175

227-
_log = logging.getLogger('textextn')
176+
For examples, see the built-in extensions in `src/php/extensions/`.
228177

229-
# Extension Methods
230-
def configure(ctx):
231-
pass
178+
**Note:** Custom user extensions from `.extensions/` directory are not currently supported in the Go-based buildpack. This feature may be added in a future release.
232179

233-
def preprocess_commands(ctx):
234-
return ()
235-
236-
def service_commands(ctx):
237-
return {}
238-
239-
def service_environment(ctx):
240-
return {}
241-
242-
def compile(install):
243-
return 0
244-
```
245180

246-
#### Tips
247-
248-
1. To be consistent with the rest of the buildpack, extensions should import and use the standard logging module. This will allow extension output to be incorporated into the output for the rest of the buildpack.
249-
1. The buildpack will run every extension that is included with the buildpack and the application. There is no mechanism to disable specific extensions. Thus, when you write an extension, you should make some way for the user to enable / disable it's functionality. See the [NewRelic] extension for an example of this.
250-
1. If an extension requires configuration, it should be included with the extension. The `defaults/options.json` file is for the buildpack and its core extensions. See the [NewRelic] buildpack for an example of this.
251-
1. Extensions should have their own test module. This generally takes the form `tests/test_<extension_name>.py`.
252-
1. Run [bosh-lite]. It'll speed up testing and allow you to inspect the environment manually, if needed.
253-
1. Run a local web server for your binaries. It'll seriously speed up download times.
254-
1. Test, test and test again. Create unit and integration tests for your code and extensions. This gives you quick and accurate feedback on your code. It also makes it easier for you to make changes in the future and be confident that you're not breaking stuff.
255-
1. Check your code with flake8. This linting tool can help to detect problems quickly.
256-
257-
[PyEnv]:https://github.com/yyuu/pyenv
258-
[virtualenv]:http://www.virtualenv.org/en/latest/
259-
[pip]:http://www.pip-installer.org/en/latest/
260-
[required packages]:https://github.com/cloudfoundry/php-buildpack/blob/master/requirements.txt
261-
[bosh-lite]:https://github.com/cloudfoundry/bosh-lite
262-
[HTTPD]:https://github.com/cloudfoundry/php-buildpack/tree/master/lib/httpd
263-
[Nginx]:https://github.com/cloudfoundry/php-buildpack/tree/master/lib/nginx
264-
[PHP]:https://github.com/cloudfoundry/php-buildpack/tree/master/lib/php
265-
[Dynatrace]:https://github.com/cloudfoundry/php-buildpack/tree/master/extensions/dynatrace
266-
[NewRelic]:https://github.com/cloudfoundry/php-buildpack/tree/master/extensions/newrelic
267-
[unit tests]:https://github.com/cloudfoundry/php-buildpack/blob/master/docs/development.md#testing
268181

269182
### Help and Support
270183

0 commit comments

Comments
 (0)