-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathloadDockerfile.js
More file actions
100 lines (84 loc) · 3.11 KB
/
Copy pathloadDockerfile.js
File metadata and controls
100 lines (84 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const parseDockerfile = require("../lib/parseDockerfile")
const IncludeCycleError = require("../errors/IncludeCycleError")
const IncludeDepthExceededError = require("../errors/IncludeDepthExceededError")
const { DEFAULT_MAX_INCLUDE_DEPTH } = require("./limits")
const postProcessDockerfile = require("./postProcessDockerfile")
module.exports = loadDockerfile // placed here to fix circular dependencies
const instructionFactory = require("../instruction") // placed here to fix circular dependencies
// `isRootInclude` is set by the INCLUDE handler when an INCLUDE appears at
// nesting level 0; FROM/COPY-from handlers deliberately do NOT set it. The
// flag is consumed by postProcessDockerfile to decide:
// - whether to scope stage names per-file (off for the inlined INCLUDE body
// so an INCLUDE inlines verbatim, on for FROM-included content so its
// stages live in their own namespace), and
// - whether to emit a trailing alias on the last FROM (off for INCLUDEd
// content because the parent's FROM rewrite owns the alias).
// The asymmetry is what makes INCLUDE inline-paste while FROM/COPY-from
// pull a *referenced* stage.
async function loadDockerfile(source, fileContext = {}) {
const {
parentStageTarget = null,
parentStageAlias = null,
nestingLevel = 0,
dockerContext,
scope = [],
includeChain = [],
maxIncludeDepth = DEFAULT_MAX_INCLUDE_DEPTH,
isRootInclude,
} = fileContext
if (nestingLevel > maxIncludeDepth) {
throw new IncludeDepthExceededError(
nestingLevel,
maxIncludeDepth,
includeChain,
)
}
// Resolve remote identity (oid/digest) eagerly so the cycle key reflects
// the resolved commit/digest even for top-level references — a moving
// `main` or `:latest` tag still pins to a stable id for cycle detection.
await source.resolve()
const sourceKey = source.key()
if (includeChain.includes(sourceKey)) {
throw new IncludeCycleError(sourceKey, includeChain)
}
const content = await source.read()
const relativeFilePath = source.displayPath(dockerContext)
scope.push(relativeFilePath)
const nextIncludeChain = [...includeChain, sourceKey]
const isRootFile = nestingLevel === 0
const filePath = source.fsPath()
const processingContext = {
...fileContext,
scope,
includeChain: nextIncludeChain,
parentSource: source,
filePath,
relativeFilePath,
isRootFile,
maxIncludeDepth,
}
const instructionProcessors = instructionFactory(processingContext)
const instructions = parseDockerfile(content, {
removeSyntaxComments: !isRootFile,
})
const lines = []
for (const instruction of instructions) {
const processor =
instructionProcessors[instruction.name] || instructionProcessors._DEFAULT
const instructionLines = await processor(instruction, lines)
if (instructionLines) {
lines.push(...instructionLines)
}
}
let result = lines.join("\n")
result = postProcessDockerfile(result, {
stageTarget: parentStageTarget,
stageAlias: parentStageAlias,
filePath,
isRootFile,
isRootInclude,
scope,
relativeFilePath,
})
return result
}