Skip to content

Handle file paths base on target platform#3908

Merged
tonistiigi merged 12 commits intomoby:masterfrom
gabriel-samfira:handle-platform-file-paths
Jul 10, 2023
Merged

Handle file paths base on target platform#3908
tonistiigi merged 12 commits intomoby:masterfrom
gabriel-samfira:handle-platform-file-paths

Conversation

@gabriel-samfira
Copy link
Copy Markdown
Collaborator

This change properly handles paths on different platforms. In short, this change checks the target platform we're building an image for and applies normalization steps to make sure the file paths are valid. This makes buildkit properly handle paths on both *nix systems and on Windows.

Depends on:

Replaces:

Note: This branch will fail to build until dependencies are merged. Leaving the old branch up, as it contains a longer discussion related to the changes in these 3 PRs.

Here is a test run with all 3 branches merged: https://github.com/gabriel-samfira/buildkit/actions/runs/5091195907

CC: @crazy-max @jedevc

@gabriel-samfira
Copy link
Copy Markdown
Collaborator Author

Rebased, now that the dependencies have been merged. This should now be ready for review.

Comment thread client/llb/fileop.go Outdated
Comment thread client/llb/fileop.go Outdated
Comment thread frontend/dockerfile/dockerfile2llb/convert.go Outdated
Comment thread solver/llbsolver/file/backend.go Outdated
mws := mountWithSession(mountable, g)
dest := m.Dest
if !filepath.IsAbs(filepath.Clean(dest)) {
if !system.IsAbs(filepath.Clean(dest), platform) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path is coming from LLB. How is it not already normalized?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is also called from NewContainer(). I can't remember for sure why I needed this here (first PR was proposed in November), but I can track it down and give you a more detailed answer.

On the other hand, I think that whenever we are dealing with paths that may be meant for a different OS than the one the code is running on, we should use the helper functions in util/system.

@gabriel-samfira
Copy link
Copy Markdown
Collaborator Author

@tonistiigi kind reminder. I would love to unblock the rest of the PRs. The executor work depends on this PR.

Comment thread client/llb/state.go Outdated
if c.Platform == nil {
c.Platform = &ocispecs.Platform{
OS: "linux",
Architecture: "amd64",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the architecture in here used anywhere? If not then I would prefer if the nil case is handled inside FileOp for OS only and it is clear that this only controls the path conversions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the Architecture.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I meant was to handle nil platform inside FileOp. If the logic is only based on OS then we shouldn't control it by passing full platform (or passing an invalid partial platform).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. Misread what you meant.

if d.stage.BaseName == emptyImageName {
d.state = llb.Scratch()
d.image = emptyImage(platformOpt.targetPlatform)
d.platform = &platformOpt.targetPlatform
Copy link
Copy Markdown
Member

@tonistiigi tonistiigi Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this can be nil pointer dereference. In that nil case we should use DefaultSpec

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am reading the code correctly, the buildPlatforms field defaults to DefaultSpec if it's not set via ConvertOpt and targetPlatform is set to &buildPlatforms[0] if it's nil, before returning.

platformOpt seems to be set at the beginning of this function using buildPlatformOpt() which always seems to return a non-nil instance of the platformOpt type.

Would you prefer I add a nil pointer check here, in case buildPlatformOpt() changes at some point?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I read it wrong. This is not even a pointer, so it can't be nil.

a = a.Copy(st, f, dest, opts...)
}
} else {
src, err = system.NormalizePath("/", src, d.platform.OS, false)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still confused why are doing these path transformations twice. If we already are always converting paths to UNIX in Dockerfile before passing to the LLB then why are we still carrying OS value in LLB and doing extra conversions there.

Copy link
Copy Markdown
Collaborator Author

@gabriel-samfira gabriel-samfira Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can remove the calls to NormalizePath() from client/llb and just use the paths as they come in, if you wish.

The current code in the master branch calls normalizePath(). This code is now incorporated into system.NormalizePath(), with additional logic to take into account the input platform.

Would you prefer we do away with this and just use path.Join() in toProtoAction() (example: https://github.com/moby/buildkit/blob/master/client/llb/fileop.go#L340) ?

It's fine with me, either way 😄

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, in the client I can just hardcode "linux" as the platform sent into NormalizePath() and it would behave just like the current normalizePath() in client/llb, but I am not sure ignoring the input platform (if set) is worth it. In any case, let me know what you prefer and I will make the change.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't need NormalizePath calls inside client/llb to make windows work then better to remove it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can revert the change to that file and bring back normalizePath() as it is in the master branch, because that is somewhat still needed. Although that code is now incorporated in system.NormalizePath().

Will change in the morning. I need to see if anything breaks (with a clear head).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted most of the changes to the client. Please take another look.

@gabriel-samfira gabriel-samfira force-pushed the handle-platform-file-paths branch from 5d2cdce to b7985be Compare June 27, 2023 20:14
@tonistiigi tonistiigi added this to the v0.12.0 milestone Jun 29, 2023
This change properly handles paths on different platforms. In short, this
change checks the target platform we're building an image for and applies
normalization steps to make sure the file paths are valid. This makes buildkit
properly handle paths on both *nix systems and on Windows.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
 * Set default platform for scratch images
 * Set default platform constraint for FileOps if none is set via
   ConstraintOpt.
 * Explicitly set platform ConstraintOpt in dockerfile frontend based
   on dispatch state platform.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
In dockerfile2llb we ensure we use proper path separators before we send
them to LLB.

In LLB we default to linux/amd64 if no constraints are set by the
caller.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
@gabriel-samfira gabriel-samfira force-pushed the handle-platform-file-paths branch from 7022827 to 1045713 Compare July 3, 2023 15:12
When running on Linux, filepath.ToSlash() is not suitable to convert paths
containing Windows path delimiter to Unix delimiters. To enable this, we
export system.ToSlash() that takes a platform flag, based on which we use
the proper file path separator, regardless of the platform we run on.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
@gabriel-samfira gabriel-samfira force-pushed the handle-platform-file-paths branch from 1045713 to 69f2c06 Compare July 3, 2023 15:30
wd := c.Path
if !path.IsAbs(c.Path) {
wd = path.Join("/", d.image.Config.WorkingDir, wd)
wd, err := system.NormalizeWorkdir(d.image.Config.WorkingDir, c.Path, d.platform.OS)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: Naming is confusing here NormalizeWorkdir returns OS-specific paths and NormalizePath Unix-only paths. "Normalize" should mean the same thing.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am terrible at naming things, and can't really think of a better name right now. I did make sure that the doc string for the function does state explicitly that for Windows, we convert path delimiter with \. If it's alright with you, I'd like to revisit the name at a later time. Or if you have any suggestions for a better name, I'll gladly change it.

Comment thread util/system/path.go Outdated
Comment thread frontend/dockerfile/dockerfile2llb/convert.go Outdated
Comment thread frontend/dockerfile/dockerfile2llb/convert.go Outdated
Comment thread frontend/dockerfile/dockerfile2llb/convert.go Outdated
Comment thread solver/llbsolver/file/backend.go Outdated
Comment thread client/llb/fileop.go Outdated
Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
@gabriel-samfira gabriel-samfira force-pushed the handle-platform-file-paths branch from b829c52 to f1657ec Compare July 10, 2023 19:58
@tonistiigi tonistiigi merged commit 595bfa2 into moby:master Jul 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants