mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-09-01 06:41:30 +00:00
Merge branch 'fix/dnd-independent-copy' of https://github.com/M-Hassan-Raza/kitty
This commit is contained in:
commit
dc4471ea6c
3 changed files with 72 additions and 9 deletions
|
|
@ -130,7 +130,8 @@ func uniqify_child_names(names []string, is_case_sensitive_filesystem bool) []st
|
|||
return names
|
||||
}
|
||||
|
||||
func do_local_copy(ctx context.Context, dest_dir *os.File, uri_list []string) (err error) {
|
||||
func do_local_copy(ctx context.Context, dest_dir *os.File, uri_list []string, action int, copy_mode string) (err error) {
|
||||
disallow_hardlinks := action == copy_on_drop && copy_mode == "independent"
|
||||
var src_file *os.File
|
||||
defer func() {
|
||||
if src_file != nil {
|
||||
|
|
@ -162,6 +163,7 @@ func do_local_copy(ctx context.Context, dest_dir *os.File, uri_list []string) (e
|
|||
return err
|
||||
}
|
||||
err = utils.CopyFolderContents(ctx, src_file, d, utils.CopyFolderOptions{
|
||||
Disallow_hardlinks: disallow_hardlinks,
|
||||
Filter_files: func(parent *os.File, child os.FileInfo) bool {
|
||||
return child.IsDir() || child.Mode().IsRegular() || child.Mode()&fs.ModeSymlink != 0
|
||||
},
|
||||
|
|
@ -171,15 +173,17 @@ func do_local_copy(ctx context.Context, dest_dir *os.File, uri_list []string) (e
|
|||
return err
|
||||
}
|
||||
} else if st.Mode().IsRegular() {
|
||||
// First try a hard link
|
||||
dest := filepath.Join(dest_dir.Name(), filepath.Base(path))
|
||||
if err = os.Link(path, dest); err == nil {
|
||||
continue
|
||||
if !disallow_hardlinks {
|
||||
// First try a hard link
|
||||
dest := filepath.Join(dest_dir.Name(), filepath.Base(path))
|
||||
if err = os.Link(path, dest); err == nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if src_file, err = os.Open(path); err != nil {
|
||||
return err
|
||||
}
|
||||
d, err := utils.CreateAt(dest_dir, filepath.Base(dest), st.Mode().Perm())
|
||||
d, err := utils.CreateAt(dest_dir, filepath.Base(path), st.Mode().Perm())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -202,7 +206,7 @@ func do_local_copy(ctx context.Context, dest_dir *os.File, uri_list []string) (e
|
|||
return
|
||||
}
|
||||
|
||||
func do_local_copy_in_goroutine(ctx context.Context, dest_dir *os.File, completion chan error, uri_list []string, wakeup func()) {
|
||||
func do_local_copy_in_goroutine(ctx context.Context, dest_dir *os.File, completion chan error, uri_list []string, action int, copy_mode string, wakeup func()) {
|
||||
var err error
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
|
@ -211,7 +215,7 @@ func do_local_copy_in_goroutine(ctx context.Context, dest_dir *os.File, completi
|
|||
completion <- err
|
||||
wakeup()
|
||||
}()
|
||||
err = do_local_copy(ctx, dest_dir, uri_list)
|
||||
err = do_local_copy(ctx, dest_dir, uri_list, action, copy_mode)
|
||||
}
|
||||
|
||||
type path_stack struct {
|
||||
|
|
@ -691,7 +695,7 @@ func (dnd *dnd) all_mime_data_dropped() (err error) {
|
|||
}
|
||||
drop_status.local_copy.ctx, drop_status.local_copy.cancel_ctx = context.WithCancel(context.Background())
|
||||
drop_status.local_copy.completion = make(chan error, 1)
|
||||
go do_local_copy_in_goroutine(drop_status.local_copy.ctx, f, drop_status.local_copy.completion, file_paths, func() { dnd.lp.WakeupMainThread() })
|
||||
go do_local_copy_in_goroutine(drop_status.local_copy.ctx, f, drop_status.local_copy.completion, file_paths, drop_status.action, dnd.opts.CopyMode, func() { dnd.lp.WakeupMainThread() })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
package dnd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
|
@ -53,6 +54,54 @@ func sortedStrings(s []string) []string {
|
|||
return out
|
||||
}
|
||||
|
||||
func TestLocalCopyHardlinkPolicy(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
action int
|
||||
copy_mode string
|
||||
want_hardlink bool
|
||||
}{
|
||||
{"copy-auto", copy_on_drop, "auto", true},
|
||||
{"copy-independent", copy_on_drop, "independent", false},
|
||||
{"move-auto", move_on_drop, "auto", true},
|
||||
{"move-independent", move_on_drop, "independent", true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
src := filepath.Join(tmp, "src")
|
||||
dst := filepath.Join(tmp, "dst")
|
||||
files := map[string]string{"file.txt": "top level", "folder/nested.txt": "nested"}
|
||||
if err := os.Mkdir(dst, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
buildTree(t, src, files, nil)
|
||||
|
||||
if err := do_local_copy(context.Background(), openDir(t, dst), []string{filepath.Join(src, "file.txt"), filepath.Join(src, "folder")}, tc.action, tc.copy_mode); err != nil {
|
||||
t.Fatalf("do_local_copy: %v", err)
|
||||
}
|
||||
for path, content := range files {
|
||||
source_info, err := os.Stat(filepath.Join(src, path))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
copied := filepath.Join(dst, path)
|
||||
copied_info, err := os.Stat(copied)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if same := os.SameFile(source_info, copied_info); same != tc.want_hardlink {
|
||||
t.Errorf("os.SameFile() for %s: got %v, want %v", path, same, tc.want_hardlink)
|
||||
}
|
||||
if data, err := os.ReadFile(copied); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(data) != content {
|
||||
t.Errorf("copied file %s has unexpected content", path)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestFindOverwrites_NoOverlap verifies that an empty result is returned when
|
||||
// source and destination have no names in common.
|
||||
func TestFindOverwrites_NoOverlap(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,16 @@ text/uri-list.
|
|||
Path to the directory in which dropped data is saved. Defaults to the current working directory.
|
||||
|
||||
|
||||
--copy-mode
|
||||
type=choices
|
||||
choices=auto,independent
|
||||
default=auto
|
||||
Control how local files are handled for Copy drops. The default, :code:`auto`, uses hard links
|
||||
when possible for performance and falls back to copying file data. :code:`independent` always
|
||||
copies file data, so modifying a dropped file cannot modify its source. Move drops always use
|
||||
hard links when possible.
|
||||
|
||||
|
||||
--confirm-drop-overwrite
|
||||
type=bool-set
|
||||
Ask for confirmation when dropping text/uri-list data if the drop will cause any existing
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue