UNPKG

4.61 kBPlain TextView Raw
1import { SoftwareEnvironment, Person } from '@stencila/schema'
2import parser from 'docker-file-parser'
3
4import Doer from './Doer'
5
6/**
7 * Parser for Dockerfiles
8 *
9 * This class implements Dockerfile parsing. It extracts meta-data defined in a Dockerfile using
10 * the [`LABEL`](https://docs.docker.com/engine/reference/builder/#label) or
11 * deprecated [`MAINTAINER`](https://docs.docker.com/engine/reference/builder/#maintainer-deprecated) instructions.
12 * Unlike the other parsers in Dockter it does not attempt to parse out dependencies.
13 *
14 * Here "label" refers to a key in a LABEL instruction that is un-prefixed
15 * or has either the [`org.opencontainers.image`](https://github.com/opencontainers/image-spec/blob/master/annotations.md) prefix,
16 * or the deprecated [`org.label-schema`](https://github.com/label-schema/label-schema.org) prefix.
17 * In other words, the following are all equivalent:
18 *
19 * ```Dockerfile
20 * LABEL version = 1.2.0
21 * LABEL org.opencontainers.image.version = 1.2.0
22 * LABEL org.label-schema.version = 1.2.0
23 * ```
24 *
25 * The following [schema crosswalk](https://en.wikipedia.org/wiki/Schema_crosswalk) defines how labels in
26 * Dockerfiles are translated into JSON-LD properties
27 *
28 * | Label | Property (`context:type.property`)
29 * | --- | ----
30 * | `authors` | `schema:CreativeWork.author`
31 * | `build` |
32 * | `created` | `schema:SoftwareSourceCode.dateCreated`
33 * | `description` | `schema:Thing.description`
34 * | `documentation` | `schema:softwareHelp`
35 * | `licenses` | `schema:CreativeWork.license`
36 * | `maintainer` | `codemeta:SoftwareSourceCode.maintainer`
37 * | `ref-name` |
38 * | `revision` |
39 * | `schema-version` | `schema:schemaVersion`
40 * | `source` | `schema:SoftwareSourceCode.codeRepository`
41 * | `title` | `schema:Thing.name`
42 * | `url` | `schema:Thing.url`
43 * | `vendor` | `schema:Organization.legalName`
44 * | `version` | `schema:SoftwareApplication.softwareVersion`
45 *
46 */
47
48export default class DockerParser extends Doer {
49
50 /**
51 * Parse a folder by detecting any Dockerfile
52 * and return a `SoftwareEnvironment` instance
53 */
54 async parse (content?: string): Promise<SoftwareEnvironment | null> {
55
56 let dockerfile: string
57 if (content) {
58 dockerfile = content
59 } else {
60 if (!this.exists('Dockerfile')) return null
61 dockerfile = this.read('Dockerfile')
62 }
63
64 const environ = new SoftwareEnvironment()
65
66 // Parse instructions from the Dockerfile
67 const instructions = parser.parse(dockerfile)
68
69 // Process LABEL instructions
70 for (let instruction of instructions.filter(instruction => instruction.name === 'LABEL')) {
71 for (let [key, value] of Object.entries(instruction.args)) {
72 // Remove recognised prefixes from key
73 const match = key.match(/^(org\.opencontainers\.image|org\.label-schema)\.([^ ]+)$/)
74 if (match) key = match[2]
75
76 // Unquote value if necessary
77 if (value.startsWith('"')) value = value.substring(1)
78 if (value.endsWith('"')) value = value.slice(0, -1)
79 // Unescape spaces
80 value = value.replace(/\\ /, ' ')
81
82 switch (key) {
83 case 'name':
84 environ.name = value
85 break
86 case 'description':
87 environ.description = value
88 break
89 case 'maintainer':
90 case 'author':
91 environ.authors.push(Person.fromText(value))
92 break
93 }
94 }
95 }
96
97 // Process MAINTAINER instructions
98 for (let instruction of instructions.filter(instruction => instruction.name === 'MAINTAINER')) {
99 let author = ''
100 if (typeof instruction.args === 'string') author = instruction.args
101 else throw new Error(`Unexpected type of instruction arguments ${typeof instruction.args}`)
102 environ.authors.push(Person.fromText(author))
103 }
104
105 return environ
106 }
107
108}