Skip to content

Commit

Permalink
fix: docker and docker compose error in doctor sub-command
Browse files Browse the repository at this point in the history
  • Loading branch information
omidasadpour authored and endersonmaia committed Apr 30, 2024
1 parent d426c00 commit 5cf5187
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 40 deletions.
5 changes: 5 additions & 0 deletions .changeset/ten-llamas-smile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cartesi/cli": patch
---

fixed checking docker and docker compose in doctor command
136 changes: 96 additions & 40 deletions apps/cli/src/commands/doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,75 +9,131 @@ export default class DoctorCommand extends BaseCommand<typeof DoctorCommand> {

private static MINIMUM_DOCKER_VERSION = "23.0.0"; // Replace with our minimum required Docker version
private static MINIMUM_DOCKER_COMPOSE_VERSION = "2.21.0"; // Replace with our minimum required Docker Compose version
private static MINIMUM_BUILDX_VERSION = "0.13.0"; // Replace with our minimum required Buildx version

private static isDockerVersionValid(version: string): boolean {
return semver.gte(version, DoctorCommand.MINIMUM_DOCKER_VERSION);
}
private async checkDocker(): Promise<true | never> {
try {
const { stdout: dockerVersion } = await execa("docker", [
"version",
"--format",
"{{json .Client.Version}}",
]);

private static isDockerComposeVersionValid(version: string): boolean {
const v = semver.coerce(version);
return (
v !== null &&
semver.gte(v, DoctorCommand.MINIMUM_DOCKER_COMPOSE_VERSION)
);
}
const v = semver.coerce(dockerVersion);
if (
v !== null &&
!semver.gte(v, DoctorCommand.MINIMUM_DOCKER_VERSION)
) {
throw new Error(
`Unsupported Docker version. Minimum required version is ${DoctorCommand.MINIMUM_DOCKER_VERSION}. Installed version is ${v}.`,
);
}
} catch (e: unknown) {
if (
e instanceof Error &&
(e as NodeJS.ErrnoException).code === "ENOENT"
) {
throw new Error("Docker not found");
} else {
throw e;
}
}

private static isBuildxRiscv64Supported(buildxOutput: string): boolean {
return buildxOutput.includes("riscv64");
return true;
}

public async run() {
private async checkCompose(): Promise<true | never> {
try {
// Check Docker version
const { stdout: dockerVersionOutput } = await execa("docker", [
const { stdout: dockerComposeVersion } = await execa("docker", [
"compose",
"version",
"--format",
"{{json .Client.Version}}",
"--short",
]);
const dockerVersion = JSON.parse(dockerVersionOutput);

if (!DoctorCommand.isDockerVersionValid(dockerVersion)) {
const v = semver.coerce(dockerComposeVersion);
if (
v !== null &&
!semver.gte(v, DoctorCommand.MINIMUM_DOCKER_COMPOSE_VERSION)
) {
throw new Error(
`Unsupported Docker Compose version. Minimum required version is ${DoctorCommand.MINIMUM_DOCKER_COMPOSE_VERSION}. Installed version is ${v}.`,
);
}
} catch (e: unknown) {
if (
e instanceof Error &&
(e as Error & { exitCode?: number }).exitCode === 125
) {
throw new Error(
`Unsupported Docker version. Minimum required version is ${DoctorCommand.MINIMUM_DOCKER_VERSION}. Installed version is ${dockerVersion}.`,
"Docker Compose is required but not installed or the command execution failed. Please refer to the Docker Compose documentation for installation instructions: https://docs.docker.com/compose/install/",
);
} else {
throw e;
}
}

// Check Docker Compose version
const { stdout: dockerComposeVersionOutput } = await execa(
"docker",
["compose", "version", "--short"],
);
const dockerComposeVersion = dockerComposeVersionOutput.trim();
return true;
}

private async checkBuildx(): Promise<true | never> {
try {
const { stdout: buildxOutput } = await execa("docker", [
"buildx",
"version",
]);

const v = semver.coerce(buildxOutput);
if (
!DoctorCommand.isDockerComposeVersionValid(dockerComposeVersion)
v !== null &&
!semver.gte(v, DoctorCommand.MINIMUM_BUILDX_VERSION)
) {
throw new Error(
`Unsupported Docker Compose version. Minimum required version is ${DoctorCommand.MINIMUM_DOCKER_COMPOSE_VERSION}. Installed version is ${dockerComposeVersion}.`,
`Unsupported Docker Buildx version. Minimum required version is ${DoctorCommand.MINIMUM_BUILDX_VERSION}. Installed version is ${v}.`,
);
}

// Check Docker Buildx version and riscv64 support
const { stdout: buildxOutput } = await execa("docker", [
const { stdout: platformsOutput } = await execa("docker", [
"buildx",
"ls",
"--format",
"{{.Platforms}}",
]);
const buildxRiscv64Supported =
DoctorCommand.isBuildxRiscv64Supported(buildxOutput);

if (!buildxRiscv64Supported) {
const buildxPlatforms: string[] = platformsOutput
.split(",")
.map((platform) => platform.trim());

if (!buildxPlatforms.includes("linux/riscv64")) {
throw new Error(
"Your system does not support riscv64 architecture.",
"Your system does not support riscv64 architecture. Run `docker run --privileged --rm tonistiigi/binfmt:riscv` to enable riscv64 support.",
);
}

this.log(`Your system is ready for ${this.config.bin}.`);
} catch (error: unknown) {
if (error instanceof Error) {
this.error(error.message);
} catch (e: unknown) {
if (
e instanceof Error &&
(e as Error & { exitCode?: number }).exitCode === 125
) {
throw new Error(
"Docker Buildx is required but not installed. Please refer to the Docker Desktop documentation for installation instructions: https://docs.docker.com/desktop/",
);
} else {
this.error(String(error));
throw e;
}
}

return true;
}

public async run(): Promise<void> {
try {
if (await this.checkDocker()) {
await this.checkCompose();
await this.checkBuildx();
}
} catch (e: unknown) {
this.error(e as Error);
}

this.log("Your system is ready.");
}
}

0 comments on commit 5cf5187

Please sign in to comment.