Skip to content

Commit

Permalink
Merge pull request #134 from seanpoulter/refactor
Browse files Browse the repository at this point in the history
feat: Fail fast when docker is not installed
  • Loading branch information
seanpoulter authored Mar 7, 2024
2 parents 6a6a218 + 085c0e4 commit 37e7ba7
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 84 deletions.
37 changes: 20 additions & 17 deletions src/launcher.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import fs from 'fs-extra';
import { SevereServiceError } from 'webdriverio';
import Docker from './utils/docker';
import getFilePath from './utils/getFilePath';
import logger from '@wdio/logger';
Expand All @@ -13,7 +14,7 @@ class DockerLauncher {
this.dockerLogs = null;
}

onPrepare(config) {
async onPrepare(config) {
this.logToStdout = config.logToStdout;
this.dockerLogs = config.dockerLogs;
this.watchMode = !!config.watch;
Expand Down Expand Up @@ -52,15 +53,18 @@ class DockerLauncher {
});
}

return this.docker.run()
.then(() => {
if (typeof onDockerReady === 'function') {
onDockerReady();
}
})
.catch((err) => {
Logger.error(`Failed to run container: ${ err.message }`);
});
try {
await this.docker.run();
if (typeof onDockerReady === 'function') {
onDockerReady();
}
}
catch (err) {
if (err.code === 'ENOENT' && err.path === 'docker') {
throw new SevereServiceError('Docker was not found.');
}
Logger.error(`Failed to run container: ${ err.message }`);
}
}

onComplete() {
Expand All @@ -80,14 +84,13 @@ class DockerLauncher {
* @param logFile
* @private
*/
_redirectLogStream(logFile) {
async _redirectLogStream(logFile) {
// ensure file & directory exists
return fs.ensureFile(logFile).then(() => {
const logStream = fs.createWriteStream(logFile, { flags: 'w' });

this.docker.process.stdout.pipe(logStream);
this.docker.process.stderr.pipe(logStream);
});
await fs.ensureFile(logFile);

const logStream = fs.createWriteStream(logFile, { flags: 'w' });
this.docker.process.stdout.pipe(logStream);
this.docker.process.stderr.pipe(logStream);
}
}

Expand Down
121 changes: 54 additions & 67 deletions src/utils/docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class Docker extends EventEmitter {
/**
* @return {Promise}
*/
run() {
async run() {
this.logger.log(`Docker command: ${ this.dockerRunCommand.join(SPACE) }`);
this.dockerEventsListener.connect({
filter: `image=${ this.image }`
Expand All @@ -80,69 +80,56 @@ class Docker extends EventEmitter {
});
}

return this._removeStaleContainer()
.then(() => {
return this._isImagePresent()
.catch(() => {
this.logger.warn('NOTE: Pulling image for the first time. Please be patient.');
return this._pullImage();
});
})
.then(() => {
this.logger.info(`Launching docker image '${ this.image }'`);
return runProcess(this.dockerRunCommand);
})
.then(process => {
this.process = process;
this.emit('processCreated');

if (this.debug) {
this.process.stdout.on('data', (data) => {
this.logger.log(data.toString());
});

this.process.stderr.on('data', (data) => {
this.logger.error(data.toString());
});

this.dockerEventsListener.once('container.start', (event) => {
this.logger.info('Container started:', JSON.stringify(event, null, 4));
});

this.dockerEventsListener.once('container.stop', (event) => {
this.logger.info('Container stopped:', JSON.stringify(event, null, 4));
});
}
await this._removeStaleContainer();

return this._reportWhenDockerIsRunning()
.then(() => {
this.logger.info('Docker container is ready');
return process;
});
})
.catch((err) => {
if (err.code === 'ENOENT') {
return Promise.resolve();
}
try {
await this._isImagePresent();
} catch (_err) {
this.logger.warn('NOTE: Pulling image for the first time. Please be patient.');
return this._pullImage();
}

this.logger.info(`Launching docker image '${this.image}'`);
const process = await runProcess(this.dockerRunCommand);
this.process = process;
this.emit('processCreated');

if (this.debug) {
this.process.stdout.on('data', (data) => {
this.logger.log(data.toString());
});

this.process.stderr.on('data', (data) => {
this.logger.error(data.toString());
});

this.dockerEventsListener.once('container.start', (event) => {
this.logger.info('Container started:', JSON.stringify(event, null, 4));
});

throw err;
this.dockerEventsListener.once('container.stop', (event) => {
this.logger.info('Container stopped:', JSON.stringify(event, null, 4));
});
}

await this._reportWhenDockerIsRunning();
this.logger.info('Docker container is ready');
return process;
}

/**
* @return {Promise}
*/
stop() {
return this._removeStaleContainer()
.then(() => {
if (this.process) {
this.process.kill();
this.process = null;
}
async stop() {
await this._removeStaleContainer();

this.logger.info('Docker container has stopped');
this.dockerEventsListener.disconnect();
});
if (this.process) {
this.process.kill();
this.process = null;
}

this.logger.info('Docker container has stopped');
this.dockerEventsListener.disconnect();
}

/**
Expand Down Expand Up @@ -219,20 +206,20 @@ class Docker extends EventEmitter {

/**
* Removes any stale docker image
* @return {Promise}
* @return {Promise<void>}
* @private
*/
_removeStaleContainer() {
return fs.readFile(this.cidfile)
.then((cid) => {
this.logger.info('Shutting down running container');
return Docker.stopContainer(cid).then(() => Docker.removeContainer(cid));
})
.catch(() => Promise.resolve())
.then(() => {
this.logger.info('Cleaning up CID files');
return fs.remove(this.cidfile);
});
async _removeStaleContainer() {
try {
const cid = await fs.readFile(this.cidfile);
this.logger.info('Shutting down running container');
await Docker.stopContainer(cid);
await Docker.removeContainer(cid);
}
catch (_err) {} // eslint-disable-line no-empty

this.logger.info('Cleaning up CID files');
await fs.remove(this.cidfile);
}

/**
Expand Down

0 comments on commit 37e7ba7

Please sign in to comment.