| 
4 | 4 | package unittest  | 
5 | 5 | 
 
  | 
6 | 6 | import (  | 
7 |  | -	"errors"  | 
8 | 7 | 	"io"  | 
9 | 8 | 	"os"  | 
10 | 9 | 	"path"  | 
@@ -55,44 +54,73 @@ func Copy(src, dest string) error {  | 
55 | 54 | 	return os.Chmod(dest, si.Mode())  | 
56 | 55 | }  | 
57 | 56 | 
 
  | 
58 |  | -// CopyDir copy files recursively from source to target directory.  | 
59 |  | -//  | 
60 |  | -// The filter accepts a function that process the path info.  | 
61 |  | -// and should return true for need to filter.  | 
62 |  | -//  | 
63 |  | -// It returns error when error occurs in underlying functions.  | 
64 |  | -func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error {  | 
65 |  | -	// Check if target directory exists.  | 
66 |  | -	if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) {  | 
67 |  | -		return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath)  | 
 | 57 | +// Sync synchronizes the two files. This is skipped if both files  | 
 | 58 | +// exist and the size, modtime, and mode match.  | 
 | 59 | +func Sync(srcPath, destPath string) error {  | 
 | 60 | +	dest, err := os.Stat(destPath)  | 
 | 61 | +	if err != nil {  | 
 | 62 | +		if os.IsNotExist(err) {  | 
 | 63 | +			return Copy(srcPath, destPath)  | 
 | 64 | +		}  | 
 | 65 | +		return err  | 
68 | 66 | 	}  | 
69 | 67 | 
 
  | 
70 |  | -	err := os.MkdirAll(destPath, os.ModePerm)  | 
 | 68 | +	src, err := os.Stat(srcPath)  | 
71 | 69 | 	if err != nil {  | 
72 | 70 | 		return err  | 
73 | 71 | 	}  | 
74 | 72 | 
 
  | 
75 |  | -	// Gather directory info.  | 
76 |  | -	infos, err := util.StatDir(srcPath, true)  | 
 | 73 | +	if src.Size() == dest.Size() &&  | 
 | 74 | +		src.ModTime() == dest.ModTime() &&  | 
 | 75 | +		src.Mode() == dest.Mode() {  | 
 | 76 | +		return nil  | 
 | 77 | +	}  | 
 | 78 | + | 
 | 79 | +	return Copy(srcPath, destPath)  | 
 | 80 | +}  | 
 | 81 | + | 
 | 82 | +// SyncDirs synchronizes files recursively from source to target directory.  | 
 | 83 | +//  | 
 | 84 | +// It returns error when error occurs in underlying functions.  | 
 | 85 | +func SyncDirs(srcPath, destPath string) error {  | 
 | 86 | +	err := os.MkdirAll(destPath, os.ModePerm)  | 
77 | 87 | 	if err != nil {  | 
78 | 88 | 		return err  | 
79 | 89 | 	}  | 
80 | 90 | 
 
  | 
81 |  | -	var filter func(filePath string) bool  | 
82 |  | -	if len(filters) > 0 {  | 
83 |  | -		filter = filters[0]  | 
 | 91 | +	// find and delete all untracked files  | 
 | 92 | +	infos, err := util.StatDir(destPath, true)  | 
 | 93 | +	if err != nil {  | 
 | 94 | +		return err  | 
84 | 95 | 	}  | 
85 | 96 | 
 
  | 
86 | 97 | 	for _, info := range infos {  | 
87 |  | -		if filter != nil && filter(info) {  | 
88 |  | -			continue  | 
 | 98 | +		curPath := path.Join(destPath, info)  | 
 | 99 | + | 
 | 100 | +		if _, err := os.Stat(path.Join(srcPath, info)); err != nil {  | 
 | 101 | +			if os.IsNotExist(err) {  | 
 | 102 | +				// Delete  | 
 | 103 | +				if err := os.RemoveAll(curPath); err != nil {  | 
 | 104 | +					return err  | 
 | 105 | +				}  | 
 | 106 | +			} else {  | 
 | 107 | +				return err  | 
 | 108 | +			}  | 
89 | 109 | 		}  | 
 | 110 | +	}  | 
90 | 111 | 
 
  | 
 | 112 | +	// Gather directory info.  | 
 | 113 | +	infos, err = util.StatDir(srcPath, true)  | 
 | 114 | +	if err != nil {  | 
 | 115 | +		return err  | 
 | 116 | +	}  | 
 | 117 | + | 
 | 118 | +	for _, info := range infos {  | 
91 | 119 | 		curPath := path.Join(destPath, info)  | 
92 | 120 | 		if strings.HasSuffix(info, "/") {  | 
93 | 121 | 			err = os.MkdirAll(curPath, os.ModePerm)  | 
94 | 122 | 		} else {  | 
95 |  | -			err = Copy(path.Join(srcPath, info), curPath)  | 
 | 123 | +			err = Sync(path.Join(srcPath, info), curPath)  | 
96 | 124 | 		}  | 
97 | 125 | 		if err != nil {  | 
98 | 126 | 			return err  | 
 | 
0 commit comments