UNPKG

5.75 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const fs_1 = __importDefault(require("fs"));
7const path_1 = __importDefault(require("path"));
8const schema_1 = require("@stencila/schema");
9const DockerParser_1 = __importDefault(require("./DockerParser"));
10const parsers_1 = __importDefault(require("./parsers"));
11const DockerGenerator_1 = __importDefault(require("./DockerGenerator"));
12const DockerBuilder_1 = __importDefault(require("./DockerBuilder"));
13const DockerExecutor_1 = __importDefault(require("./DockerExecutor"));
14/**
15 * Compiles a project into a Dockerfile, or Docker image
16 */
17class DockerCompiler {
18 constructor(urlFetcher) {
19 this.urlFetcher = urlFetcher;
20 }
21 /**
22 * Compile a project
23 *
24 * @param source The folder, Dockerfile or `SoftwareEnvironment` to compile
25 * @param build Should the Docker image be built?
26 * @param comments Should comments be added to the Dockerfile?
27 * @param stencila Should relevant Stencila language packages be installed in the image?
28 */
29 async compile(source, build = true, comments = true, stencila = false) {
30 let folder;
31 if (source.substring(0, 7) === 'file://') {
32 folder = source.substring(7);
33 }
34 else {
35 folder = source;
36 }
37 let dockerfile;
38 let environ;
39 if (fs_1.default.existsSync(path_1.default.join(folder, 'Dockerfile'))) {
40 // Dockerfile found so use that
41 dockerfile = 'Dockerfile';
42 environ = await new DockerParser_1.default(this.urlFetcher, folder).parse();
43 }
44 else {
45 if (fs_1.default.existsSync(path_1.default.join(folder, 'environ.jsonld'))) {
46 // Read existing environment from file
47 const jsonld = fs_1.default.readFileSync(path_1.default.join(folder, 'environ.jsonld'), 'utf8');
48 const initializer = JSON.parse(jsonld);
49 environ = new schema_1.SoftwareEnvironment(initializer);
50 }
51 else {
52 // Create environment by merging packages
53 // generated by each language parser
54 environ = new schema_1.SoftwareEnvironment();
55 environ.name = path_1.default.basename(folder);
56 for (let ParserClass of parsers_1.default) {
57 const parser = new ParserClass(this.urlFetcher, folder);
58 const pkg = await parser.parse();
59 if (pkg)
60 environ.softwareRequirements.push(pkg);
61 }
62 // Save environ as an intermediate file
63 const jsonld = JSON.stringify(environ.toJSONLD(), null, ' ');
64 fs_1.default.writeFileSync(path_1.default.join(folder, '.environ.jsonld'), jsonld);
65 }
66 // Generate Dockerfile
67 dockerfile = '.Dockerfile';
68 new DockerGenerator_1.default(this.urlFetcher, environ, folder).generate(comments, stencila);
69 }
70 if (build) {
71 // Use the name of the environment, if possible
72 let name = (environ && environ.name) || undefined;
73 // Build the image!
74 const builder = new DockerBuilder_1.default();
75 await builder.build(folder, name, dockerfile);
76 }
77 return environ;
78 }
79 /**
80 * Execute the project by compiling, building and running a Docker container for it
81 *
82 * @param source The project to execute
83 */
84 async execute(source, command = '') {
85 let folder;
86 if (source.substring(0, 7) === 'file://') {
87 folder = source.substring(7);
88 }
89 else {
90 folder = source;
91 }
92 // Compile the environment first
93 let environ = await this.compile(source);
94 if (!environ)
95 throw new Error('Environment not created');
96 if (!environ.name)
97 throw new Error('Environment does not have a name');
98 // Execute the environment's image (which is built in compile())
99 const executor = new DockerExecutor_1.default();
100 return executor.execute(environ.name, folder, command);
101 }
102 /**
103 * Find out who contributed to the packages that your project
104 * depends upon.
105 *
106 * @param folder The project to examine
107 * @param maxDepth The maximum dependency recursion depth
108 */
109 async who(folder, maxDepth = 100) {
110 let environ = await this.compile(folder, false);
111 if (!environ)
112 throw new Error('Environment not created');
113 const people = {};
114 /**
115 * Get the people for a software package
116 *
117 * @param pkg The package
118 * @param depth The current recursion depth
119 */
120 function get(pkg, depth = 0) {
121 let all = pkg.authors.concat(pkg.contributors).concat(pkg.creators);
122 for (let person of all) {
123 const name = person.name;
124 if (people[name]) {
125 if (!people[name].includes(pkg.name))
126 people[name].push(pkg.name);
127 }
128 else {
129 people[name] = [pkg.name];
130 }
131 }
132 // Keep going deeper, if we haven't yet reached the maximum depth
133 if (depth < maxDepth) {
134 for (let req of pkg.softwareRequirements) {
135 get(req, depth + 1);
136 }
137 }
138 }
139 get(environ);
140 return people;
141 }
142}
143exports.default = DockerCompiler;