Skip to content

Commit

Permalink
feat: docker start
Browse files Browse the repository at this point in the history
  • Loading branch information
peterpeterparker committed Jan 25, 2024
1 parent 171429e commit a87213e
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 45 deletions.
4 changes: 4 additions & 0 deletions src/commands/dev.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {red} from 'kleur';
import {build} from '../services/build.services';
import {eject} from '../services/eject.services';
import {start} from '../services/start.services';
import {helpDev} from './help';

export const dev = async (args?: string[]) => {
Expand All @@ -13,6 +14,9 @@ export const dev = async (args?: string[]) => {
case 'build':
await build();
break;
case 'start':
await start();
break;
default:
console.log(`${red('Unknown command.')}`);
console.log(helpDev);
Expand Down
1 change: 1 addition & 0 deletions src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export const GITHUB_API_CLI_URL = 'https://api.github.com/repos/junobuild/cli';
export const IGNORE_OS_FILES = ['.ds_store', 'thumbs.db'];
export const RUST_MIN_VERSION = '1.71.0';
export const IC_WASM_MIN_VERSION = '0.3.6';
export const DOCKER_MIN_VERSION = '24.0.0';
7 changes: 5 additions & 2 deletions src/services/build.services.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {green, grey, magenta, yellow} from 'kleur';
import {existsSync} from 'node:fs';
import {lstat, mkdir} from 'node:fs/promises';
import {lstat, mkdir, rename} from 'node:fs/promises';
import {join, relative} from 'node:path';
import ora, {type Ora} from 'ora';
import {IC_WASM_MIN_VERSION} from '../constants/constants';
Expand Down Expand Up @@ -58,7 +58,10 @@ export const build = async () => {

spinner.text = 'Compressing...';

await gzipFile(SATELLITE_OUTPUT);
// We use a temporary file otherwise the automatic deployment in Docker may start with a file that is not yet fully gzipped
await gzipFile({source: SATELLITE_OUTPUT, destination: `${SATELLITE_OUTPUT}.tmp.gz`});

await rename(`${SATELLITE_OUTPUT}.tmp.gz`, `${SATELLITE_OUTPUT}.gz`);

await successMsg(spinner);
} finally {
Expand Down
45 changes: 7 additions & 38 deletions src/services/eject.services.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import {cyan, green, magenta, yellow} from 'kleur';
import {existsSync} from 'node:fs';
import {copyFile, mkdir} from 'node:fs/promises';
import {dirname, join, relative} from 'node:path';
import {fileURLToPath} from 'url';
import {mkdir} from 'node:fs/promises';
import {join} from 'node:path';
import {helpDevSubCommands} from '../commands/help';
import {checkRustVersion} from '../utils/env.utils';
import {confirm} from '../utils/prompt.utils';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
import {copyTemplateFile} from '../utils/fs.utils';

const TEMPLATE_PATH = '../templates/eject';
const TEMPLATE_SATELLITE_PATH = join(TEMPLATE_PATH, 'src/satellite');
Expand All @@ -18,29 +13,29 @@ export const eject = async () => {
const {valid} = await checkRustVersion();

if (valid === 'error') {
console.error(`Cannot detect your Rust runtime version. Is Cargo installed on your machine?`);
console.error(`Cannot detect your Rust version. Is Cargo installed on your machine?`);
return;
}

if (!valid) {
return;
}

await writeFile({
await copyTemplateFile({
template: 'Cargo.toml',
sourceFolder: TEMPLATE_PATH,
destinationFolder: '.'
});

await mkdir(join(process.cwd(), './src/satellite/src'), {recursive: true});

await writeFile({
await copyTemplateFile({
template: 'Cargo.toml',
sourceFolder: TEMPLATE_SATELLITE_PATH,
destinationFolder: DESTINATION_SATELLITE_PATH
});

await writeFile({
await copyTemplateFile({
template: 'lib.rs',
sourceFolder: join(TEMPLATE_SATELLITE_PATH, 'src'),
destinationFolder: join(DESTINATION_SATELLITE_PATH, 'src')
Expand All @@ -49,32 +44,6 @@ export const eject = async () => {
console.log(success({src: DESTINATION_SATELLITE_PATH}));
};

const writeFile = async ({
sourceFolder,
destinationFolder,
template
}: {
sourceFolder: string;
destinationFolder: string;
template: string;
}) => {
const destination = join(process.cwd(), destinationFolder, template);

if (existsSync(destination)) {
const answer = await confirm(
`File ${yellow(
relative(process.cwd(), destination)
)} already exists. Do you want to overwrite it?`
);

if (!answer) {
return;
}
}

await copyFile(join(__dirname, sourceFolder, template), destination);
};

export const success = ({src}: {src: string}): string => `
✅ Satellite successfully ejected!
Expand Down
66 changes: 66 additions & 0 deletions src/services/start.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {magenta} from 'kleur';
import {existsSync} from 'node:fs';
import {execute} from '../utils/cmd.utils';
import {checkDockerVersion} from '../utils/env.utils';
import {copyTemplateFile} from '../utils/fs.utils';
import {confirmAndExit} from '../utils/prompt.utils';

const TEMPLATE_PATH = '../templates/docker';
const DESTINATION_PATH = '.';

export const start = async () => {
const {valid} = await checkDockerVersion();

if (valid === 'error') {
console.error(`Cannot detect Docker version. Is Docker installed on your machine?`);
return;
}

if (!valid) {
return;
}

await assertJunoDevConfig();
await assertDockerCompose();

await execute({
command: 'docker',
args: ['compose', 'up']
});
};

const assertJunoDevConfig = async () => {
if (existsSync('juno.dev.json')) {
return;
}

await confirmAndExit(
`A config file is required for development. Would you like the CLI to create a default ${magenta(
'juno.dev.json'
)} for you?`
);

await copyTemplateFile({
template: 'juno.dev.json',
sourceFolder: TEMPLATE_PATH,
destinationFolder: DESTINATION_PATH
});
};

const assertDockerCompose = async () => {
if (existsSync('docker-compose.yml')) {
return;
}

await confirmAndExit(
`The CLI utilizes Docker Compose, which is handy for customizing configurations. Would you like the CLI to generate a default ${magenta(
'docker-compose.yml'
)} file for you?`
);

await copyTemplateFile({
template: 'docker-compose.yml',
sourceFolder: TEMPLATE_PATH,
destinationFolder: DESTINATION_PATH
});
};
14 changes: 10 additions & 4 deletions src/utils/compress.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@ export const gzipFiles = async ({
const pattern = gzip === true ? DEPLOY_DEFAULT_GZIP : gzip;

const filesToCompress = sourceFiles.filter((file) => minimatch(file, pattern));
return await Promise.all(filesToCompress.map(gzipFile));
return await Promise.all(filesToCompress.map(async (source) => await gzipFile({source})));
};

export const gzipFile = async (sourcePath: string) =>
export const gzipFile = async ({
source,
destination
}: {
source: string;
destination?: string;
}): Promise<string> =>
await new Promise<string>((resolve, reject) => {
const sourceStream = createReadStream(sourcePath);
const sourceStream = createReadStream(source);

const destinationPath = `${sourcePath}.gz`;
const destinationPath = destination ?? `${source}.gz`;
const destinationStream = createWriteStream(destinationPath);

const gzip = createGzip();
Expand Down
33 changes: 32 additions & 1 deletion src/utils/env.utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {green, yellow} from 'kleur';
import {lt, major} from 'semver';
import {IC_WASM_MIN_VERSION, NODE_18, RUST_MIN_VERSION} from '../constants/constants';
import {
DOCKER_MIN_VERSION,
IC_WASM_MIN_VERSION,
NODE_18,
RUST_MIN_VERSION
} from '../constants/constants';
import {spawn} from './cmd.utils';

export const checkNodeVersion = (): {valid: boolean | 'error'} => {
Expand Down Expand Up @@ -74,3 +79,29 @@ export const checkIcWasmVersion = async (): Promise<{valid: boolean | 'error'}>

return {valid: true};
};

export const checkDockerVersion = async (): Promise<{valid: boolean | 'error'}> => {
try {
let output = '';
await spawn({
command: 'docker',
args: ['--version'],
stdout: (o) => (output += o)
});

const version = output.replaceAll(',', '').trim().split(' ')[2];

if (lt(version, DOCKER_MIN_VERSION)) {
console.log(
`Your version of Docker is ${yellow(version.trim())}. Juno CLI requires ${green(
`${DOCKER_MIN_VERSION}`
)} or a more recent version.`
);
return {valid: false};
}
} catch (e: unknown) {
return {valid: 'error'};
}

return {valid: true};
};
35 changes: 35 additions & 0 deletions src/utils/fs.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {yellow} from 'kleur';
import {existsSync} from 'node:fs';
import {copyFile as fsCopyFile} from 'node:fs/promises';
import {dirname, join, relative} from 'node:path';
import {fileURLToPath} from 'url';
import {confirm} from './prompt.utils';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export const copyTemplateFile = async ({
sourceFolder,
destinationFolder,
template
}: {
sourceFolder: string;
destinationFolder: string;
template: string;
}) => {
const destination = join(process.cwd(), destinationFolder, template);

if (existsSync(destination)) {
const answer = await confirm(
`File ${yellow(
relative(process.cwd(), destination)
)} already exists. Do you want to overwrite it?`
);

if (!answer) {
return;
}
}

await fsCopyFile(join(__dirname, sourceFolder, template), destination);
};
12 changes: 12 additions & 0 deletions templates/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
services:
juno-satellite:
image: juno-satellite
ports:
- 5987:5987
volumes:
- my_dapp_new:/juno/.juno
- ./juno.dev.json:/juno/juno.dev.json
- ./target/deploy:/juno/target/deploy/

volumes:
my_dapp_new:
16 changes: 16 additions & 0 deletions templates/docker/juno.dev.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"satellite": {
"collections": {
"db": [
{
"collection": "demo",
"read": "managed",
"write": "managed",
"memory": "heap"
}
],
"storage": []
},
"controllers": []
}
}

0 comments on commit a87213e

Please sign in to comment.