From 3b9b46492e6b54d8c70c99c8112f50f8e79ea8dc Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Fri, 19 Dec 2025 17:58:08 -0600 Subject: [PATCH 1/3] buildx setup leia test --- .github/workflows/pr-setup-linux-tests.yml | 1 + examples/setup-linux-buildx/README.md | 30 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 examples/setup-linux-buildx/README.md diff --git a/.github/workflows/pr-setup-linux-tests.yml b/.github/workflows/pr-setup-linux-tests.yml index 682ab7d98..a7483ec1d 100644 --- a/.github/workflows/pr-setup-linux-tests.yml +++ b/.github/workflows/pr-setup-linux-tests.yml @@ -13,6 +13,7 @@ jobs: matrix: leia-test: - setup-linux + - setup-linux-buildx node-version: - "20" os: diff --git a/examples/setup-linux-buildx/README.md b/examples/setup-linux-buildx/README.md new file mode 100644 index 000000000..5aa777348 --- /dev/null +++ b/examples/setup-linux-buildx/README.md @@ -0,0 +1,30 @@ +# Setup Linux Buildx Tests + +This example exists primarily to test that `lando setup` correctly installs buildx when it is not present. + +* [lando setup](https://docs.lando.dev/cli/setup.html) + +## Verification commands + +Run the following commands to validate things are rolling as they should. + +```bash +# Should dogfood the core plugin we are testing against +lando plugin-add "@lando/core@file:../.." + +# Should have buildx installed by default on GitHub runners +docker buildx version + +# Should be able to remove buildx +rm -f ~/.docker/cli-plugins/docker-buildx +docker buildx version 2>&1 | grep -i "not found\|is not a docker command\|unknown command" || echo "buildx not found" + +# Should be able to run lando setup and have it reinstall buildx +lando setup -y --skip-common-plugins + +# Should have buildx installed again +docker buildx version + +# Should have installed buildx to the correct location +stat ~/.docker/cli-plugins/docker-buildx +``` From 5ebb0c7da7d8428599f9935c30535a501c6c7ed6 Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Sat, 20 Dec 2025 21:02:47 -0600 Subject: [PATCH 2/3] install buildx during setup --- CHANGELOG.md | 2 + examples/setup-linux-buildx/README.md | 11 ++-- hooks/lando-setup-buildx.js | 91 +++++++++++++++++++++++++++ index.js | 3 + tasks/setup.js | 6 ++ utils/get-config-defaults.js | 1 + 6 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 hooks/lando-setup-buildx.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 475e6c772..38766db3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }}) +* Updated `lando setup` to install `docker-buildx` if missing + ## v3.26.2 - [December 17, 2025](https://github.com/lando/core/releases/tag/v3.26.2) * Updated to use new Lando Alliance Apple Developer certificates diff --git a/examples/setup-linux-buildx/README.md b/examples/setup-linux-buildx/README.md index 5aa777348..bae79a8db 100644 --- a/examples/setup-linux-buildx/README.md +++ b/examples/setup-linux-buildx/README.md @@ -17,14 +17,17 @@ docker buildx version # Should be able to remove buildx rm -f ~/.docker/cli-plugins/docker-buildx -docker buildx version 2>&1 | grep -i "not found\|is not a docker command\|unknown command" || echo "buildx not found" +sudo rm -f /usr/local/lib/docker/cli-plugins/docker-buildx +sudo rm -f /usr/local/libexec/docker/cli-plugins/docker-buildx +sudo rm -f /usr/lib/docker/cli-plugins/docker-buildx +sudo rm -f /usr/libexec/docker/cli-plugins/docker-buildx + +# Should confirm buildx is no longer available +(docker buildx version 2>&1 || true) | tee >(cat) | grep -i "not found\|is not a docker command\|unknown command" # Should be able to run lando setup and have it reinstall buildx lando setup -y --skip-common-plugins # Should have buildx installed again docker buildx version - -# Should have installed buildx to the correct location -stat ~/.docker/cli-plugins/docker-buildx ``` diff --git a/hooks/lando-setup-buildx.js b/hooks/lando-setup-buildx.js new file mode 100644 index 000000000..291afded1 --- /dev/null +++ b/hooks/lando-setup-buildx.js @@ -0,0 +1,91 @@ +'use strict'; + +const axios = require('../utils/get-axios')(); +const fs = require('fs'); +const path = require('path'); + +/* + * Helper to get buildx download url + */ +const getBuildxDownloadUrl = (version = '0.30.1') => { + const arch = process.arch === 'arm64' ? 'arm64' : 'amd64'; + + switch (process.platform) { + case 'darwin': + return `https://github.com/docker/buildx/releases/download/v${version}/buildx-v${version}.darwin-${arch}`; + case 'linux': + return `https://github.com/docker/buildx/releases/download/v${version}/buildx-v${version}.linux-${arch}`; + case 'win32': + return `https://github.com/docker/buildx/releases/download/v${version}/buildx-v${version}.windows-${arch}.exe`; + } +}; + +/* + * Helper to get buildx download destination + */ +const getBuildxDownloadDest = home => { + const dir = path.join(home, '.docker', 'cli-plugins'); + switch (process.platform) { + case 'linux': + case 'darwin': + return path.join(dir, 'docker-buildx'); + case 'win32': + return path.join(dir, 'docker-buildx.exe'); + } +}; + +module.exports = async (lando, options) => { + const debug = require('../utils/debug-shim')(lando.log); + const {color} = require('listr2'); + + // get stuff from config/opts + const {home} = lando.config; + const {buildx} = options; + + // if buildx is set to false allow it to be skipped + if (buildx === false) return; + + const dest = getBuildxDownloadDest(home); + const url = getBuildxDownloadUrl(buildx); + + options.tasks.push({ + title: `Downloading buildx`, + id: 'setup-buildx', + dependsOn: ['setup-build-engine'], + description: '@lando/buildx (docker-buildx)', + version: `Docker Buildx v${buildx}`, + hasRun: async () => { + try { + await require('../utils/run-command')('docker', ['buildx', 'version'], {debug}); + return true; + } catch { + return false; + } + }, + canRun: async () => { + // throw error if we cannot ping the download link + await axios.head(url); + // true if we get here + return true; + }, + task: async (ctx, task) => new Promise((resolve, reject) => { + // ensure the cli-plugins directory exists + fs.mkdirSync(path.dirname(dest), {recursive: true}); + + const download = require('../utils/download-x')(url, {debug, dest, test: ['version']}); + // success + download.on('done', data => { + task.title = `Installed buildx (Docker Buildx) to ${dest}`; + resolve(data); + }); + // handle errors + download.on('error', error => { + reject(error); + }); + // update title to reflect download progress + download.on('progress', progress => { + task.title = `Downloading buildx ${color.dim(`[${progress.percentage}%]`)}`; + }); + }), + }); +}; diff --git a/index.js b/index.js index 090bed015..053f6695c 100644 --- a/index.js +++ b/index.js @@ -97,6 +97,9 @@ module.exports = async lando => { // ensure we setup docker-compose if needed lando.events.once('pre-setup', async options => await require('./hooks/lando-setup-orchestrator')(lando, options)); + // ensure we setup buildx if needed + lando.events.once('pre-setup', async options => await require('./hooks/lando-setup-buildx')(lando, options)); + // ensure we setup landonet lando.events.once('pre-setup', async options => await require('./hooks/lando-setup-landonet')(lando, options)); diff --git a/tasks/setup.js b/tasks/setup.js index cd097a580..0d5cae119 100644 --- a/tasks/setup.js +++ b/tasks/setup.js @@ -80,6 +80,11 @@ module.exports = lando => { default: defaults.orchestrator, string: true, }, + 'buildx': { + describe: 'Sets the version of buildx to install', + default: defaults.buildx, + string: true, + }, 'plugin': { describe: 'Sets additional plugin(s) to install', default: require('../utils/parse-to-plugin-strings')(defaults.plugins), @@ -129,6 +134,7 @@ module.exports = lando => { [--build-engine ] [--build-engine-accept-license] [--orchestrator ] + [--buildx ] [--plugin ...] [--skip-common-plugins] [--skip-install-ca] diff --git a/utils/get-config-defaults.js b/utils/get-config-defaults.js index ead6181e8..18d10c144 100644 --- a/utils/get-config-defaults.js +++ b/utils/get-config-defaults.js @@ -50,6 +50,7 @@ const defaultConfig = options => ({ // @TODO: orchestrator works a bit differently because it predates lando.setup() we set it elsewhere setup: { buildEngine: getBuildEngineVersion(process.landoPlatform ?? process.platform), + buildx: '0.30.1', buildEngineAcceptLicense: !require('is-interactive')(), commonPlugins: { '@lando/acquia': 'latest', From f37c5ef01b8dfe2ec93171b40fc32b296fa3b124 Mon Sep 17 00:00:00 2001 From: Aaron Feledy Date: Fri, 23 Jan 2026 15:53:08 -0600 Subject: [PATCH 3/3] fix docs links --- docs/config/performance.md | 2 +- docs/services/l337.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config/performance.md b/docs/config/performance.md index 778982925..4c1d61a8d 100644 --- a/docs/config/performance.md +++ b/docs/config/performance.md @@ -15,7 +15,7 @@ There are, however, a few different things you can do to improve performance. ## 1. VirtioFS on macOS -Docker Desktop [4.16.1](https://docs.docker.com/desktop/release-notes/#4161) finally makes VirtioFS file sharing generally available. VirtioFS offers [significant improvements in performance](https://www.jeffgeerling.com/blog/2022/new-docker-mac-virtiofs-file-sync-4x-faster) over the default gRPC FUSE mechanism. It's worth switching to but you will need at least Lando [3.9.0](https://github.com/lando/lando/releases/tag/v3.9.0) for it to work correctly. +Docker Desktop [4.16.1](https://docs.docker.com/desktop/release-notes/#4161) finally makes VirtioFS file sharing generally available. VirtioFS offers [significant improvements in performance](https://www.jeffgeerling.com/blog/2022/new-docker-mac-virtiofs-file-sync-4x-faster/) over the default gRPC FUSE mechanism. It's worth switching to but you will need at least Lando [3.9.0](https://github.com/lando/lando/releases/tag/v3.9.0) for it to work correctly. If you see errors when using it we recommend the following corrective action: diff --git a/docs/services/l337.md b/docs/services/l337.md index 040271f4a..1be1129de 100644 --- a/docs/services/l337.md +++ b/docs/services/l337.md @@ -211,7 +211,7 @@ services: imagefile: nginx:1.21 ``` -Note that if you do `buildkit: false` some image build features, specifically those in [Dockerfile 1.1.0+](https://docs.docker.com/build/buildkit/dockerfile-release-notes/#110) and the [ssh](#ssh) features of this service, may not be available. You can also use `buildx` as an alias for `buildkit`. If you use both it will evaluate to `true` if either is `true`. Really just don't use both ;)! +Note that if you do `buildkit: false` some image build features, specifically those in [Dockerfile 1.1.0+](https://github.com/moby/buildkit/releases/#110) and the [ssh](#ssh) features of this service, may not be available. You can also use `buildx` as an alias for `buildkit`. If you use both it will evaluate to `true` if either is `true`. Really just don't use both ;)! You probably should just ignore this setting unless you have a well understood reason to do otherwise.