Skip to content

Commit 4c9dc63

Browse files
committed
feat: add buildx check/install to lando setup
Installs docker-buildx plugin during lando setup if not present. Supports configurable version via --buildx flag. Duplicates lando/core#423 for core-next.
1 parent c2b03a9 commit 4c9dc63

File tree

6 files changed

+136
-0
lines changed

6 files changed

+136
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## {{ UNRELEASED_VERSION }} - [{{ UNRELEASED_DATE }}]({{ UNRELEASED_LINK }})
22

3+
* Updated `lando setup` to install `docker-buildx` if missing
4+
35
## v4.0.0-unstable.8 - [December 9, 2025](https://github.com/lando/core-next/releases/tag/v4.0.0-unstable.8)
46

57
* Updated to prep for `bunification` part 2
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Setup Linux Buildx Tests
2+
3+
This example exists primarily to test that `lando setup` correctly installs buildx when it is not present.
4+
5+
* [lando setup](https://docs.lando.dev/cli/setup.html)
6+
7+
## Verification commands
8+
9+
Run the following commands to validate things are rolling as they should.
10+
11+
```bash
12+
# Should dogfood the core plugin we are testing against
13+
lando plugin-add "@lando/core@file:../.."
14+
15+
# Should have buildx installed by default on GitHub runners
16+
docker buildx version
17+
18+
# Should be able to remove buildx
19+
rm -f ~/.docker/cli-plugins/docker-buildx
20+
sudo rm -f /usr/local/lib/docker/cli-plugins/docker-buildx
21+
sudo rm -f /usr/local/libexec/docker/cli-plugins/docker-buildx
22+
sudo rm -f /usr/lib/docker/cli-plugins/docker-buildx
23+
sudo rm -f /usr/libexec/docker/cli-plugins/docker-buildx
24+
25+
# Should confirm buildx is no longer available
26+
(docker buildx version 2>&1 || true) | tee >(cat) | grep -i "not found\|is not a docker command\|unknown command"
27+
28+
# Should be able to run lando setup and have it reinstall buildx
29+
lando setup -y --skip-common-plugins
30+
31+
# Should have buildx installed again
32+
docker buildx version
33+
```

hooks/lando-setup-buildx.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
'use strict';
2+
3+
const axios = require('../utils/get-axios')();
4+
const fs = require('fs');
5+
const path = require('path');
6+
7+
/*
8+
* Helper to get buildx download url
9+
*/
10+
const getBuildxDownloadUrl = (version = '0.30.1') => {
11+
const arch = process.arch === 'arm64' ? 'arm64' : 'amd64';
12+
13+
switch (process.platform) {
14+
case 'darwin':
15+
return `https://github.com/docker/buildx/releases/download/v${version}/buildx-v${version}.darwin-${arch}`;
16+
case 'linux':
17+
return `https://github.com/docker/buildx/releases/download/v${version}/buildx-v${version}.linux-${arch}`;
18+
case 'win32':
19+
return `https://github.com/docker/buildx/releases/download/v${version}/buildx-v${version}.windows-${arch}.exe`;
20+
}
21+
};
22+
23+
/*
24+
* Helper to get buildx download destination
25+
*/
26+
const getBuildxDownloadDest = home => {
27+
const dir = path.join(home, '.docker', 'cli-plugins');
28+
switch (process.platform) {
29+
case 'linux':
30+
case 'darwin':
31+
return path.join(dir, 'docker-buildx');
32+
case 'win32':
33+
return path.join(dir, 'docker-buildx.exe');
34+
}
35+
};
36+
37+
module.exports = async (lando, options) => {
38+
const debug = require('../utils/debug-shim')(lando.log);
39+
const {color} = require('listr2');
40+
41+
// get stuff from config/opts
42+
const {home} = lando.config;
43+
const {buildx} = options;
44+
45+
// if buildx is set to false allow it to be skipped
46+
if (buildx === false) return;
47+
48+
const dest = getBuildxDownloadDest(home);
49+
const url = getBuildxDownloadUrl(buildx);
50+
51+
options.tasks.push({
52+
title: `Downloading buildx`,
53+
id: 'setup-buildx',
54+
dependsOn: ['setup-build-engine'],
55+
description: '@lando/buildx (docker-buildx)',
56+
version: `Docker Buildx v${buildx}`,
57+
hasRun: async () => {
58+
try {
59+
await require('../utils/run-command')('docker', ['buildx', 'version'], {debug});
60+
return true;
61+
} catch {
62+
return false;
63+
}
64+
},
65+
canRun: async () => {
66+
// throw error if we cannot ping the download link
67+
await axios.head(url);
68+
// true if we get here
69+
return true;
70+
},
71+
task: async (ctx, task) => new Promise((resolve, reject) => {
72+
// ensure the cli-plugins directory exists
73+
fs.mkdirSync(path.dirname(dest), {recursive: true});
74+
75+
const download = require('../utils/download-x')(url, {debug, dest, test: ['version']});
76+
// success
77+
download.on('done', data => {
78+
task.title = `Installed buildx (Docker Buildx) to ${dest}`;
79+
resolve(data);
80+
});
81+
// handle errors
82+
download.on('error', error => {
83+
reject(error);
84+
});
85+
// update title to reflect download progress
86+
download.on('progress', progress => {
87+
task.title = `Downloading buildx ${color.dim(`[${progress.percentage}%]`)}`;
88+
});
89+
}),
90+
});
91+
};

index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ module.exports = async lando => {
9797
// ensure we setup docker-compose if needed
9898
lando.events.once('pre-setup', async options => await require('./hooks/lando-setup-orchestrator')(lando, options));
9999

100+
// ensure we setup buildx if needed
101+
lando.events.once('pre-setup', async options => await require('./hooks/lando-setup-buildx')(lando, options));
102+
100103
// ensure we setup landonet
101104
lando.events.once('pre-setup', async options => await require('./hooks/lando-setup-landonet')(lando, options));
102105

tasks/setup.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ module.exports = lando => {
8080
default: defaults.orchestrator,
8181
string: true,
8282
},
83+
'buildx': {
84+
describe: 'Sets the version of buildx to install',
85+
default: defaults.buildx,
86+
string: true,
87+
},
8388
'plugin': {
8489
describe: 'Sets additional plugin(s) to install',
8590
default: require('../utils/parse-to-plugin-strings')(defaults.plugins),
@@ -129,6 +134,7 @@ module.exports = lando => {
129134
[--build-engine <version>]
130135
[--build-engine-accept-license]
131136
[--orchestrator <version>]
137+
[--buildx <version>]
132138
[--plugin <plugin>...]
133139
[--skip-common-plugins]
134140
[--skip-install-ca]

utils/get-config-defaults.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const defaultConfig = options => ({
5050
// @TODO: orchestrator works a bit differently because it predates lando.setup() we set it elsewhere
5151
setup: {
5252
buildEngine: getBuildEngineVersion(process.landoPlatform ?? process.platform),
53+
buildx: '0.30.1',
5354
buildEngineAcceptLicense: !require('is-interactive')(),
5455
commonPlugins: {
5556
'@lando/acquia': 'latest',

0 commit comments

Comments
 (0)