UNPKG

2.59 kBPlain TextView Raw
1import { DockerfileParser } from "dockerfile-ast";
2import { EOL } from "os";
3import { getDockerfileBaseImageName } from "./instruction-parser";
4import {
5 UpdateDockerfileBaseImageNameErrorCode,
6 UpdateDockerfileBaseImageNameResult,
7} from "./types";
8
9export { updateDockerfileBaseImageName };
10
11/**
12 * Updates the image name of the last from stage, after resolving all aliases
13 * @param contents Contents of the Dockerfile to update
14 * @param newBaseImageName New base image name Dockerfile contents should be updated to
15 */
16function updateDockerfileBaseImageName(
17 contents: string,
18 newBaseImageName: string,
19): UpdateDockerfileBaseImageNameResult {
20 const dockerfile = DockerfileParser.parse(contents);
21
22 const result = getDockerfileBaseImageName(dockerfile);
23
24 if (result.error) {
25 return {
26 contents,
27 error: {
28 code: UpdateDockerfileBaseImageNameErrorCode.BASE_IMAGE_NAME_NOT_FOUND,
29 },
30 };
31 }
32
33 const currentBaseImageName = result.baseImage;
34
35 const fromRanges = dockerfile
36 .getFROMs()
37 .filter((from) => from.getImage() === currentBaseImageName)
38 .map((from) => from.getImageRange()!);
39
40 const argRanges = dockerfile
41 .getARGs()
42 .filter((arg) => arg.getProperty()?.getValue() === currentBaseImageName)
43 .map((arg) => arg.getProperty()?.getValueRange()!);
44
45 const ranges = fromRanges.concat(argRanges);
46
47 if (ranges.length === 0) {
48 /**
49 * This happens when the image is split over multiple FROM and ARG statements
50 * making it difficult to update Dockerfiles that fall into these edge cases.
51 * e.g.:
52 * ARG REPO=repo
53 * ARG TAG=tag
54 * FROM ${REPO}:${TAG}
55 */
56 return {
57 contents,
58 error: {
59 code: UpdateDockerfileBaseImageNameErrorCode.BASE_IMAGE_NAME_FRAGMENTED,
60 },
61 };
62 }
63
64 const lines = contents.split(EOL);
65
66 for (const range of ranges) {
67 const lineNumber = range.start.line;
68 const start = range.start.character;
69 const end = range.end.character;
70
71 const content = lines[lineNumber];
72 const updated =
73 content.substring(0, start) + newBaseImageName + content.substring(end);
74 lines[lineNumber] = updated;
75 }
76
77 const updatedContents = lines.join(EOL);
78 const updatedDockerfile = DockerfileParser.parse(updatedContents);
79
80 if (
81 dockerfile.getInstructions().length !==
82 updatedDockerfile.getInstructions().length
83 ) {
84 return {
85 contents,
86 error: {
87 code: UpdateDockerfileBaseImageNameErrorCode.DOCKERFILE_GENERATION_FAILED,
88 },
89 };
90 }
91
92 return {
93 contents: updatedContents,
94 };
95}