Skip to content
Draft
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
491cd0c
feat: search, load and validates manifests
upils Nov 26, 2025
a6e57f7
feat: adapt to revised strategy
upils Jan 29, 2026
5da0450
feat: implement upgrade
upils Jan 30, 2026
5703751
fix: deletion
upils Jan 30, 2026
26bb2b3
fix: revert inadvertent change
upils Jan 30, 2026
4a14230
fix: check slice collecting error
upils Jan 30, 2026
865c1b8
fix: simplify upgrade and improve deletion
upils Jan 30, 2026
0343ddc
refactor: cleaning
upils Jan 30, 2026
e116424
refactor: refine upgrade
upils Feb 2, 2026
5b9d408
refactor: fsutil handles moving and removing
upils Feb 3, 2026
7861c8d
refactor: improve consistency
upils Feb 3, 2026
27a0d22
style: fix lint error
upils Feb 3, 2026
5f377b0
tests: Move and Remove
upils Feb 3, 2026
f74265c
tests: FindPathsInRelease
upils Feb 3, 2026
799373c
tests: more test cases for Move
upils Feb 3, 2026
dbe3f30
tests: add spread test
upils Feb 3, 2026
becfe42
tests: fix recut spread test
upils Feb 4, 2026
3c994b8
tests: SelectValidManifest
upils Feb 4, 2026
6ebb893
fix: add missing deps
upils Feb 4, 2026
ceac217
tests: recut feature
upils Feb 4, 2026
7e34e32
fix: avoid duplicates in FindPathsInRelease
upils Feb 4, 2026
e1d4e17
ci: rerun
upils Feb 4, 2026
c3db9d4
fix: apply PR suggestions
upils Feb 5, 2026
e1e9c43
refactor: simplify FindPaths and FindPathsInRelease
upils Feb 5, 2026
da567ba
style: lint
upils Feb 5, 2026
2a6c891
fix: remove outdated comment
upils Feb 5, 2026
398e032
test: fix inaccurate tests
upils Feb 5, 2026
7c17f18
refactor: apply PR suggestions
upils Feb 6, 2026
7caf3ba
refactor: revert error message change
upils Feb 6, 2026
a259d1d
fix: gate recut feature behind env var
upils Feb 9, 2026
fad2cb7
refactor: split install from Run
upils Feb 9, 2026
d095953
tests: simplify recut spread test
upils Feb 9, 2026
d0b70cd
tests: rework recut spread tests
upils Feb 9, 2026
83e7af6
refactor: revert now useless changes
upils Feb 9, 2026
d217c43
refactor: simplify
upils Feb 9, 2026
8a7066b
refactor: more cleaning
upils Feb 9, 2026
87d1496
test: wip rework uprade tests
upils Feb 10, 2026
f8e2bd6
fix: ignore unknown manifest schema error
upils Feb 11, 2026
6dd701c
feat: improve upgrade and add tests
upils Feb 11, 2026
8523aa5
tests: simplify TestRunRecut
upils Feb 11, 2026
2ceb21a
fix: rename recut env var
upils Feb 12, 2026
10a1744
docs: add TODO on other file creation bug
upils Feb 12, 2026
6cf317c
refactor: simplify targetDir handling in Run
upils Feb 12, 2026
0d1103b
fix: improve workdir name
upils Feb 12, 2026
78e3f51
fix: clarify intent to remove existing content
upils Feb 12, 2026
d14c056
fix: apply various PR suggestions
upils Feb 13, 2026
4217131
fix: apply PR suggestions
upils Feb 13, 2026
a902099
fix: apply PR suggestions
upils Feb 13, 2026
08b3edd
test: improve regex precision
upils Feb 13, 2026
cf90f0d
refactor: extract and simplify mkParentAll
upils Feb 13, 2026
46f872c
fix: Error when only invalid manifests found
upils Feb 13, 2026
2052ee5
fix: lint
upils Feb 13, 2026
0fbc47a
fix: wrap add context on upgrade errors
upils Feb 13, 2026
30f1c32
style: improve error message
upils Feb 23, 2026
a675ad8
tests: previous package is in the new manifest
upils Feb 23, 2026
558b827
fix: properly replicate parent dirs when upgrading
upils Feb 25, 2026
ab11797
tests: Verify packages in manifest after recut
upils Feb 25, 2026
9ff9bcc
tests: check exactly the package list
upils Feb 25, 2026
f1324a8
fix: nitpicks and typos
upils Feb 26, 2026
78efc45
docs: Expose reasoning behind complex dir creation
upils Feb 26, 2026
b8d695f
refactor: clarify test intent
upils Feb 26, 2026
b811661
tests: test equivalence between a single and 2 cuts
upils Feb 26, 2026
acebd11
docs: outlines important aspects of the overall logic
upils Feb 27, 2026
6e6b09e
tests: simplify TestSelectValidManifest
upils Feb 27, 2026
76483c5
docs: Clarify intent on testing parent dir creation
upils Feb 27, 2026
fb41a11
fix: apply PR suggestions
upils Mar 3, 2026
9e87404
fix: Single predictable working dir name
upils Mar 9, 2026
fea8434
style: lint
upils Mar 9, 2026
aacc37e
feat: Reserve workdir and ban it from the release
upils Mar 9, 2026
cf9aa78
fix: move globs under subdirs
upils Mar 9, 2026
25be459
Revert "fix: Single predictable working dir name"
upils Mar 11, 2026
882c557
docs: Outline limits of workdir collisions handling
upils Mar 11, 2026
1ec1b4a
docs: clarify comment on collision with workdir
upils Mar 11, 2026
bdbba3c
style: fix typo in comment
upils Mar 23, 2026
b12185b
fix: properly return manifest
upils Mar 23, 2026
17d7935
Merge branch 'canonical:main' into recut
upils Mar 31, 2026
0c9b7bd
fix: track manifest path with bools
upils Mar 31, 2026
c5fa3b8
style: rename previous manifest
upils Mar 31, 2026
059422c
fix: simplify usage of contentHash
upils Mar 31, 2026
4f868da
fix: custom error type for unknown manifest schema
upils Mar 31, 2026
b44ef37
style: respect naming convention on manifest vars
upils Apr 1, 2026
85ea2b6
feat: stricter manifest path validation
upils Apr 1, 2026
91780f4
fix: allocate missingPaths slice at once
upils Apr 1, 2026
7bd6655
feat: log when keeping non empty dir
upils Apr 1, 2026
908b49b
fix: always return an error or non-nil valid manifest
upils Apr 1, 2026
e68f1f6
style: formating
upils Apr 1, 2026
3f19c2c
refactor: custom error type for no manifest errors
upils Apr 1, 2026
59a4d7f
docs: improve comment on SelectValidManifest
upils Apr 1, 2026
d1c3919
style: be more consistent with existing terminology
upils Apr 2, 2026
ac1be1b
fix: harmonize error message when applying recut
upils Apr 2, 2026
5cda705
fix: simplify contentHash
upils Apr 2, 2026
7dd133d
Revert "fix: simplify contentHash"
upils Apr 2, 2026
0e892f7
fix: rework strategy to apply recut
upils Apr 3, 2026
18a7b22
feat: refine upgrade process
upils Apr 3, 2026
4550747
fix: lint
upils Apr 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions cmd/chisel/cmd_cut.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/canonical/chisel/internal/cache"
"github.com/canonical/chisel/internal/setup"
"github.com/canonical/chisel/internal/slicer"
"github.com/canonical/chisel/public/manifest"
)

var shortCutHelp = "Cut a tree with selected slices"
Expand Down Expand Up @@ -73,6 +74,24 @@ func (cmd *cmdCut) Execute(args []string) error {
}
}

mfest, err := slicer.SelectValidManifest(cmd.RootDir, release)
Comment thread
upils marked this conversation as resolved.
Outdated
if err != nil {
return err
}
if mfest != nil {
Comment thread
upils marked this conversation as resolved.
Outdated
err = mfest.IterateSlices("", func(slice *manifest.Slice) error {
sk, err := setup.ParseSliceKey(slice.Name)
if err != nil {
return err
}
sliceKeys = append(sliceKeys, sk)
return nil
})
if err != nil {
return err
}
}

selection, err := setup.Select(release, sliceKeys, cmd.Arch)
if err != nil {
return err
Expand Down Expand Up @@ -125,6 +144,7 @@ func (cmd *cmdCut) Execute(args []string) error {
Selection: selection,
Archives: archives,
TargetDir: cmd.RootDir,
Manifest: mfest,
})
return err
}
2 changes: 1 addition & 1 deletion internal/deb/extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ var extractTests = []extractTest{{
}},
},
},
error: `cannot extract from package "test-package": cannot create path /[a-z0-9\-\/]*/file outside of root /[a-z0-9\-\/]*`,
error: `cannot extract from package "test-package": cannot handle path /[a-z0-9\-\/]*/file outside of root /[a-z0-9\-\/]*`,
}}

func (s *S) TestExtract(c *C) {
Expand Down
27 changes: 19 additions & 8 deletions internal/fsutil/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type Entry struct {
//
// Create can return errors from the os package.
func Create(options *CreateOptions) (*Entry, error) {
o, err := getValidOptions(options)
o, err := getValidCreateOptions(options)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -124,7 +124,7 @@ func Create(options *CreateOptions) (*Entry, error) {
// information recorded in Entry. The Hash and Size attributes are set on
// calling Close() on the Writer.
func CreateWriter(options *CreateOptions) (io.WriteCloser, *Entry, error) {
o, err := getValidOptions(options)
o, err := getValidCreateOptions(options)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -166,11 +166,22 @@ func createDir(o *CreateOptions) error {
if err != nil {
return err
}
err = os.Mkdir(path, o.Mode)
if os.IsExist(err) {
return nil
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)
Comment thread
upils marked this conversation as resolved.
Outdated
}

func createFile(o *CreateOptions) error {
Expand Down Expand Up @@ -241,7 +252,7 @@ func createHardLink(o *CreateOptions) error {
return err
}

func getValidOptions(options *CreateOptions) (*CreateOptions, error) {
func getValidCreateOptions(options *CreateOptions) (*CreateOptions, error) {
optsCopy := *options
o := &optsCopy
if o.Root == "" {
Expand All @@ -257,7 +268,7 @@ func getValidOptions(options *CreateOptions) (*CreateOptions, error) {
func absPath(root, relPath string) (string, error) {
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)
Comment thread
upils marked this conversation as resolved.
Outdated
}
return path, nil
}
Expand Down
4 changes: 2 additions & 2 deletions internal/fsutil/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ var createTests = []createTest{{
Mode: 0666,
Data: bytes.NewBufferString("hijacking system file"),
},
error: `cannot create path /file outside of root /root/`,
error: `cannot handle path /file outside of root /root/`,
}, {
summary: "Hardlink cannot escape Root",
options: fsutil.CreateOptions{
Expand Down Expand Up @@ -410,7 +410,7 @@ var createWriterTests = []createWriterTest{{
Mode: 0644,
MakeParents: true,
},
error: `cannot create path /file outside of root /root/`,
error: `cannot handle path /file outside of root /root/`,
}}

func (s *S) TestCreateWriter(c *C) {
Expand Down
84 changes: 84 additions & 0 deletions internal/fsutil/move.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package fsutil

import (
"fmt"
"io/fs"
"os"
"path/filepath"
)

type MoveOptions struct {
SrcRoot string
DstRoot string
// Path is relative to Root.
Path string
Mode fs.FileMode
// If MakeParents is true, missing parent directories of Path are
// created with permissions 0755.
MakeParents bool
// If OverrideMode is true and entry already exists, update the mode. Does
// not affect symlinks.
OverrideMode bool
}

// Move moves or create a filesystem entry according to the provided options.
//
// Move can return errors from the os package.
func Move(options *MoveOptions) error {
o, err := getValidMoveOptions(options)
if err != nil {
return err
}

srcPath, err := absPath(options.SrcRoot, o.Path)
if err != nil {
return err
}
dstPath, err := absPath(options.DstRoot, o.Path)
if err != nil {
return err
}

if o.MakeParents {
if err := os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
return err
}
}

switch o.Mode & fs.ModeType {
Comment thread
upils marked this conversation as resolved.
Outdated
case 0, fs.ModeSymlink:
err = os.Rename(srcPath, dstPath)
case fs.ModeDir:
err = createDir(&CreateOptions{
Comment thread
upils marked this conversation as resolved.
Outdated
Root: o.DstRoot,
Path: o.Path,
Mode: o.Mode,
OverrideMode: o.OverrideMode,
Comment thread
upils marked this conversation as resolved.
Outdated
})
default:
err = fmt.Errorf("unsupported file type: %s", o.Path)
}
if err != nil {
return err
}

return nil
}

func getValidMoveOptions(options *MoveOptions) (*MoveOptions, error) {
optsCopy := *options
o := &optsCopy
if o.SrcRoot == "" {
return nil, fmt.Errorf("internal error: MoveOptions.SrcRoot is unset")
}
if o.DstRoot == "" {
return nil, fmt.Errorf("internal error: MoveOptions.DstRoot is unset")
}
if o.SrcRoot != "/" {
o.SrcRoot = filepath.Clean(o.SrcRoot) + "/"
}
if o.DstRoot != "/" {
o.DstRoot = filepath.Clean(o.DstRoot) + "/"
}
return o, nil
}
Loading
Loading