Conversation
letFunny
left a comment
There was a problem hiding this comment.
Thanks Paul, this looks very good, only a few minor comments
| const manifestMode fs.FileMode = 0644 | ||
| const ( | ||
| manifestMode fs.FileMode = 0o644 | ||
| rootWorkdir = ".chisel" |
There was a problem hiding this comment.
I think the naming is a bit off here. This is not necessarily a working directory, right now we have only one usage but from the conversation the other day it could evolve into doing more things. It also makes it harder later to differentiate between .chisel and .chisel/<workdir_for_recut>.
There was a problem hiding this comment.
I tried different names and settled on this one because I thought it was in fact a "working directory". As you can see in the rest of the code, the subdirectory holding the new rootfs is not named "workdir" anymore, to avoid confusion.
metadataDir or stateDir are other potential candidates but I am not really convinced they better encompass what could be stored in this directory. Do you have other ideas?
There was a problem hiding this comment.
I have a slight preference for stateDir or something similar yes
| func mkWorkdir(workdir string, mode os.FileMode) (err error) { | ||
| defer func() { | ||
| if err != nil { | ||
| err = fmt.Errorf("cannot create working directory: %w", err) |
There was a problem hiding this comment.
As this is a "helper" function, I did not want to make too many assumptions on how the returned error was used. In the current implementation, you are right that this is not strictly needed because returned errors are immediately returned as is. However, I wanted to keep consistency with other places in this package where most os errors are wrapped.
This is an internal package, so we are the only ones that could depend in the behavior of this API. If/when we start unwrapping errors returned by Run I would prefer having consistency and avoid being surprised that some errors cannot be unwrapped like others.
Do you agree?
There was a problem hiding this comment.
Okay this makes sense, so that the caller could check os.IsExists and the like
This is an internal package, so we are the only ones that could depend in the behavior of this API
In general, the design should not depend too much on whether it is internal or external as the same principles apply. In this case this is dealing with os so it is okay to use %w, in other functions, even if internal, it is not if we don't want to rely on the errors.
internal/slicer/slicer.go
Outdated
| // TODO: Use a predetermined name and reserve it. The release validation | ||
| // would ensure it cannot be used in chisel-releases. | ||
| tmpWorkDir, err := os.MkdirTemp(targetDir, "chisel-workdir-*") | ||
| rootfsPath := filepath.Join(rootWorkdirPath, "rootfs") |
There was a problem hiding this comment.
The naming is a bit weird now, tmpWorkDir indicated this was temporary and a working directory suggesting we will do something to it later to install the files definitely but now rootfsPath loses both connotations.
There was a problem hiding this comment.
See my other comment regarding the "working dir" connotation.
However I was on the fence about the "temporary" aspect of it. I am adding at least this aspect back to the name.
| // The root working directory must only be removed if empty. | ||
| // This call will do so or silently fail. | ||
| os.Remove(rootWorkdirPath) | ||
| }() |
There was a problem hiding this comment.
You can also check for error here and return it from the outer function. This might be worth it if we want to differentiate empty dir vs no permissions, the latter is an error.
There was a problem hiding this comment.
I did that at first, but then I saw that in the whole code base we never deal with returning the error of the outer function and the error of the deferred function. In the vast majority of cases we even ignore the error of whatever is called in the defer. Returning both errors should be done carefully to not hide the error of the outer function and to make sure the user can make sense of the "complete" error displayed.
I do not like that this is creating a blind spot though, so I would like to discuss it with G.
There was a problem hiding this comment.
Just to be clear I meant: if the error is nil but os.Remove fails then we can return the latter. But let's discuss it with G.
letFunny
left a comment
There was a problem hiding this comment.
Thanks Paul, this is almost ready, just a couple of questions.
| }, | ||
| error: `cannot create working directory: existing entry at .*/\.chisel is not a directory`, | ||
| }, { | ||
| summary: "Run keeps non-empty .chisel directory", |
There was a problem hiding this comment.
This might also make it somewhat more flexible for future compatibility. It is a little bit hard to know at this point.
| err := os.Chmod(opts.TargetDir, 0o555) | ||
| c.Assert(err, IsNil) | ||
| }, | ||
| error: `cannot create working directory: mkdir .*/\.chisel: permission denied`, |
| }, | ||
| filesystem: map[string]string{ | ||
| "/.chisel/": "dir 0755", | ||
| "/.chisel/keep": "file 0644 6ca7ea2f", |
There was a problem hiding this comment.
We need to be careful if we ever implement restarts from crashes to use the existence of .chisel to tell us that we can go ahead and resume from a restart. That will break when future versions do not remove this directory.
I am so-so on keeping it or removing it. I see in one of the comments that you state a requirements to not remove it when not empty, can you explain why?
There was a problem hiding this comment.
I am so-so on keeping it or removing it. I see in one of the comments that you state a requirements to not remove it when not empty, can you explain why?
That was the agreement with Gustavo. This directory might be used in the future by chisel to store other things that we may want to keep between executions, so already have this logic of keeping it if not empty makes sense.
So given this is a general purpose directory, we should not use its existence as an indicator it is fine to resume operation after a crash. If/when we implement crash recovery, we should probably rely on something inside this directory.
This PR implements two conceptual changes:
.chiselworking directoryat the root of the target directory. Existing entry at the same path is remove
to ensure the creation of this directory. This directory is removed at the end
only if it empty. This accomodates future use cases that might leave content
in it on purpose between executions.
rootfsdirectory is created under the.chiselworking dir to cut the new content in an isolated place. Thisdirectory is removed at the end of the process.