Line continuation overhaul
Summary of breaking changes
This release changes a number of API datatypes from simple String
values to use a new BreakableString
wrapper type. The Display
implementation should provide equivalent functionality in most cases, except where previous parsed values were technically incorrect (e.g. improperly including comments).
If necessary, simply call .to_string()
on any BreakableString
value:
let dockerfile = Dockerfile::parse(indoc!(r#"
FROM alpine
RUN apk add --no-cache \
curl
"#)?;
assert_eq!(
&dockerfile.instructions[1]
.as_run().unwrap()
.as_shell().unwrap()
.to_string(),
"apk add --no-cache curl"
);
Comments and spans for individual text segments of any BreakableString
value are available in BreakableString.components
.
Details
This release improves parsing of line continuations and adds support for embedded comments and empty lines in all positions that support line continuations, for example:
RUN foo && \
# test comment
bar && \
baz
CMD [ \
# comment
"foo" \
"bar" \
]
ENV \
foo=a \
# comment
bar=b \
# empty lines too
baz=c
COPY \
--from=foo \
# comment
/src \
/dest
Previously, comments were included inline with actual content in the parse result, if they parsed properly at all (empty lines, multiple unescaped comments, and other situations were not considered valid). Docker strips these comments at runtime so they aren't part of the embedded bash script, but simply stripping these out could make it challenging to modify values while preserving user comments.
Where these continuation-friendly values are directly exposed (e.g. RUN
, CMD
, ENTRYPOINT
, ENV
), plain String
values have been replaced with BreakableString
, a new wrapper type that splits and categorizes all text segments in a broken string along with their text spans. The type's Display
implementation omits comments and line continuations to produce a single, joined line that should match what Docker actually executes in, for example, a shell-style RUN
instruction.
Additionally, new conversion helper functions have been added to various enum types, particularly Instruction
and the various RUN
-like instructions:
Instruction::into_run() -> Option<RunInstruction>
: consumes the instruction and attempts to convert it to its inner value (repeated for all other instruction types; also,as_*
for references)RunInstruction::into_shell() -> Option<BreakableString>
: consumes the instruction and returns a breakable string if it's a Shell instruction (repeated forCmdInstruction
andEntrypointInstruction
; similarly supports.as_shell()
)RunInstruction::into_exec() -> Option<Vec<String>>
: as above, but for Exec form