-
Notifications
You must be signed in to change notification settings - Fork 558
Comparing changes
Open a pull request
base repository: openrewrite/rewrite
base: main
head repository: openrewrite/rewrite
compare: tim/docker-arg-quoted-values
- 11 commits
- 19 files changed
- 1 contributor
Commits on Aug 21, 2026
-
Docker: model quoted values and
$VARrefs for ARG, ENV, WORKDIR, LABEL`DockerParserVisitor` had two ways of building a `Docker.Argument`. One walked tokens, stripping quotes into `Literal.quoteStyle` and splitting `$VAR` out into `Docker.EnvironmentVariable`. The other took the raw source substring into a single `Literal` with `quoteStyle = null`, and was used by ARG, ENV, WORKDIR, STOPSIGNAL and MAINTAINER. So `ARG A="x"` produced `Literal(text="\"x\"", quoteStyle=null)`, forcing recipes to match the quotes by hand, and `ARG A=$BASE` produced a plain `Literal("$BASE")` — meaning `hasEnvironmentVariables()` was false for every ARG and ENV, and `extractText()` returned `"$BASE"` as though it were a statically known value. Route all five through the token-walking path and delete the raw one. `Docker.Literal` already modelled quote style, and the printer already re-emitted quotes from it, so printing is unaffected. Separately, the `labelValue` grammar rule accepted a single token and omitted `ENV_VAR`, so `LABEL L=$VAL` failed the `labelKey EQUALS labelValue` alternative and silently fell through to the old-format branch, yielding `hasEquals=false` and a value of `["=", $VAL]`. Model it as `labelValueElement+` mirroring `envTextEquals`, excluding EQUALS so that `LABEL a=1 b=$X c=3` still splits into three pairs. Add public `getText()`, `getTextWithVariables()`, `getQuoteStyle()` and `hasEnvironmentVariables()` to `Docker.Argument`. Equivalent helpers existed on the package-private `DockerTraitMatcher`, out of reach of recipe authors, and an argument can hold several contents (`a"b"c`), so reading `getContents().get(0)` was already wrong. Those helpers now delegate, leaving one implementation. Verified round-trip printing is byte-identical across 142 real Dockerfiles, matching the pre-change baseline exactly.Configuration menu - View commit details
-
Copy full SHA for dd427f9 - Browse repository at this point
Copy the full SHA dd427f9View commit details -
Configuration menu - View commit details
-
Copy full SHA for a4991f4 - Browse repository at this point
Copy the full SHA a4991f4View commit details -
Configuration menu - View commit details
-
Copy full SHA for 75e7715 - Browse repository at this point
Copy the full SHA 75e7715View commit details -
Configuration menu - View commit details
-
Copy full SHA for 628588d - Browse repository at this point
Copy the full SHA 628588dView commit details -
Configuration menu - View commit details
-
Copy full SHA for 86eba51 - Browse repository at this point
Copy the full SHA 86eba51View commit details -
Configuration menu - View commit details
-
Copy full SHA for 2cbc401 - Browse repository at this point
Copy the full SHA 2cbc401View commit details -
Treat flag-shaped argument values as text
Flags are options to commands. A value beginning with "--" inside an ARG, WORKDIR or MAINTAINER is not a flag, but the lexer emits `--name=value` as a single FLAG token wherever it appears, so such a value reached the model as one raw literal: `ARG X=--flag="a b"` kept its quotes, and `--flag=$VAR` never yielded an EnvironmentVariable. Decompose those tokens as text. `=` keeps its key/value meaning only where a command's flag value gives it one, so the caller passes that in.
Configuration menu - View commit details
-
Copy full SHA for 45669e9 - Browse repository at this point
Copy the full SHA 45669e9View commit details -
Keep a value whole rather than splitting it into parts
A value is one literal holding its source text, so a value spanning whitespace stays whole: `LABEL author "John Doe" of ACME` is a single literal rather than three, and `ARG X=--flag="a b"` is not taken apart as though it were an option to a command. Quote style is recorded only when the entire value is one quoted token, as in `ARG X="a b"`. Where only part of a value is quoted the quotes belong to its text, so getText() returns them. Environment variable references are still split out, since their value cannot be resolved from the source. This drops the fast path that produced the same single literal whenever a value happened to contain no quote, variable or comment; the general case now does that for every value.
Configuration menu - View commit details
-
Copy full SHA for 823b78c - Browse repository at this point
Copy the full SHA 823b78cView commit details -
Split variable references out of a value's text, not its tokens
Splitting on ENV_VAR tokens made the lexer's boundaries decide what counts as a variable, and it emits `--name=value` as a single token: the reference in `ARG X=--flag=$VAR` sat inside one and went unmodelled, while the one in `ARG X=${BASE}-suffix` did not. A value that reads as a literal `--flag=` followed by a variable should be modelled that way. Scan the value's text instead, which drops the token special case entirely. What counts as a reference follows the lexer's own ENV_VAR and SPECIAL_VAR rules, so `${BASE:-def}` keeps its default, and `$$`, `$1` and lowercase `$var` remain text. Quoting is unaffected: a wholly quoted value still records its style, and a partly quoted one still keeps its quotes as text.Configuration menu - View commit details
-
Copy full SHA for d097b85 - Browse repository at this point
Copy the full SHA d097b85View commit details -
Split variable references out of double-quoted values
`ENV PATH="/opt/venv/bin:$PATH"` is among the most common lines in a Dockerfile, and its reference went unmodelled: a wholly quoted value became one literal, so hasEnvironmentVariables() was false and getText() offered the text as though it were static. Across 142 real Dockerfiles this covered 22 of them, and modelling it lifts the references found from 58 to 112. A quoted value holding a reference is no longer one literal, so by the rule already in place its quotes become part of its text: ARG X="pre $V post" -> L<"pre > V<V> L< post"> Only double quotes expand. Single quotes are literal in the shell and in Docker's own parser, so `'pre $V post'` stays whole, as does an escaped `\$`. The scan tracks single-quoted sections, so a value mixing both kinds of quoting expands only where it should. ImageReferences.tagColonIndex now ignores a colon inside quotes. Without that, `FROM "alpine:${TAG}"` would split at the colon it no longer holds in a single quoted literal, reporting an image name of `"alpine`.Configuration menu - View commit details
-
Copy full SHA for aa25a61 - Browse repository at this point
Copy the full SHA aa25a61View commit details -
Drop the separator handling from Argument's text accessors
Contents used to carry the whitespace between them in their prefixes, so reading a value back had to re-append it. A value is now a single literal holding its source text, which puts that whitespace inside the text: no content the parser produces has a prefix after the first, across all 142 Dockerfiles in the corpus I round-trip against.
Configuration menu - View commit details
-
Copy full SHA for 5c2911c - Browse repository at this point
Copy the full SHA 5c2911cView commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...tim/docker-arg-quoted-values