diff --git a/weed/server/filer_grpc_server_rename.go b/weed/server/filer_grpc_server_rename.go index 568b10428..7142f7606 100644 --- a/weed/server/filer_grpc_server_rename.go +++ b/weed/server/filer_grpc_server_rename.go @@ -96,6 +96,11 @@ func (fs *FilerServer) moveSelfEntry(ctx context.Context, oldParent filer2.FullP glog.V(1).Infof("moving entry %s => %s", oldPath, newPath) + if oldPath == newPath { + glog.V(1).Infof("skip moving entry %s => %s", oldPath, newPath) + return nil + } + // add to new directory newEntry := &filer2.Entry{ FullPath: newPath, diff --git a/weed/shell/command_fs_mv.go b/weed/shell/command_fs_mv.go new file mode 100644 index 000000000..130bfe4e7 --- /dev/null +++ b/weed/shell/command_fs_mv.go @@ -0,0 +1,96 @@ +package shell + +import ( + "context" + "fmt" + "io" + "path/filepath" + + "github.com/chrislusf/seaweedfs/weed/filer2" + "github.com/chrislusf/seaweedfs/weed/pb/filer_pb" +) + +func init() { + Commands = append(Commands, &commandFsMv{}) +} + +type commandFsMv struct { +} + +func (c *commandFsMv) Name() string { + return "fs.mv" +} + +func (c *commandFsMv) Help() string { + return `move or rename a file or a folder + + fs.mv + + fs.mv /dir/file_name /dir2/filename2 + fs.mv /dir/file_name /dir2 + + fs.mv /dir/dir2 /dir3/dir4/ + fs.mv /dir/dir2 /dir3/new_dir + +` +} + +func (c *commandFsMv) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) { + + filerServer, filerPort, sourcePath, err := commandEnv.parseUrl(args[0]) + if err != nil { + return err + } + + _, _, destinationPath, err := commandEnv.parseUrl(args[1]) + if err != nil { + return err + } + + ctx := context.Background() + + + sourceDir, sourceName := filer2.FullPath(sourcePath).DirAndName() + + destinationDir, destinationName := filer2.FullPath(destinationPath).DirAndName() + + + return commandEnv.withFilerClient(ctx, filerServer, filerPort, func(client filer_pb.SeaweedFilerClient) error { + + // collect destination entry info + destinationRequest := &filer_pb.LookupDirectoryEntryRequest{ + Name: destinationDir, + Directory: destinationName, + } + respDestinationLookupEntry, err := client.LookupDirectoryEntry(ctx, destinationRequest) + + var targetDir, targetName string + + // moving a file or folder + if err == nil && respDestinationLookupEntry.Entry.IsDirectory { + // to a directory + targetDir = filepath.ToSlash(filepath.Join(destinationDir, destinationName)) + targetName = sourceName + } else { + // to a file or folder + targetDir = destinationDir + targetName = destinationName + } + + + request := &filer_pb.AtomicRenameEntryRequest{ + OldDirectory: sourceDir, + OldName: sourceName, + NewDirectory: targetDir, + NewName: targetName, + } + + _, err = client.AtomicRenameEntry(ctx, request) + + fmt.Fprintf(writer, "move: %s => %s\n", sourcePath, filer2.NewFullPath(targetDir, targetName)) + + return err + + }) + +}