Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

touch: add recurse functionality - issue #5301 #5330

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/touch/touch.go
Expand Up @@ -17,6 +17,7 @@ var (
notCreateNewFile bool
timeAsArgument string
localTime bool
recurse bool
)

const (
Expand All @@ -31,6 +32,7 @@ func init() {
flags.BoolVarP(cmdFlags, &notCreateNewFile, "no-create", "C", false, "Do not create the file if it does not exist.")
flags.StringVarP(cmdFlags, &timeAsArgument, "timestamp", "t", "", "Use specified time instead of the current time of day.")
flags.BoolVarP(cmdFlags, &localTime, "localtime", "", false, "Use localtime for timestamp, not UTC.")
flags.BoolVarP(cmdFlags, &recurse, "recursive", "R", false, "Recurse into the listing.")
}

var commandDefinition = &cobra.Command{
Expand Down
22 changes: 22 additions & 0 deletions cmd/touch/touch_test.go
Expand Up @@ -117,3 +117,25 @@ func TestTouchCreateMultipleDirAndFile(t *testing.T) {
file1 := fstest.NewItem("a/b/c.txt", "", t1)
fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{"a", "a/b"}, fs.ModTimeNotSupported)
}

func TestTouchRecursiveWithTimestamp(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()

timeAsArgument = "060102"
srcFileName := "oldFile"
err := TouchRecursive(context.Background(), r.Fremote, srcFileName)
require.NoError(t, err)
checkFile(t, r.Fremote, srcFileName, "")
}

func TestTouchRecursiveWithLongerTimestamp(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()

timeAsArgument = "2006-01-02T15:04:05"
srcFileName := "oldFile"
err := TouchRecursive(context.Background(), r.Fremote, srcFileName)
require.NoError(t, err)
checkFile(t, r.Fremote, srcFileName, "")
}
1 change: 1 addition & 0 deletions docs/content/commands/rclone_touch.md
Expand Up @@ -39,6 +39,7 @@ rclone touch remote:path [flags]
-h, --help help for touch
--localtime Use localtime for timestamp, not UTC.
-C, --no-create Do not create the file if it does not exist.
-R, --recursive Recurse into the listing.
-t, --timestamp string Use specified time instead of the current time of day.
```

Expand Down
47 changes: 47 additions & 0 deletions fs/operations/touch.go
@@ -0,0 +1,47 @@
package operations

import (
"context"
"fmt"
"log"
"path"
"sort"
"strings"

"github.com/pkg/errors"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/config"
"github.com/rclone/rclone/fs/hash"
"github.com/rclone/rclone/fs/walk"
)

// Recursively touch every file in fscr with time t
func TouchRecursive(ctx context.Context, fsrc fs.Fs, t time.Time) (err error) {
timeAtr := time.Now()
if timeAsArgument != "" {
layout := defaultLayout
if len(timeAsArgument) == len(layoutDateWithTime) {
layout = layoutDateWithTime
} else if len(timeAsArgument) > len(layoutDateWithTime) {
layout = layoutDateWithTimeNano
}
var timeAtrFromFlags time.Time
if localTime {
timeAtrFromFlags, err = time.ParseInLocation(layout, timeAsArgument, time.Local)
} else {
timeAtrFromFlags, err = time.Parse(layout, timeAsArgument)
}
if err != nil {
return errors.Wrap(err, "failed to parse date/time argument")
}
timeAtr = timeAtrFromFlags
}

return operations.ListFn(ctx, fsrc, func(o fs.Object) {
err := o.SetModTime(ctx, timeAtr)
if err != nil {
err = fs.CountError(err)
fs.Errorf(o, "touch: couldn't set mod time %v", err)
}
})
}