Skip to content

Commit c2aae9a

Browse files
authored
Feature: 上传时默认忽略隐藏的文件 (#92)
* Feature: 上传时默认忽略隐藏的文件 - 用户上传目录时,目录中包含的 . 开头的文件默认会被忽略 - 用户可以使用 --all 参数 强制上传所以文件 * 忽略windows下的隐藏文件 - 增加对windows系统下隐藏文件忽略的支持 * 上传隐藏目录触发提示 如果上传的是目录,并且是隐藏的目录,没有使用 `-all` 参数则触发提示 * chore: 增加忽略文件的测试用例
1 parent 9125cd7 commit c2aae9a

File tree

8 files changed

+189
-28
lines changed

8 files changed

+189
-28
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ upx get -c /baima_text_auditer.tar
363363
| options | 说明 |
364364
|---------|-----------------------------|
365365
| -w | 多线程下载 (1-10) (default: 5) |
366-
366+
| -all | 上传包含目录下隐藏的文件和文件夹 |
367367
#### 语法
368368
```bash
369369
upx put <local-file> [remote-file]
@@ -391,6 +391,7 @@ upx put ./video /myfiles
391391
| options | 说明 |
392392
|---------|-----------------------------|
393393
| -w | 多线程下载 (1-10) (default: 5) |
394+
| -all | 上传包含目录下隐藏的文件和文件夹 |
394395
| --remote | 远程路径 |
395396

396397
#### 语法

commands.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,13 @@ func NewPutCommand() cli.Command {
347347
localPath,
348348
upPath,
349349
c.Int("w"),
350+
c.Bool("all"),
350351
)
351352
return nil
352353
},
353354
Flags: []cli.Flag{
354355
cli.IntFlag{Name: "w", Usage: "max concurrent threads", Value: 5},
356+
cli.BoolFlag{Name: "all", Usage: "upload all files including hidden files"},
355357
},
356358
}
357359
}
@@ -370,10 +372,12 @@ func NewUploadCommand() cli.Command {
370372
c.Args(),
371373
c.String("remote"),
372374
c.Int("w"),
375+
c.Bool("all"),
373376
)
374377
return nil
375378
},
376379
Flags: []cli.Flag{
380+
cli.BoolFlag{Name: "all", Usage: "upload all files including hidden files"},
377381
cli.IntFlag{Name: "w", Usage: "max concurrent threads", Value: 5},
378382
cli.StringFlag{Name: "remote", Usage: "remote path", Value: "./"},
379383
},

fsutil/ignore.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package fsutil
2+
3+
import (
4+
"strings"
5+
)
6+
7+
// 判断文件是否是 . 开头的
8+
func hasDotPrefix(filename string) bool {
9+
return strings.HasPrefix(filename, ".")
10+
}

fsutil/ignore_unix.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build linux || darwin
2+
3+
package fsutil
4+
5+
import (
6+
"io/fs"
7+
"path/filepath"
8+
)
9+
10+
// 判断文件是否是需要忽略的文件
11+
func IsIgnoreFile(path string, fileInfo fs.FileInfo) bool {
12+
return hasDotPrefix(filepath.Base(path))
13+
}

fsutil/ignore_windows.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//go:build windows
2+
3+
package fsutil
4+
5+
import (
6+
"io/fs"
7+
"path/filepath"
8+
"syscall"
9+
)
10+
11+
// 判断文件是否是需要忽略的文件
12+
func IsIgnoreFile(path string, fileInfo fs.FileInfo) bool {
13+
for hasDotPrefix(filepath.Base(path)) {
14+
return true
15+
}
16+
17+
underlyingData := fileInfo.Sys().(*syscall.Win32FileAttributeData)
18+
if underlyingData != nil {
19+
return underlyingData.FileAttributes&syscall.FILE_ATTRIBUTE_HIDDEN != 0
20+
}
21+
22+
return false
23+
}

putiginore_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package upx
2+
3+
import (
4+
"io/ioutil"
5+
"path"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func Ls(up string) ([]string, error) {
14+
b, err := Upx("ls", up)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
var ups = make([]string, 0)
20+
output := strings.TrimRight(string(b), "\n")
21+
for _, line := range strings.Split(output, "\n") {
22+
items := strings.Split(line, " ")
23+
ups = append(ups, items[len(items)-1])
24+
}
25+
return ups, nil
26+
}
27+
28+
func TestPutIgnore(t *testing.T) {
29+
SetUp()
30+
defer TearDown()
31+
32+
upRootPath := path.Join(ROOT, "iginore")
33+
Upx("mkdir", upRootPath)
34+
35+
localRootPath, err := ioutil.TempDir("", "test")
36+
assert.NoError(t, err)
37+
localRootName := filepath.Base(localRootPath)
38+
39+
CreateFile(path.Join(localRootPath, "FILE1"))
40+
CreateFile(path.Join(localRootPath, "FILE2"))
41+
CreateFile(path.Join(localRootPath, ".FILE3"))
42+
CreateFile(path.Join(localRootPath, ".FILES/FILE"))
43+
44+
// 上传文件夹
45+
// 不包含隐藏的文件,所以只有FILE1和FILE2
46+
Upx("put", localRootPath, upRootPath)
47+
files, err := Ls(path.Join(upRootPath, localRootName))
48+
49+
assert.NoError(t, err)
50+
assert.Len(t, files, 2)
51+
assert.ElementsMatch(
52+
t,
53+
files,
54+
[]string{"FILE1", "FILE2"},
55+
)
56+
57+
// 上传隐藏的文件夹, 无all,上传失效
58+
Upx(
59+
"put",
60+
path.Join(localRootPath, ".FILES"),
61+
path.Join(upRootPath, localRootName, ".FILES"),
62+
)
63+
files, err = Ls(path.Join(upRootPath, localRootName))
64+
assert.NoError(t, err)
65+
66+
assert.Len(t, files, 2)
67+
assert.ElementsMatch(
68+
t,
69+
files,
70+
[]string{"FILE1", "FILE2"},
71+
)
72+
73+
// 上传隐藏的文件夹, 有all,上传成功
74+
Upx(
75+
"put",
76+
"-all",
77+
path.Join(localRootPath, ".FILES"),
78+
path.Join(upRootPath, localRootName, ".FILES"),
79+
)
80+
files, err = Ls(path.Join(upRootPath, localRootName))
81+
assert.NoError(t, err)
82+
assert.Len(t, files, 3)
83+
assert.ElementsMatch(
84+
t,
85+
files,
86+
[]string{"FILE1", "FILE2", ".FILES"},
87+
)
88+
89+
// 上传所有文件
90+
Upx("put", "-all", localRootPath, upRootPath)
91+
files, err = Ls(path.Join(upRootPath, localRootName))
92+
assert.NoError(t, err)
93+
assert.Len(t, files, 4)
94+
assert.ElementsMatch(
95+
t,
96+
files,
97+
[]string{"FILE1", "FILE2", ".FILE3", ".FILES"},
98+
)
99+
}

session.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"encoding/json"
66
"fmt"
7+
"io/fs"
78
"io/ioutil"
89
"log"
910
"math/rand"
@@ -20,6 +21,7 @@ import (
2021
"github.com/arrebole/progressbar"
2122
"github.com/fatih/color"
2223
"github.com/upyun/go-sdk/v3/upyun"
24+
"github.com/upyun/upx/fsutil"
2325
"github.com/upyun/upx/partial"
2426
)
2527

@@ -496,7 +498,6 @@ func (sess *Session) putFileWithProgress(localPath, upPath string, localInfo os.
496498
return err
497499
}
498500
defer fd.Close()
499-
500501
cfg := &upyun.PutObjectConfig{
501502
Path: upPath,
502503
Headers: map[string]string{
@@ -601,20 +602,32 @@ func (sess *Session) putFilesWitchProgress(localFiles []*UploadedFile, workers i
601602
wg.Wait()
602603
}
603604

604-
func (sess *Session) putDir(localPath, upPath string, workers int) {
605+
func (sess *Session) putDir(localPath, upPath string, workers int, withIgnore bool) {
606+
localAbsPath, err := filepath.Abs(localPath)
607+
if err != nil {
608+
PrintErrorAndExit(err.Error())
609+
}
610+
// 如果上传的是目录,并且是隐藏的目录,则触发提示
611+
rootDirInfo, err := os.Stat(localAbsPath)
612+
if err != nil {
613+
PrintErrorAndExit(err.Error())
614+
}
615+
if !withIgnore && fsutil.IsIgnoreFile(localAbsPath, rootDirInfo) {
616+
PrintErrorAndExit("%s is a ignore dir, use `-all` to force put all files", localAbsPath)
617+
}
618+
605619
type FileInfo struct {
606620
fpath string
607621
fInfo os.FileInfo
608622
}
609623
localFiles := make(chan *FileInfo, workers*2)
610624
var wg sync.WaitGroup
611-
var err error
612625
wg.Add(workers)
613626
for w := 0; w < workers; w++ {
614627
go func() {
615628
defer wg.Done()
616629
for info := range localFiles {
617-
rel, _ := filepath.Rel(localPath, info.fpath)
630+
rel, _ := filepath.Rel(localAbsPath, info.fpath)
618631
desPath := path.Join(upPath, filepath.ToSlash(rel))
619632
if fInfo, err := os.Stat(info.fpath); err == nil && fInfo.IsDir() {
620633
err = sess.updriver.Mkdir(desPath)
@@ -628,21 +641,29 @@ func (sess *Session) putDir(localPath, upPath string, workers int) {
628641
}()
629642
}
630643

631-
walk(localPath, func(fpath string, fInfo os.FileInfo, err error) {
632-
if err == nil {
644+
filepath.Walk(localAbsPath, func(path string, info fs.FileInfo, err error) error {
645+
if err != nil {
646+
return err
647+
}
648+
if !withIgnore && fsutil.IsIgnoreFile(path, info) {
649+
if info.IsDir() {
650+
return filepath.SkipDir
651+
}
652+
} else {
633653
localFiles <- &FileInfo{
634-
fpath: fpath,
635-
fInfo: fInfo,
654+
fpath: path,
655+
fInfo: info,
636656
}
637657
}
658+
return nil
638659
})
639660

640661
close(localFiles)
641662
wg.Wait()
642663
}
643664

644665
// / Put 上传单文件或单目录
645-
func (sess *Session) Put(localPath, upPath string, workers int) {
666+
func (sess *Session) Put(localPath, upPath string, workers int, withIgnore bool) {
646667
upPath = sess.AbsPath(upPath)
647668

648669
exist, isDir := false, false
@@ -693,7 +714,7 @@ func (sess *Session) Put(localPath, upPath string, workers int) {
693714
upPath = path.Join(upPath, filepath.Base(localPath))
694715
}
695716
}
696-
sess.putDir(localPath, upPath, workers)
717+
sess.putDir(localPath, upPath, workers, withIgnore)
697718
} else {
698719
if isDir {
699720
upPath = path.Join(upPath, filepath.Base(localPath))
@@ -703,7 +724,7 @@ func (sess *Session) Put(localPath, upPath string, workers int) {
703724
}
704725

705726
// put 的升级版命令, 支持多文件上传
706-
func (sess *Session) Upload(filenames []string, upPath string, workers int) {
727+
func (sess *Session) Upload(filenames []string, upPath string, workers int, withIgnore bool) {
707728
upPath = sess.AbsPath(upPath)
708729

709730
// 检测云端的目的地目录
@@ -741,7 +762,12 @@ func (sess *Session) Upload(filenames []string, upPath string, workers int) {
741762

742763
// 上传目录
743764
for _, localPath := range dirs {
744-
sess.putDir(localPath, path.Join(upPath, filepath.Base(localPath)), workers)
765+
sess.putDir(
766+
localPath,
767+
path.Join(upPath, filepath.Base(localPath)),
768+
workers,
769+
withIgnore,
770+
)
745771
}
746772

747773
// 上传文件

utils.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import (
44
"crypto/md5"
55
"fmt"
66
"io"
7-
"io/ioutil"
87
"os"
9-
"path/filepath"
108
"strconv"
119
"strings"
1210
"time"
@@ -134,19 +132,6 @@ func md5File(fpath string) (string, error) {
134132
return fmt.Sprintf("%x", hash.Sum(nil)), nil
135133
}
136134

137-
func walk(root string, f func(string, os.FileInfo, error)) {
138-
fi, err := os.Stat(root)
139-
if err == nil && fi != nil && fi.IsDir() {
140-
fInfos, err := ioutil.ReadDir(root)
141-
f(root, fi, err)
142-
for _, fInfo := range fInfos {
143-
walk(filepath.Join(root, fInfo.Name()), f)
144-
}
145-
} else {
146-
f(root, fi, err)
147-
}
148-
}
149-
150135
func contains(slice []string, item string) bool {
151136
for _, s := range slice {
152137
if s == item {

0 commit comments

Comments
 (0)