Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/init.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
tart clone ghcr.io/kevinwang5658/sonoma-codify:v0.0.3 codify-test-vm
tart clone ghcr.io/kevinwang5658/sonoma-codify:v0.0.3 codify-sonoma
# tart clone ghcr.io/kevinwang5658/sonoma-codify:v0.0.3 codify-sonoma
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { VscodeResource } from './resources/vscode/vscode.js';
import { XcodeToolsResource } from './resources/xcode-tools/xcode-tools.js';
import { MacportsResource } from './resources/macports/macports.js';
import { Npm } from './resources/node/npm/npm.js';
import { DockerResource } from './resources/docker/docker.js';

runPlugin(Plugin.create(
'default',
Expand Down Expand Up @@ -74,5 +75,6 @@ runPlugin(Plugin.create(
new PipSync(),
new MacportsResource(),
new Npm(),
new DockerResource(),
])
)
18 changes: 18 additions & 0 deletions src/resources/docker/docker-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://www.codifycli.com/docker.json",
"title": "Docker resource",
"type": "object",
"description": "Installs docker.",
"properties": {
"acceptLicense": {
"type": "boolean",
"description": "Accepts the license agreement. Defaults to true"
},
"useCurrentUser": {
"type": "boolean",
"description": "Use the current user to install docker. Defaults to true"
}
},
"additionalProperties": false
}
102 changes: 102 additions & 0 deletions src/resources/docker/docker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { CreatePlan, DestroyPlan, Resource, ResourceSettings, getPty } from 'codify-plugin-lib';
import { StringIndexedObject } from 'codify-schemas';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

import { SpawnStatus, codifySpawn } from '../../utils/codify-spawn.js';
import { FileUtils } from '../../utils/file-utils.js';
import { Utils } from '../../utils/index.js';
import Schema from './docker-schema.json';

export interface DockerConfig extends StringIndexedObject {
acceptLicense?: boolean;
useCurrentUser?: boolean;
}

const ARM_DOWNLOAD_LINK = 'https://desktop.docker.com/mac/main/arm64/Docker.dmg'
const INTEL_DOWNLOAD_LINK = 'https://desktop.docker.com/mac/main/amd64/Docker.dmg'

export class DockerResource extends Resource<DockerConfig> {
getSettings(): ResourceSettings<DockerConfig> {
return {
id: 'docker',
schema: Schema,
parameterSettings: {
acceptLicense: {
type: 'boolean',
setting: true,
default: true,
},
// version: {
// type: 'version'
// },
useCurrentUser: {
type: 'boolean',
setting: true,
default: true,
}
}
};
}

async refresh(): Promise<Partial<DockerConfig> | Partial<DockerConfig>[] | null> {
const $ = getPty();

const versionResult = await $.spawnSafe('docker --version');
if (versionResult.status === SpawnStatus.ERROR) {
return null;
}

const result: DockerConfig = {};

// TODO: support versioning in the future
// const version = /Docker version (.*), build/.exec(versionResult.data)?.[1];
// if (version && parameters.version) {
// result.version = version;
// }

return result;
}

/**
* References:
* Blog about docker changes: https://dazwallace.wordpress.com/2022/12/02/changes-to-docker-desktop-for-mac/
* Path: https://stackoverflow.com/questions/64009138/docker-command-not-found-when-running-on-mac
* Issue: https://github.com/docker/for-mac/issues/6504
* @param plan
*/
async create(plan: CreatePlan<DockerConfig>): Promise<void> {
const downloadLink = await Utils.isArmArch() ? ARM_DOWNLOAD_LINK : INTEL_DOWNLOAD_LINK;

const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'codify-docker'))
await Utils.downloadUrlIntoFile(path.join(tmpDir, 'Docker.dmg'), downloadLink);
const user = Utils.getUser();

try {
await codifySpawn('hdiutil attach Docker.dmg', { cwd: tmpDir, requiresRoot: true })

console.log('Running Docker installer. This may take a couple of minutes to complete...')
await codifySpawn(`/Volumes/Docker/Docker.app/Contents/MacOS/install ${plan.desiredConfig.acceptLicense ? '--accept-license' : ''} ${plan.desiredConfig.useCurrentUser ? `--user ${user}` : ''}`,
{ requiresRoot: true }
)
await codifySpawn('hdiutil detach /Volumes/Docker', { cwd: tmpDir, requiresRoot: true })
} finally {
await fs.rm(tmpDir, { recursive: true, force: true })
}

await codifySpawn('xattr -r -d com.apple.quarantine /Applications/Docker.app', { requiresRoot: true });
await FileUtils.addPathToZshrc('/Applications/Docker.app/Contents/Resources/bin', false);
}

async destroy(plan: DestroyPlan<DockerConfig>): Promise<void> {
await codifySpawn('/Applications/Docker.app/Contents/MacOS/uninstall', { throws: false })
await fs.rm(path.join(os.homedir(), 'Library/Group\\ Containers/group.com.docker'), { recursive: true, force: true });
await fs.rm(path.join(os.homedir(), 'Library/Containers/com.docker.docker/Data'), { recursive: true, force: true });
await fs.rm(path.join(os.homedir(), '.docker'), { recursive: true, force: true });
await codifySpawn('rm -rf /Applications/Docker.app', { requiresRoot: true })

await FileUtils.removeLineFromZshrc('/Applications/Docker.app/Contents/Resources/bin')
}

}
8 changes: 4 additions & 4 deletions src/resources/node/npm/npm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CreatePlan, DestroyPlan, RefreshContext, Resource, ResourceSettings, getPty } from 'codify-plugin-lib';
import { Resource, ResourceSettings, getPty } from 'codify-plugin-lib';
import { ResourceConfig } from 'codify-schemas';

import { NpmGlobalInstallParameter, NpmPackage } from './global-install.js';
Expand All @@ -22,7 +22,7 @@ export class Npm extends Resource<NpmConfig> {
}
}

async refresh(parameters: Partial<NpmConfig>, context: RefreshContext<NpmConfig>): Promise<Partial<NpmConfig> | Partial<NpmConfig>[] | null> {
async refresh(parameters: Partial<NpmConfig>): Promise<Partial<NpmConfig> | Partial<NpmConfig>[] | null> {
const pty = getPty();

const { status } = await pty.spawnSafe('which npm')
Expand All @@ -34,9 +34,9 @@ export class Npm extends Resource<NpmConfig> {
}

// Npm gets created with NodeJS
async create(plan: CreatePlan<NpmConfig>): Promise<void> {}
async create(): Promise<void> {}

// Npm is destroyed with NodeJS
destroy(plan: DestroyPlan<NpmConfig>): Promise<void> {}
async destroy(): Promise<void> {}

}
17 changes: 11 additions & 6 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import * as fs from 'node:fs/promises';
import * as fsSync from 'node:fs';

import { codifySpawn, SpawnStatus } from './codify-spawn.js';
import { SpotlightKind, SpotlightUtils } from './spotlight-search.js';
import * as fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { finished } from 'node:stream/promises';
import { Readable } from 'node:stream';
import { finished } from 'node:stream/promises';

import { SpawnStatus, codifySpawn } from './codify-spawn.js';
import { SpotlightKind, SpotlightUtils } from './spotlight-search.js';

export const Utils = {
async findApplication(name: string): Promise<string[]> {
Expand Down Expand Up @@ -73,7 +74,7 @@ export const Utils = {

async isArmArch(): Promise<boolean> {
const query = await codifySpawn('sysctl -n machdep.cpu.brand_string');
return /M([0-9])/.test(query.data);
return /M(\d)/.test(query.data);
},

async isDirectoryOnPath(directory: string): Promise<boolean> {
Expand Down Expand Up @@ -108,4 +109,8 @@ export const Utils = {
// Different type definitions here for readable stream (NodeJS vs DOM). Small hack to fix that
await finished(Readable.fromWeb(body as never).pipe(ws));
},

getUser(): string {
return os.userInfo().username;
}
};
22 changes: 22 additions & 0 deletions test/docker/docker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { beforeEach, describe, expect, it } from 'vitest';
import { PluginTester } from 'codify-plugin-test';
import * as path from 'node:path';
import cp from 'child_process';

describe('Test docker', async () => {
const pluginPath = path.resolve('./src/index.ts');

it('Can install docker', { timeout: 300000 }, async () => {
await PluginTester.fullTest(pluginPath, [
{ type: 'docker' },
], {
validateApply: async () => {
expect(() => cp.execSync('source ~/.zshrc; which aws;')).to.not.throw;

},
validateDestroy: async () => {
expect(() => cp.execSync('source ~/.zshrc; which aws;')).to.throw;
}
})
})
})
Loading