Conversation
Signed-off-by: Paul Mars <paul.mars@canonical.com>
|
letFunny
left a comment
There was a problem hiding this comment.
First review. I am missing a couple of files but I wanted to publish it as quickly as possible so we have more time to iterate. This is looking great Paul, many things are looking dead simple which is always an extremely good sign. I have written some comments about how to make the PR shorter and how to make it, hopefully, even simpler. Let me know what you think.
I see some of the comments are similar to past discussions we had in upils#1. We spent some effort there, so please make sure all the comments were carried over to this one.
| fileinfo, err := os.Lstat(path) | ||
| if err == nil { | ||
| if fileinfo.IsDir() { | ||
| if fileinfo.Mode() != o.Mode && o.OverrideMode { | ||
| return os.Chmod(path, o.Mode) | ||
| } | ||
| return nil | ||
| } | ||
| err = os.Remove(path) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } else if !os.IsNotExist(err) { | ||
| return err | ||
| } | ||
| return err | ||
| return os.Mkdir(path, o.Mode) |
There was a problem hiding this comment.
A couple of things:
- Prefer early return when possible. In this case it is better to check if os.IsNotExist and fail directly then the rest of the block does not need to be indented.
- It is now a bit wasteful to do
Lstathere followed by another one infsutil.Create. It would be great if we could unify them. - Are we sure we want to remove the path here? This is "breaking compatibility" with the past and it might lead to unexpected deletion in the user side.
- This feels unrelated to the PR. Maybe as a separate PR (this one is 1400+ lines) and you can state a TODO in this one saying we found a bug in the existing code that will be fixed next.
| path := filepath.Clean(filepath.Join(root, relPath)) | ||
| if !strings.HasPrefix(path, root) { | ||
| return "", fmt.Errorf("cannot create path %s outside of root %s", path, root) | ||
| return "", fmt.Errorf("cannot handle path %s outside of root %s", path, root) |
There was a problem hiding this comment.
Why do we need to change the error message? It feels unrelated to the PR.
| } | ||
| } | ||
|
|
||
| mfest, err := slicer.SelectValidManifest(cmd.RootDir, release) |
There was a problem hiding this comment.
In general our philosophy is that we should be able to cut a release from main at any point in time. That is, if we ever do a bug fix we should be able to release a point version. This is changing how Chisel works in folders with a manifest and it is not the correct behavior (yet) so I would prefer if we could gate this functionality over a environmental variable or a debug command or any other mechanism.
| case 0, fs.ModeSymlink: | ||
| err = os.Rename(srcPath, dstPath) | ||
| case fs.ModeDir: | ||
| err = createDir(&CreateOptions{ |
There was a problem hiding this comment.
This is not moving the directory, it is left behind. It is also unexpected when an API is called Move and it moves the directory without its contents.
| Root: o.DstRoot, | ||
| Path: o.Path, | ||
| Mode: o.Mode, | ||
| OverrideMode: o.OverrideMode, |
There was a problem hiding this comment.
This should always be true or else we are not moving anything, it shouldn't be an option of Move.
| summary: "Empty release", | ||
| release: &setup.Release{ | ||
| Packages: map[string]*setup.Package{}, | ||
| }, |
There was a problem hiding this comment.
Let's include expected here to highlight that we should not be getting anything back. As a rule of thumb, every test should always list inputs and outputs that are relevant for the test.
| return err | ||
| } | ||
| if strings.HasSuffix(options.Path, "/") { | ||
| err = syscall.Rmdir(path) |
There was a problem hiding this comment.
Good news! The syscall is not actually needed, when I suggested it I had not realized that os.Remove already does the same thing internally, from documentation: Remove removes the named file or (empty) directory.
| targetDir = filepath.Join(dir, targetDir) | ||
| } | ||
|
|
||
| var originalTargetDir string |
There was a problem hiding this comment.
A different way of doing it is to extract what used to be the Run function into another one and have Run call into that with different target dir and then upgrade (see extract.go for Run vs extractData). Do you think it will be clearer this way?
| } | ||
| } | ||
|
|
||
| // Remove missing paths |
There was a problem hiding this comment.
| // Remove missing paths | |
| // Remove missing paths. |
| err := fsutil.Remove(&fsutil.RemoveOptions{ | ||
| Root: targetDir, | ||
| Path: relPath, | ||
| }) |
There was a problem hiding this comment.
See my other comments in the abstraction and about syscall.Rmdir but I am more convinced now we can call os.Remove directly here. This will also help make the PR shorter.
This commit enables Chisel detecting the target directory contains the result
of a previous execution to then operate an upgrade of the content. This initial
simple implementation has the the limitation that content (files, symlinks) is
systematically replaced, even if identical. As a consequences:
different and thus the new OCI layer contains duplicated files.