UNPKG

@wocker/ws

Version:

Docker workspace for web projects

309 lines (308 loc) 12.9 kB
"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);