diff --git a/buildkit/convert.go b/buildkit/convert.go index 6f79f5d..a79b8fe 100644 --- a/buildkit/convert.go +++ b/buildkit/convert.go @@ -136,7 +136,8 @@ func getBaseState(plan *p.BuildPlan, platform specs.Platform) llb.State { llb.Platform(platform), ) - state = state.Run(llb.Shlex("sh -c 'apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*'"), llb.WithCustomName("install base packages")).Root() + state = state.AddEnv("DEBIAN_FRONTEND", "noninteractive") + state = state.Run(llb.Shlex("sh -c 'apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*'")).Root() state = state.Dir(WorkingDir) return state diff --git a/cli/build.go b/cli/build.go index a0c5a5c..1d25d55 100644 --- a/cli/build.go +++ b/cli/build.go @@ -19,28 +19,11 @@ var BuildCommand = &cli.Command{ Usage: "build an image with BuildKit", ArgsUsage: "DIRECTORY", EnableShellCompletion: true, - Flags: []cli.Flag{ + Flags: append([]cli.Flag{ &cli.StringFlag{ Name: "name", Usage: "name of the image to build", }, - &cli.StringSliceFlag{ - Name: "env", - Usage: "environment variables to set", - }, - &cli.StringFlag{ - Name: "build-cmd", - Usage: "build command to use", - }, - &cli.StringFlag{ - Name: "start-cmd", - Usage: "start command to use", - }, - &cli.BoolFlag{ - Name: "llb", - Usage: "output the LLB plan to stdout instead of building the image", - Value: false, - }, &cli.StringFlag{ Name: "output", Usage: "output the final filesystem to a local directory", @@ -55,11 +38,7 @@ var BuildCommand = &cli.Command{ Usage: "Show the build plan before building. This is useful for development and debugging.", Value: false, }, - &cli.StringSliceFlag{ - Name: "previous-versions", - Usage: "versions of packages used for previous builds. These versions will be used instead of the defaults. format: NAME@VERSION", - }, - }, + }, commonPlanFlags()...), Action: func(ctx context.Context, cmd *cli.Command) error { buildResult, app, env, err := GenerateBuildResultForCommand(cmd) if err != nil { diff --git a/cli/common.go b/cli/common.go index 5cca42c..3379f31 100644 --- a/cli/common.go +++ b/cli/common.go @@ -10,6 +10,27 @@ import ( "github.com/urfave/cli/v3" ) +func commonPlanFlags() []cli.Flag { + return []cli.Flag{ + &cli.StringSliceFlag{ + Name: "env", + Usage: "environment variables to set", + }, + &cli.StringSliceFlag{ + Name: "previous-versions", + Usage: "versions of packages used for previous builds", + }, + &cli.StringFlag{ + Name: "build-cmd", + Usage: "build command to use", + }, + &cli.StringFlag{ + Name: "start-cmd", + Usage: "start command to use", + }, + } +} + func GenerateBuildResultForCommand(cmd *cli.Command) (*core.BuildResult, *a.App, *a.Environment, error) { directory := cmd.Args().First() diff --git a/cli/info.go b/cli/info.go index 9b2222f..06f0283 100644 --- a/cli/info.go +++ b/cli/info.go @@ -17,29 +17,17 @@ var InfoCommand = &cli.Command{ Usage: "get as much information as possible about an app", ArgsUsage: "DIRECTORY", EnableShellCompletion: true, - Flags: []cli.Flag{ - &cli.StringSliceFlag{ - Name: "env", - Usage: "environment variables to set. format: KEY=VALUE", - }, - &cli.StringFlag{ - Name: "build-cmd", - Usage: "build command to use", - }, - &cli.StringFlag{ - Name: "start-cmd", - Usage: "start command to use", - }, + Flags: append([]cli.Flag{ &cli.StringFlag{ Name: "format", Usage: "output format. one of: pretty, json", Value: "pretty", }, - &cli.StringSliceFlag{ - Name: "previous", - Usage: "versions of packages used for previous builds. These versions will be used instead of the defaults. format: NAME@VERSION", + &cli.StringFlag{ + Name: "out", + Usage: "output file name", }, - }, + }, commonPlanFlags()...), Action: func(ctx context.Context, cmd *cli.Command) error { buildResult, _, _, err := GenerateBuildResultForCommand(cmd) if err != nil { diff --git a/cli/plan.go b/cli/plan.go index 6406104..13b06bf 100644 --- a/cli/plan.go +++ b/cli/plan.go @@ -16,21 +16,13 @@ var PlanCommand = &cli.Command{ Usage: "generate a build plan for a directory", ArgsUsage: "DIRECTORY", EnableShellCompletion: true, - Flags: []cli.Flag{ - &cli.StringSliceFlag{ - Name: "env", - Usage: "environment variables to set. format: KEY=VALUE", - }, + Flags: append([]cli.Flag{ &cli.StringFlag{ Name: "out", Aliases: []string{"o"}, Usage: "output file name", }, - &cli.StringSliceFlag{ - Name: "previous", - Usage: "versions of packages used for previous builds. These versions will be used instead of the defaults. format: NAME@VERSION", - }, - }, + }, commonPlanFlags()...), Action: func(ctx context.Context, cmd *cli.Command) error { buildResult, _, _, err := GenerateBuildResultForCommand(cmd) if err != nil { diff --git a/cmd/cli/main.go b/cmd/cli/main.go index f327893..ada7a33 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -4,7 +4,9 @@ import ( "context" "os" + "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/log" + "github.com/muesli/termenv" "github.com/railwayapp/railpack/cli" urfave "github.com/urfave/cli/v3" ) @@ -19,6 +21,10 @@ func main() { }).Writer() urfave.ErrWriter = urfaveLogWriter + if os.Getenv("FORCE_COLOR") != "" { + lipgloss.SetColorProfile(termenv.TrueColor) + } + cmd := &urfave.Command{ Name: "railpack", Usage: "Automatically analyze and generate build plans for applications", diff --git a/core/prettyPrint.go b/core/prettyPrint.go index 7e9b0ef..0a7224b 100644 --- a/core/prettyPrint.go +++ b/core/prettyPrint.go @@ -112,7 +112,7 @@ func FormatBuildResult(br *BuildResult, options ...PrintOptions) string { // Steps section stepsToPrint := getStepsToPrint(br) if len(stepsToPrint) > 0 { - output.WriteString(sectionHeaderStyle.Render("Steps")) + output.WriteString(sectionHeaderStyle.MarginTop(1).Render("Steps")) output.WriteString("\n") stepCount := 0 diff --git a/core/providers/golang/golang.go b/core/providers/golang/golang.go index 2a5e949..ae8977a 100644 --- a/core/providers/golang/golang.go +++ b/core/providers/golang/golang.go @@ -123,7 +123,7 @@ func (p *GoProvider) Install(ctx *generate.GenerateContext, packages *generate.M // If CGO is enabled, we need to install the gcc packages if p.hasCGOEnabled(ctx) { aptStep := ctx.NewAptStepBuilder("cgo") - aptStep.Packages = []string{"gcc", "g++", "libc6-dev", "libgcc-9-dev", "libstdc++-9-dev"} + aptStep.Packages = []string{"gcc", "g++", "libc6-dev"} install.DependsOn = append(install.DependsOn, aptStep.DisplayName) } else { install.AddCommand(plan.NewVariableCommand("CGO_ENABLED", "0")) diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index a3b1a5a..b12a7c9 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -17,10 +17,8 @@ export default defineConfig({ github: "https://github.com/railwayapp/railpack", }, customCss: [ - // Path to your Tailwind base styles: "./src/tailwind.css", - // Fontsource files for to regular and semi-bold font weights. "@fontsource/inter/400.css", "@fontsource/inter/600.css", ], @@ -85,14 +83,13 @@ export default defineConfig({ label: "Package Resolution", link: "/architecture/package-resolution", }, - { label: "Plan Generation", link: "/architecture/plan-generation" }, - { label: "Secrets and Environment", link: "/architecture/secrets" }, { - label: "Previous Versions", - link: "/architecture/previous-versions", + label: "Secrets and Variables", + link: "/architecture/secrets", }, { label: "BuildKit Generation", link: "/architecture/buildkit" }, { label: "Caching", link: "/architecture/caching" }, + { label: "User Config", link: "/architecture/user-config" }, ], }, { diff --git a/docs/src/content/docs/architecture/buildkit.md b/docs/src/content/docs/architecture/buildkit.md index 64e9807..3c4722a 100644 --- a/docs/src/content/docs/architecture/buildkit.md +++ b/docs/src/content/docs/architecture/buildkit.md @@ -3,4 +3,24 @@ title: BuildKit LLB Generation description: Understanding how Railpack generates BuildKit LLB definitions --- -_todo_ +Railpack takes the build plan and generates a BuildKit LLB definition using the +[LLB Go API](https://github.com/moby/buildkit#exploring-llb). + +The LLB is then either [sent to the BuildKit daemon](/guides/building-with-cli) +or [used by a custom frontend](/guides/custom-frontend). + +Generating LLB directly instead of transpiling the plan into a Dockerfile has +several advantages: + +1. **Custom Frontend Integration**: Direct LLB generation enables integration + with BuildKit's frontend gateway. This allows the platform to either use + BuildKit through Docker or by interacting with the BuildKit daemon directly. + +1. **Caching and Optimization**: Direct LLB generation enables fine-grained + control over the build cache, allowing more complex caching than what's + possible with Dockerfile generation. + +1. **Secret Management**: LLB provides more secure and flexible secret mounting. + +1. **Type Safety and Compile-Time Validation**: The build defintion is checked + at compile-time using the first party Go library. diff --git a/docs/src/content/docs/architecture/caching.md b/docs/src/content/docs/architecture/caching.md index 11e7cb4..eed4a49 100644 --- a/docs/src/content/docs/architecture/caching.md +++ b/docs/src/content/docs/architecture/caching.md @@ -3,4 +3,53 @@ title: Caching description: Understanding Railpack's caching mechanisms --- -_todo_ +Railpack takes advantage of BuildKit layer and mount caches to speed up +successive builds. + +## Layer Cache + +Railpack takes advantage of BuildKit's layer cache and avoids busting the cache +when possible. Cache busting events are defined in a granular way as part of the +[steps commands list](/architecture/overview/#build-step). These include + +- Copying files from the local context to the build context +- Changing environment variables +- Adding new generated files to the build context +- Executing shell commands in the build context + +## Mount Cache + +The [BuildKit mount +cache](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#run---mounttypecache) +is used to save the contents of a directory from the build context between +builds. This is useful for speeding up commands that download or compile assets +(e.g. npm install). The directory **does not** appear in the final image. + +Caches are defined on the build plan and can be referenced via execution commands. + +```json +{ + "caches": { + "npm-install": { + "directory": "/root/.npm", + "type": "shared" + } + }, + + "steps": { + "install": { + "commands": [ + { + "cmd": "npm install", + "caches": ["npm-install"] + } + // ... + ] + // ... + } + } +} +``` + +Caches are shared across all steps. This is useful for common caches such as the +apt-cache or apt-lists. diff --git a/docs/src/content/docs/architecture/overview.md b/docs/src/content/docs/architecture/overview.md index 7538fb4..509fccc 100644 --- a/docs/src/content/docs/architecture/overview.md +++ b/docs/src/content/docs/architecture/overview.md @@ -3,4 +3,81 @@ title: High Level Overview description: Understanding Railpack's architecture and components --- -_todo_ +Railpack is split up into three main components: + +- Core + - The main logic that analyzes the app and generates the build plan +- Buildkit + - Takes the build plan and generates [BuildKit + LLB](https://github.com/moby/buildkit?tab=readme-ov-file#exploring-llb) + - Starts a custom frontend or creates a BuildKit client to execute the build + plan and generate an image +- CLI + - The main entry point for Railpack + +The core can be thought of as a _compiler_. The build plan that is generated is +independent from Docker, BuildKit, or any other tool that can be used to +generate an image. At the moment, BuildKit is the only _backend_, but more could +be added in the future. + +## Build Plan + +The build plan is a JSON object that contains all the information necessary to +generate an image. Things that it includes are: + +- Base image + - File system to start from +- Steps + - Group of commands to run +- Start information + - Command, variables, path, etc. Things needed when starting a container from + the image +- Caches + - Caches that are referenced by the commands in the steps +- Secrets + - Build secrets that are referenced by the commands in the steps (just the + names, not the values) + +### Build Step + +A step is a group of commands that is executed sequentially in the build. Steps +**can depend** on other steps, which means that they run with the filesystem of +all the outputs of the dependent steps. The build graph is constructed in such a +way that BuildKit will execute non-dependent steps in parallel. + +Steps contain: + +- Depends on + - List of other steps that this step must run after +- Commands + - List of commands to run in the build + - Exec command: run a shell command + - Copy command: copy files from the local context (user app) or another + image into the current FS + - Variable command: Set an environment variable + - Path command: Prefix the global PATH with another directory + - File command: Create a new file in the current FS referencing the step + assets +- Assets + - Mapping of name to file contents that is referenced in a file command +- Use secrets + - Whether or not this step uses build secrets. [Docs](/architecture/secrets) +- Starting image + - Instead of starting from the output of a previous step, it can start from a + completely different image. This is typically used for root steps +- Outputs + - List of file system paths that is the "result" of running this step. Parts + of the FS that are not included will not appear in the final image. If not + explicitly defined, the entire FS is assumed to be the output. + +## Providers + +Language suppport is provided through... providers. Providers are typically +associated a single language (e.g. node, python, php, etc.). A provider will + +- Detect + - Analyze the app and determine if it matches. (e.g. the node provider will + check for the precense of a `package.json` file). +- Build + - Modifies the build context with all the steps, commands, and everything that + is needed to build for that language/framework. diff --git a/docs/src/content/docs/architecture/package-resolution.md b/docs/src/content/docs/architecture/package-resolution.md index f7b6c4f..bdaa2b8 100644 --- a/docs/src/content/docs/architecture/package-resolution.md +++ b/docs/src/content/docs/architecture/package-resolution.md @@ -3,4 +3,36 @@ title: Packages and Version Resolution description: Understanding how Railpack resolves package versions using Mise --- -_todo_ +Railpack providers will analyze the app and determine _fuzzy_ versions of +exectuables to install. Versions like `3.13`, or `22`. The versions resolution +step will resolve those fuzzy versions into the latest valid version that exists. + +[Mise](https://mise.jdx.dev/) is used for the package resolution using the `mise +latest package@version` command. Mise is also used for (most) package +installations in the builds as well. However, this is not a requirement of +Railpack and alternative installation methods are possible (for example php will +use Mise to resolve a valid version and then start from a php base image). + +## Previous and default versions + +One important aspect of Railpack is that updating the default version of +executables in providers (e.g. Node 20 -> 22) should not change the version +installed version for apps that have already been building successfully with +Railpack. This is mainly useful on platform that use Railpack to build user +applications (e.g. Railway). + +To support this, you can pass in a `--previous pkg@name ...` flag when +generating the build plan. The typical flow will go like this + +- User builds for the first time with Railpack. The default Node version is used (20). +- The platform saves the resolved versions of packages used +- Railpack updates the default version of Node to 22 +- User submits a new build. The platform passes a `--previous` flag +- Railpack will use the previous versions instead of using the new default version + +This means that Railpack can freely update default versions of packages without +having to worry about breaking existing apps that rely on the previous defaults. + +Passing in a previous version will only be used in place of the default. If a +more specific version of a package is requested (e.g. through a package.json +engines field or env var), then we will always use that. diff --git a/docs/src/content/docs/architecture/plan-generation.md b/docs/src/content/docs/architecture/plan-generation.md deleted file mode 100644 index 53ef6e6..0000000 --- a/docs/src/content/docs/architecture/plan-generation.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Plan Generation -description: Understanding how Railpack generates build plans ---- - -_todo_ diff --git a/docs/src/content/docs/architecture/previous-versions.md b/docs/src/content/docs/architecture/previous-versions.md deleted file mode 100644 index bfacecd..0000000 --- a/docs/src/content/docs/architecture/previous-versions.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Previous Installed Versions -description: How Railpack manages previously installed versions ---- - -_todo_ diff --git a/docs/src/content/docs/architecture/secrets.md b/docs/src/content/docs/architecture/secrets.md index 192c894..1027a6c 100644 --- a/docs/src/content/docs/architecture/secrets.md +++ b/docs/src/content/docs/architecture/secrets.md @@ -3,4 +3,111 @@ title: Secrets and Environment Variables description: How Railpack handles secrets and environment variables --- -_todo_ +Build secrets and environment variables are treated separatley. The main differences being + +- Environment variables are saved in the final image and should not contain + sensitive information. Since they are in the final image, providers can add + variables that will be available to the app at runtime. +- Secrets are never logged or saved in the build logs. They are also only + available at build time and not saved to the final image. + +## Environment Variables + +Environment variables are added to the build plan as a step command. This allows +the providers to control exactly when to bust the layer cache (in contrast to +Nixpacks which treats env vars as all or nothing at the start of the build). + +```json +{ + "steps": { + "install": { + "commands": [ + { "name": "NODE_ENV", "value": "production" } + // ... + ] + // ... + } + } +} +``` + +## Secrets + +The names of all secrets that should be used during the build are added to the +top of the build plan. Whether or not a step uses the secrets is determined by a +`useSecrets` key. If this key is present, the secrets will be available to all +exec commands run in the step. + +Under the hood, Railpack uses [BuildKit secrets +mounts](https://docs.docker.com/build/building/secrets/) to supply an exec +command with the secret value as an environment variable. + +```json +{ + "secrets": ["STRIPE_LIVE_KEY"], + + "steps": { + "build": { + "useSecrets": true + // ... + } + } +} +``` + +### Providing Secrets + +You can add secrets when building or generating a build plan with the `--env` +flag. The names of these variables will be added to the build plan as secrets. + +#### CLI Build + +If building with [the CLI](/guides/building-with-cli), Railpack will check that +all the secrets defined in the build plan have variables. + +```bash +railpack build --env STRIPE_LIVE_KEY=sk_live_asdf +``` + +#### Custom Frontend + +If building with a [custom frontend](/guides/building-with-custom-frontends), +you should still provide the secrets when generating the plan with `--env`. This +adds the secrets to the build plan. You then need to pass the secrets to Docker +or BuildKit with the `--secret` flag. + +```bash +# Generate a build plan +railpack plan --env STRIPE_LIVE_KEY=sk_live_asdf --out test/railpack-plan.json + +# Build with the custom frontend +STRIPE_LIVE_KEY=sk_live_asdf docker build \ + --build-arg BUILDKIT_SYNTAX="ghcr.io/railwayapp/railpack:railpack-frontend" \ + -f test/railpack-plan.json \ + --secret id=STRIPE_LIVE_KEY,env=STRIPE_LIVE_KEY \ + examples/node-bun +``` + +### Secrets hash + +By default, BuildKit will not invalidate the a layer if a secret is changed. To +get around this, Railpack uses a hash of the secret values and mounts this as a +file in the layer. This will bust the layer cache if the secret is changed. + +If using the CLI to build, this will happen automatically. + +If using a custom frontend, you will need to provide the secret hash manually +via the `--opt secrets-hash=` flag. + +```bash +STRIPE_LIVE_KEY=sk_live_asdf docker build \ + --build-arg BUILDKIT_SYNTAX="ghcr.io/railwayapp/railpack:railpack-frontend" \ + -f test/railpack-plan.json \ + --secret id=STRIPE_LIVE_KEY,env=STRIPE_LIVE_KEY \ + --opt secrets-hash=asdf123456789... \ + examples/node-bun +``` + +This value can be anything that indicates that the secrets have changed (a +simple counter also works). However, we recommend using a non-reversible hash of +the secret values. diff --git a/docs/src/content/docs/architecture/user-config.md b/docs/src/content/docs/architecture/user-config.md new file mode 100644 index 0000000..0d8fa07 --- /dev/null +++ b/docs/src/content/docs/architecture/user-config.md @@ -0,0 +1,18 @@ +--- +title: User Config +description: How Railpack handles user config +--- + +Users can configure Railpack in a few different ways: + +- CLI flags +- Environment variables +- Config file + +These configs are merged together and then applied to the generate context. + +Everything that affects a part of the build plan _should_ be configurable. +Config affects the generate context rather than the plan itself as it allows +Railpack to perform optimizations after the config is applied. It also allows +the user config format to be abstracted at a higher level compared to the +relatively low level build plan schema. diff --git a/docs/src/content/docs/contributing.md b/docs/src/content/docs/contributing.md index 4454cd7..5feb0f5 100644 --- a/docs/src/content/docs/contributing.md +++ b/docs/src/content/docs/contributing.md @@ -3,4 +3,9 @@ title: Contributing description: How to contribute to Railpack --- -[View on GitHub](https://github.com/railwayapp/railpack) +Railpack is [open source on GitHub](https://github.com/railwayapp/railpack) and +open to contributions. We are only accepting significant changes and bug fixes +and will close any "drive by PRs". + +Check out [this guide](/guides/developing-locally) for how to set things up +locally. diff --git a/docs/src/content/docs/guides/developing-locally.md b/docs/src/content/docs/guides/developing-locally.md index 3e3a5cf..216350f 100644 --- a/docs/src/content/docs/guides/developing-locally.md +++ b/docs/src/content/docs/guides/developing-locally.md @@ -3,11 +3,14 @@ title: Developing Locally description: Learn how to develop Railpack locally --- -Once you've [checked out the repo](https://github.com/railwayapp/railpack), you can follow this to start developing locally. +Once you've [checked out the repo](https://github.com/railwayapp/railpack), you +can follow this to start developing locally. ## Getting Setup -We use [Mise](https://mise.jdx.dev/) for managing language dependencies and tasks for building and testing Railpack. You don't have to use Mise, but it's recommended. +We use [Mise](https://mise.jdx.dev/) for managing language dependencies and +tasks for building and testing Railpack. You don't have to use Mise, but it's +recommended. Install and use all versions of tools needed for Railpack @@ -31,9 +34,12 @@ go run cmd/cli/main.go --help ## ① Building directly with Buildkit -**👋 Requirement**: an instance of Buildkit must be running locally. Instructions in "[Run BuildKit Locally](#run-buildkit-locally)" at the bottom of the readme. +**👋 Requirement**: an instance of Buildkit must be running locally. +Instructions in "[Run BuildKit Locally](#run-buildkit-locally)" at the bottom of +the readme. -Railpack will instantiate a BuildKit client and communicate to over GRPC in order to build the generated LLB. +Railpack will instantiate a BuildKit client and communicate to over GRPC in +order to build the generated LLB. ```bash go run cmd/cli/main.go --verbose build examples/node-bun @@ -43,9 +49,12 @@ You need to have a BuildKit instance running (see below). ## ② Custom frontend -You can build with a [custom BuildKit frontend](/guides/custom-frontend), but this is a bit tedious for local iteration. +You can build with a [custom BuildKit frontend](/guides/custom-frontend), but +this is a bit tedious for local iteration. -The frontend needs to be built into an image and accessible to the BuildKit instance. To see how you can build and push an image, see the `build-and-push-frontend` mise task in `mise.toml`. +The frontend needs to be built into an image and accessible to the BuildKit +instance. To see how you can build and push an image, see the +`build-and-push-frontend` mise task in `mise.toml`. Once you have an image, you can do: @@ -75,7 +84,9 @@ buildctl build \ --output type=docker,name=test | docker load ``` -_Note the `docker load` here to load the image into Docker. However, you can change the [output](https://github.com/moby/buildkit?tab=readme-ov-file#output) or push to a registry instead._ +_Note the `docker load` here to load the image into Docker. However, you can +change the [output](https://github.com/moby/buildkit?tab=readme-ov-file#output) +or push to a registry instead._ ## Run BuildKit Locally diff --git a/docs/src/content/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md index 3f962ba..f09ad16 100644 --- a/docs/src/content/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -5,20 +5,104 @@ description: Complete reference for the Railpack CLI commands Complete reference documentation for all Railpack CLI commands. +## Common Options + +The following options are available across multiple commands: + +| Flag | Description | +| --------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `--env` | Environment variables to set. Format: `KEY=VALUE` | +| `--previous-versions` | Versions of packages used for previous builds. These versions will be used instead of the defaults. Format: `NAME@VERSION` | +| `--build-cmd` | Build command to use | +| `--start-cmd` | Start command to use | + ## Commands ### build -Build a project using Railpack... +Build a project using Railpack. This command takes a directory as input and +builds a container image using BuildKit. + +**Usage:** + +```bash +railpack build [options] DIRECTORY +``` + +**Options:** + +| Flag | Description | Default | +| ------------- | ------------------------------------------------ | ------- | +| `--name` | Name of the image to build | | +| `--output` | Output the final filesystem to a local directory | | +| `--progress` | BuildKit progress output mode (auto, plain, tty) | `auto` | +| `--show-plan` | Show the build plan before building | `false` | ### plan -Generate and view build plans... +Generate and view build plans for a project. This command analyzes a directory +and outputs the build plan that would be used. + +**Usage:** + +```bash +railpack plan [options] DIRECTORY +``` + +**Options:** + +| Flag | Description | +| ------------- | ----------------------------- | +| `--out`, `-o` | Output file name for the plan | ### info -View information about the current project... +View detailed information about a project. This command analyzes a directory and +provides information about the detected configuration, dependencies, and build +requirements. + +**Usage:** + +```bash +railpack info [options] DIRECTORY +``` + +**Options:** + +| Flag | Description | Default | +| ---------- | ---------------------------- | -------- | +| `--format` | Output format (pretty, json) | `pretty` | +| `--out` | Output file name | | + +### schema + +Output the JSON schema for the Railpack configuration file. This command outputs +the schema that defines the structure of valid Railpack configuration files. The +schema can be used by IDEs and other tools for providing autocompletion and +validation. + +**Usage:** + +```bash +railpack schema +``` + +### frontend + +Start the BuildKit GRPC frontend server. This command is typically used +internally by the build system. + +**Usage:** + +```bash +railpack frontend +``` ## Global Options -List of global CLI options and flags... +These options can be used with any command: + +| Flag | Description | +| ----------------- | ------------------------ | +| `--help`, `-h` | Show help information | +| `--version`, `-v` | Show version information |