Skip to content

Line continuation overhaul

Compare
Choose a tag to compare
@timothyb89 timothyb89 released this 30 Oct 23:51
· 10 commits to master since this release
ab6b845

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 for CmdInstruction and EntrypointInstruction; similarly supports .as_shell())
  • RunInstruction::into_exec() -> Option<Vec<String>>: as above, but for Exec form