How to compile swift-format in Docker with latest ubuntu?

I am getting this toward the end of the logs of installing swift-format:

#73 70.09 [41/45] Compiling ArgumentParserToolInfo ToolInfo.swift
#73 134.7 [43/47] Compiling ArgumentParser BashCompletionsGenerator.swift
#73 140.9 [45/48] Compiling Markdown ChildIndexPath.swift
#73 1108.5 [47/49] Compiling SwiftSyntax AbsolutePosition.swift
#73 1119.1 [49/53] Compiling SwiftBasicFormat BasicFormat.swift
#73 1125.5 [51/54] Compiling SwiftDiagnostics Convenience.swift
#73 1266.7 [53/55] Compiling SwiftParser Attributes.swift
#73 1283.3 [55/58] Compiling SwiftOperators Operator.swift
#73 1329.1 [57/59] Compiling SwiftParserDiagnostics DiagnosticExtensions.swift
#73 1433.5 [59/61] Compiling SwiftFormat Configuration+Default.swift
#73 1434.8 [61/66] Compiling SwiftFormatConfiguration Compatibility.swift
#73 1441.0 [63/67] Compiling _SwiftFormatTestSupport Configuration+Testing.swift
#73 1445.7 [65/68] Compiling generate_pipeline FileGenerator.swift
#73 1448.5 [67/69] Compiling swift_format ConfigurationLoader.swift
#73 1448.6 [67/70] Linking generate-pipeline
#73 1451.0 [69/70] Linking swift-format
#73 1451.0 Build complete! (1447.68s)
#73 DONE 1451.1s

#75 [70/70] RUN swift-format -v
#75 0.228 /bin/sh: line 1: swift-format: command not found
#75 ERROR: process "/bin/sh -c swift-format -v" did not complete successfully: exit code: 127

The Dockerfile commands I have are:

RUN git clone https://github.com/apple/swift-format.git
RUN cd swift-format && git checkout "tags/509.0.0" && swift build -c release
RUN swift-format -v

Now, swift -v works, and I tested swiftc -emit-assembly my.swift and that works in Docker.

Now I also tried installing swiftformat (without the dash), but get a similar error:

#69 [66/75] RUN cd SwiftFormat && swift build -c release
#69 CACHED

#70 [internal] load build context
#70 transferring context: 336B done
#70 DONE 0.0s

#71 [67/75] RUN cd SwiftFormat && find . -name "swiftformat"
#71 0.142 ./CommandLineTool/swiftformat
#71 0.142 ./.build/x86_64-unknown-linux-gnu/release/swiftformat
#71 DONE 0.1s

#72 [68/75] RUN alias swiftformat="/usr/local/bin/swiftformat"
#72 DONE 0.1s

#73 [69/75] RUN swiftformat data/example.swift
#73 0.207 /bin/sh: line 1: swiftformat: command not found
#73 ERROR: process "/bin/sh -c swiftformat data/example.swift" did not complete successfully: exit code: 127
------
> [69/75] RUN swiftformat data/example.swift:
0.207 /bin/sh: line 1: swiftformat: command not found
------
Dockerfile.swift:154
--------------------
152 |     RUN alias swiftformat="/usr/local/bin/swiftformat"
153 |     # RUN swiftformat --output
154 | >>> RUN swiftformat data/example.swift
155 |     # https://github.com/nicklockwood/SwiftFormat?tab=readme-ov-file#config-file

How do I compile these CLI tools so they work in Docker basically, any ideas?

This was my swiftformat build command:

RUN git clone https://github.com/nicklockwood/SwiftFormat
RUN cd SwiftFormat && swift build -c release
RUN cd SwiftFormat && ln -s $(pwd)/CommandLineTool/swiftformat /usr/bin/swiftformat

But the binary, I don't know where that is, or how to reference it once it's built.

My dockerfile begins with:

FROM --platform=linux/amd64 amd64/ubuntu:noble

Here is the full Dockerfile.

You can get a path to your executable binary by running this command in the root directory of the package containing the executable target:

swift build --show-bin-path

If the binary was built in release, then the command should look like this:

swift build --show-bin-path -c release

This is the reason your container can't find the binary. It's in that build folder and none of the PATH folders, until you explicitly copy it to those or add the build folder path to the PATH list.

1 Like

Ok interesting. I tried these but still getting swift-format command not found:

RUN git clone https://github.com/apple/swift-format.git
RUN cd swift-format && git checkout "tags/509.0.0" && swift build -c release
RUN ln -s $(swift build --show-bin-path -c release) /usr/bin/swift-format
RUN echo $(swift build --show-bin-path -c release)
RUN echo $(swift build --show-bin-path -c release)
RUN ls $(swift build --show-bin-path -c release)
RUN /usr/bin/swift-format -v

Do I need to invoke it in a differnet context? It is saying:

RUN ls $(swift build --show-bin-path -c release):
cannot access '/.build/x86_64-unknown-linux-gnu/release': No such file or directory

What are the specific commands I should run do you suggest?

Every RUN directive in Dockerfile runs as a separate shell invocation, so cd swift-format command you run on line 2 has no effect on subsequent RUN directives. You either have to run cd swift-format on every line that needs to run swift build, or add a corresponding WORKDIR directive for the current working directory change to persist.

I was only able to get it to work like this, the commented-out line doesn't work.

RUN git clone https://github.com/apple/swift-format.git
RUN cd swift-format && git checkout "tags/509.0.0" && swift build -c release
# RUN ls -la /usr/bin
# RUN ls -s $(cd swift-format && swift build --show-bin-path -c release)/swift-format /usr/bin/swift-format
RUN ln -s /swift-format/.build/x86_64-unknown-linux-gnu/release/swift-format /usr/bin/swift-format
RUN swift-format -v

Can it be cleaned up?

If you're not going to use the cloned repository in subsequent steps, why not just copy the binary to where you need it instead of creating a symlink? Then you can freely remove the cloned repository at the end of the build, so that swift-format sources aren't included in your final Docker image. Additionally, you'd want to copy it to /usr/local/bin, since /usr/bin is usually reserved for executables installed by system package managers.

1 Like