@wocker/ws
Version:
Docker workspace for web projects
309 lines (308 loc) • 12.9 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectService = void 0;
const core_1 = require("@wocker/core");
const docker_module_1 = require("@wocker/docker-module");
const cli_1 = require("@kearisp/cli");
const preset_1 = require("../../preset");
const ProjectRepository_1 = require("../repositories/ProjectRepository");
class PublicCli extends cli_1.Cli {
parseCommand(command, index) {
return super.parseCommand(command, index);
}
}
let ProjectService = class ProjectService extends core_1.ProjectService {
constructor(appConfigService, processService, eventService, dockerService, composeService, projectRepository, presetService, presetRepository, logService) {
super();
this.appConfigService = appConfigService;
this.processService = processService;
this.eventService = eventService;
this.dockerService = dockerService;
this.composeService = composeService;
this.projectRepository = projectRepository;
this.presetService = presetService;
this.presetRepository = presetRepository;
this.logService = logService;
}
get(name) {
const project = name
? this.projectRepository.searchOne({ name })
: this.projectRepository.searchOne({
path: this.processService.pwd()
});
if (!project) {
throw new Error("Project not found");
}
if (name) {
this.processService.chdir(project.path);
}
return project;
}
search(params = {}) {
return this.projectRepository.search(params);
}
searchOne(params = {}) {
return this.projectRepository.searchOne(params);
}
save(project) {
this.projectRepository.save(project);
}
async start(project, restart, rebuild, attach) {
if (restart || rebuild) {
await this.stop(project);
}
await this.build(project, rebuild);
await this.eventService.emit("project:beforeStart", project);
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET: {
let container = await this.dockerService.getContainer(project.containerName);
const fs = new core_1.FileSystem(project.path);
if (!container) {
container = await this.dockerService.createContainer({
name: project.containerName,
image: project.imageName,
cmd: project.cmd,
env: {
...this.appConfigService.config.env || {},
...project.env || {}
},
ports: project.ports || [],
volumes: (project.volumes || []).map((volume) => {
const regVolume = /^([^:]+):([^:]+)(?::([^:]+))?$/;
const [, source, destination, options] = regVolume.exec(volume);
if (source.startsWith("/")) {
return volume;
}
return `${fs.path(source)}:${destination}` + (options ? `:${options}` : "");
}),
extraHosts: Object.keys(project.extraHosts || {}).map((host) => {
return `${project.extraHosts[host]}:${host}`;
})
});
}
const { State: { Status } } = await container.inspect();
if (Status === "created" || Status === "exited") {
await container.start();
}
break;
}
case core_1.PROJECT_TYPE_COMPOSE: {
await this.composeService.up({
context: project.path,
composefile: project.composefile
});
break;
}
}
await this.eventService.emit("project:start", project);
await this.eventService.emit("project:afterStart", project);
if (attach) {
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET:
await this.dockerService.attach(project.containerName);
break;
case core_1.PROJECT_TYPE_COMPOSE:
break;
}
}
}
async stop(project) {
await this.eventService.emit("project:beforeStop", project);
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET:
await this.dockerService.removeContainer(project.containerName);
break;
case core_1.PROJECT_TYPE_COMPOSE: {
await this.composeService.down({
context: project.path,
composefile: project.composefile
});
break;
}
}
await this.eventService.emit("project:stop", project);
}
async build(project, rebuild) {
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
await this.dockerService.pullImage(project.imageName);
break;
case core_1.PROJECT_TYPE_DOCKERFILE: {
project.imageName = `project-${project.name}:develop`;
project.save();
if (rebuild) {
await this.dockerService.imageRm(project.imageName);
}
if (!await this.dockerService.imageExists(project.imageName)) {
await this.dockerService.buildImage({
version: this.appConfigService.isExperimentalEnabled("buildKit") ? "2" : "1",
tag: project.imageName,
buildArgs: project.buildArgs,
context: project.path,
dockerfile: project.dockerfile
});
}
break;
}
case core_1.PROJECT_TYPE_PRESET: {
const preset = this.presetRepository.searchOne({
name: project.preset
});
if (preset.image) {
await this.dockerService.pullImage(preset.image);
project.imageName = preset.image;
project.save();
}
if (preset.dockerfile) {
project.imageName = this.presetService.getImageNameForProject(project, preset);
project.save();
if (rebuild) {
await this.dockerService.imageRm(project.imageName);
}
if (!await this.dockerService.imageExists(project.imageName)) {
await this.dockerService.buildImage({
version: this.appConfigService.isExperimentalEnabled("buildKit") ? "2" : "1",
tag: project.imageName,
labels: {
"org.wocker.preset": preset.name
},
buildArgs: project.buildArgs,
context: project.presetMode === "project"
? [preset.path, project.path]
: preset.path,
dockerfile: preset.dockerfile
});
}
}
break;
}
case core_1.PROJECT_TYPE_COMPOSE: {
await this.composeService.build({
context: project.path,
composefile: project.composefile
});
break;
}
}
await this.eventService.emit("project:build", project, rebuild);
}
async attach(project) {
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET: {
await this.dockerService.attach(project.containerName);
break;
}
}
}
async run(project, script, service, args = []) {
if (!project.scripts || !project.scripts[script]) {
throw new Error(`Script ${script} not found`);
}
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET: {
const container = await this.dockerService.getContainer(project.containerName);
if (!container) {
throw new Error("The project is not started");
}
const cli = new PublicCli();
const cmd = cli.parseCommand(`command ${project.scripts[script]}`, 0);
this.logService.debug(cmd);
const exec = await container.exec({
AttachStdin: true,
AttachStdout: true,
AttachStderr: true,
Tty: process.stdin.isTTY,
Cmd: [...cmd, ...args || []]
});
const stream = await exec.start({
hijack: true,
stdin: true,
Tty: process.stdin.isTTY
});
await this.dockerService.attachStream(stream);
break;
}
case core_1.PROJECT_TYPE_COMPOSE: {
console.log(service, script, args);
break;
}
}
}
async exec(project, command) {
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET:
await this.dockerService.exec(project.containerName, command, true);
break;
case core_1.PROJECT_TYPE_COMPOSE: {
const [service, ...args] = command;
await this.composeService.exec({
service,
args,
context: project.path,
composefile: project.composefile
});
break;
}
}
}
async logs(project, detach) {
switch (project.type) {
case core_1.PROJECT_TYPE_IMAGE:
case core_1.PROJECT_TYPE_DOCKERFILE:
case core_1.PROJECT_TYPE_PRESET: {
const container = await this.dockerService.getContainer(project.containerName);
if (!container) {
throw new Error("Project not started");
}
if (!detach) {
await this.dockerService.logs(container);
}
else {
const data = await container.logs({
stdout: true,
stderr: true,
follow: false
});
process.stdout.write(data);
}
break;
}
case core_1.PROJECT_TYPE_COMPOSE:
break;
}
}
};
exports.ProjectService = ProjectService;
exports.ProjectService = ProjectService = __decorate([
(0, core_1.Injectable)("PROJECT_SERVICE"),
__metadata("design:paramtypes", [core_1.AppConfigService,
core_1.ProcessService,
core_1.EventService,
docker_module_1.DockerService,
docker_module_1.ComposeService,
ProjectRepository_1.ProjectRepository,
preset_1.PresetService,
preset_1.PresetRepository,
core_1.LogService])
], ProjectService);