UNPKG

4.55 kBPlain TextView Raw
1import { SoftwareEnvironment } from '@stencila/schema'
2
3import Generator from './Generator'
4import generators from './generators'
5import IUrlFetcher from './IUrlFetcher'
6
7const PREFERRED_UBUNTU_VERSION = '18.04'
8
9/**
10 * Compare semantic version numbers
11 *
12 * @param versionOne
13 * @param versionTwo
14 */
15function versionCompare (versionOne: string, versionTwo: string) {
16 if (versionOne === versionTwo) {
17 return 0 // shortcut
18 }
19
20 let splitV1 = versionOne.split('.')
21 let splitV2 = versionTwo.split('.')
22
23 while (splitV1.length < splitV2.length) {
24 splitV1.push('0')
25 }
26
27 while (splitV2.length < splitV1.length) {
28 splitV2.push('0')
29 }
30
31 for (let i = 0; i < splitV1.length; i) {
32 let component1 = parseInt(splitV1[i], 10)
33 let component2 = parseInt(splitV2[i], 10)
34
35 if (component1 < component2) {
36 return -1
37 } else if (component1 > component2) {
38 return 1
39 }
40 }
41
42 return 0 // all components equal
43}
44
45/**
46 * A Dockerfile generator that collects instructions from
47 * all the other generators to allow for images that support
48 * multiple languages.
49 */
50export default class DockerGenerator extends Generator {
51
52 /**
53 * The software environment for which a Dockerfile
54 * will be generated
55 */
56 environ: SoftwareEnvironment
57
58 /**
59 * The child generators from which this 'super' generator
60 * collects instructions.
61 */
62 protected generators: Array<Generator>
63
64 constructor (urlFetcher: IUrlFetcher, environ: SoftwareEnvironment, folder?: string) {
65 super(urlFetcher, folder)
66 this.environ = environ
67
68 // Each of the environment's `softwareRequirements` is
69 // matched to one of the language specific generators
70 // (the first that says that it `applies`)
71 this.generators = []
72 for (let pkg of this.environ.softwareRequirements) {
73 for (let GeneratorClass of generators) {
74 // @ts-ignore
75 const generator = new GeneratorClass(urlFetcher, pkg, folder)
76 if (generator.applies()) {
77 this.generators.push(generator)
78 break
79 }
80 }
81 }
82
83 }
84
85 /**
86 * Collect arrays of string from each child generator
87 * and flatten them into an array of strings.
88 * Used below for method overrides.
89 *
90 * @param func The child generator method to call
91 */
92 private collect (func: any): Array<any> {
93 // @ts-ignore
94 return this.generators.map(func).reduce((memo, items) => (memo.concat(items)), [])
95 }
96
97 /**
98 * Join strings from each child generator
99 *
100 * @param func The child generator method to call
101 */
102 private join (func: any, sep: string = ' \\\n && '): string {
103 // @ts-ignore
104 return this.generators.map(func).filter(cmd => cmd).join(sep)
105 }
106
107 // Methods that override those in `Generator`
108
109 applies (): boolean {
110 return true
111 }
112
113 baseVersion (): string {
114 return [PREFERRED_UBUNTU_VERSION].concat(
115 this.generators.filter(generator => generator.baseName() === this.baseName()) // filter to generators with matching base name
116 .map(generator => generator.baseVersion()))
117 .sort(versionCompare)[0]
118 }
119
120 envVars (sysVersion: string): Array<[string, string]> {
121 return this.collect((generator: Generator) => generator.envVars(sysVersion))
122 }
123
124 aptKeysCommand (sysVersion: string): string | undefined {
125 return this.join((generator: Generator) => generator.aptKeysCommand(sysVersion))
126 }
127
128 aptRepos (sysVersion: string): Array<string> {
129 return this.collect((generator: Generator) => generator.aptRepos(sysVersion))
130 }
131
132 aptPackages (sysVersion: string): Array<string> {
133 // Get the set of unique apt packages requested by each child generator
134 const pkgs = this.collect((generator: Generator) => generator.aptPackages(sysVersion)).sort()
135 return Array.from(new Set(pkgs))
136 }
137
138 stencilaInstall (sysVersion: string): string | undefined {
139 return this.join((generator: Generator) => generator.stencilaInstall(sysVersion))
140 }
141
142 installFiles (sysVersion: string): Array<[string, string]> {
143 return this.collect((generator: Generator) => generator.installFiles(sysVersion))
144 }
145
146 installCommand (sysVersion: string): string | undefined {
147 return this.join((generator: Generator) => generator.installCommand(sysVersion))
148 }
149
150 projectFiles (sysVersion: string): Array<[string, string]> {
151 return this.collect((generator: Generator) => generator.projectFiles(sysVersion))
152 }
153
154 runCommand (sysVersion: string): string | undefined {
155 return this.join((generator: Generator) => generator.runCommand(sysVersion))
156 }
157}