You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

555 lines
13 KiB

  1. package grsync
  2. import (
  3. "fmt"
  4. "io"
  5. "os"
  6. "os/exec"
  7. "strconv"
  8. "strings"
  9. )
  10. // Rsync is wrapper under rsync
  11. type Rsync struct {
  12. Source string
  13. Destination string
  14. cmd *exec.Cmd
  15. }
  16. // RsyncOptions for rsync
  17. type RsyncOptions struct {
  18. // Verbose increase verbosity
  19. Verbose bool
  20. // Quet suppress non-error messages
  21. Quiet bool
  22. // Checksum skip based on checksum, not mod-time & size
  23. Checksum bool
  24. // Archve is archive mode; equals -rlptgoD (no -H,-A,-X)
  25. Archive bool
  26. // Recurse into directories
  27. Recursive bool
  28. // Relative option to use relative path names
  29. Relative bool
  30. // NoImliedDirs don't send implied dirs with --relative
  31. NoImpliedDirs bool
  32. // Update skip files that are newer on the receiver
  33. Update bool
  34. // Inplace update destination files in-place
  35. Inplace bool
  36. // Append data onto shorter files
  37. Append bool
  38. // AppendVerify --append w/old data in file checksum
  39. AppendVerify bool
  40. // Dirs transfer directories without recursing
  41. Dirs bool
  42. // Links copy symlinks as symlinks
  43. Links bool
  44. // CopyLinks transform symlink into referent file/dir
  45. CopyLinks bool
  46. // CopyUnsafeLinks only "unsafe" symlinks are transformed
  47. CopyUnsafeLinks bool
  48. // SafeLinks ignore symlinks that point outside the tree
  49. SafeLinks bool
  50. // CopyDirLinks transform symlink to dir into referent dir
  51. CopyDirLinks bool
  52. // KeepDirLinks treat symlinked dir on receiver as dir
  53. KeepDirLinks bool
  54. // HardLinks preserve hard links
  55. HardLinks bool
  56. // Perms preserve permissions
  57. Perms bool
  58. // Executability preserve executability
  59. Executability bool
  60. // CHMOD affect file and/or directory permissions
  61. CHMOD os.FileMode
  62. // Acls preserve ACLs (implies -p)
  63. ACLs bool
  64. // XAttrs preserve extended attributes
  65. XAttrs bool
  66. // Owner preserve owner (super-user only)
  67. Owner bool
  68. // Group preserve group
  69. Group bool
  70. // Devices preserve device files (super-user only)
  71. Devices bool
  72. // Specials preserve special files
  73. Specials bool
  74. // Times preserve modification times
  75. Times bool
  76. // omit directories from --times
  77. OmitDirTimes bool
  78. // Super receiver attempts super-user activities
  79. Super bool
  80. // FakeSuper store/recover privileged attrs using xattrs
  81. FakeSuper bool
  82. // Sparce handle sparse files efficiently
  83. Sparse bool
  84. // DryRun perform a trial run with no changes made
  85. DryRun bool
  86. // WholeFile copy files whole (w/o delta-xfer algorithm)
  87. WholeFile bool
  88. // OneFileSystem don't cross filesystem boundaries
  89. OneFileSystem bool
  90. // BlockSize block-size=SIZE force a fixed checksum block-size
  91. BlockSize int
  92. // Rsh -rsh=COMMAND specify the remote shell to use
  93. Rsh string
  94. // RsyncProgramm rsync-path=PROGRAM specify the rsync to run on remote machine
  95. RsyncProgramm string
  96. // Existing skip creating new files on receiver
  97. Existing bool
  98. // IgnoreExisting skip updating files that exist on receiver
  99. IgnoreExisting bool
  100. // RemoveSourceFiles sender removes synchronized files (non-dir)
  101. RemoveSourceFiles bool
  102. // Delete delete extraneous files from dest dirs
  103. Delete bool
  104. // DeleteBefore receiver deletes before transfer, not during
  105. DeleteBefore bool
  106. // DeleteDuring receiver deletes during the transfer
  107. DeleteDuring bool
  108. // DeleteDelay find deletions during, delete after
  109. DeleteDelay bool
  110. // DeleteAfter receiver deletes after transfer, not during
  111. DeleteAfter bool
  112. // DeleteExcluded also delete excluded files from dest dirs
  113. DeleteExcluded bool
  114. // IgnoreErrors delete even if there are I/O errors
  115. IgnoreErrors bool
  116. // Force deletion of dirs even if not empty
  117. Force bool
  118. // MaxDelete max-delete=NUM don't delete more than NUM files
  119. MaxDelete int
  120. // MaxSize max-size=SIZE don't transfer any file larger than SIZE
  121. MaxSize int
  122. // MinSize don't transfer any file smaller than SIZE
  123. MinSize int
  124. // Partial keep partially transferred files
  125. Partial bool
  126. // PartialDir partial-dir=DIR
  127. PartialDir string
  128. // DelayUpdates put all updated files into place at end
  129. DelayUpdates bool
  130. // PruneEmptyDirs prune empty directory chains from file-list
  131. PruneEmptyDirs bool
  132. // NumericIDs don't map uid/gid values by user/group name
  133. NumericIDs bool
  134. // Timeout timeout=SECONDS set I/O timeout in seconds
  135. Timeout int
  136. // Contimeout contimeout=SECONDS set daemon connection timeout in seconds
  137. Contimeout int
  138. // IgnoreTimes don't skip files that match size and time
  139. IgnoreTimes bool
  140. // SizeOnly skip files that match in size
  141. SizeOnly bool
  142. // ModifyWindow modify-window=NUM compare mod-times with reduced accuracy
  143. ModifyWindow bool
  144. // TempDir temp-dir=DIR create temporary files in directory DIR
  145. TempDir string
  146. // Fuzzy find similar file for basis if no dest file
  147. Fuzzy bool
  148. // CompareDest compare-dest=DIR also compare received files relative to DIR
  149. CompareDest string
  150. // CopyDest copy-dest=DIR ... and include copies of unchanged files
  151. CopyDest string
  152. // LinkDest link-dest=DIR hardlink to files in DIR when unchanged
  153. LinkDest string
  154. // Compress file data during the transfer
  155. Compress bool
  156. // CompressLevel explicitly set compression level
  157. CompressLevel int
  158. // SkipCompress skip-compress=LIST skip compressing files with suffix in LIST
  159. SkipCompress []string
  160. // CVSExclude auto-ignore files in the same way CVS does
  161. CVSExclude bool
  162. // Stats give some file-transfer stats
  163. Stats bool
  164. // HumanReadable output numbers in a human-readable format
  165. HumanReadable bool
  166. // Progress show progress during transfer
  167. Progress bool
  168. // 端口
  169. Port int
  170. // 密钥文件
  171. PasswordFile string
  172. // Info
  173. Info string
  174. // ipv4
  175. IPv4 bool
  176. // ipv6
  177. IPv6 bool
  178. }
  179. // StdoutPipe returns a pipe that will be connected to the command's
  180. // standard output when the command starts.
  181. func (r Rsync) StdoutPipe() (io.ReadCloser, error) {
  182. return r.cmd.StdoutPipe()
  183. }
  184. // StderrPipe returns a pipe that will be connected to the command's
  185. // standard error when the command starts.
  186. func (r Rsync) StderrPipe() (io.ReadCloser, error) {
  187. return r.cmd.StderrPipe()
  188. }
  189. // Run start rsync task
  190. func (r Rsync) Run() error {
  191. if !isExist(r.Destination) {
  192. if err := createDir(r.Destination); err != nil {
  193. return err
  194. }
  195. }
  196. if err := r.cmd.Start(); err != nil {
  197. return err
  198. }
  199. return r.cmd.Wait()
  200. }
  201. // NewRsync returns task with described options
  202. func NewRsync(source, destination string, options RsyncOptions) *Rsync {
  203. arguments := append(getArguments(options), source, destination)
  204. return &Rsync{
  205. Source: source,
  206. Destination: destination,
  207. cmd: exec.Command("rsync", arguments...),
  208. }
  209. }
  210. func getArguments(options RsyncOptions) []string {
  211. arguments := []string{}
  212. if options.Verbose {
  213. arguments = append(arguments, "--verbose")
  214. }
  215. if options.Checksum {
  216. arguments = append(arguments, "--checksum")
  217. }
  218. if options.Quiet {
  219. arguments = append(arguments, "--quiet")
  220. }
  221. if options.Archive {
  222. arguments = append(arguments, "--archive")
  223. }
  224. if options.Recursive {
  225. arguments = append(arguments, "--recursive")
  226. }
  227. if options.Relative {
  228. arguments = append(arguments, "--relative")
  229. }
  230. if options.NoImpliedDirs {
  231. arguments = append(arguments, "--no-implied-dirs")
  232. }
  233. if options.Update {
  234. arguments = append(arguments, "--update")
  235. }
  236. if options.Inplace {
  237. arguments = append(arguments, "--inplace")
  238. }
  239. if options.Append {
  240. arguments = append(arguments, "--append")
  241. }
  242. if options.AppendVerify {
  243. arguments = append(arguments, "--append-verify")
  244. }
  245. if options.Dirs {
  246. arguments = append(arguments, "--dirs")
  247. }
  248. if options.Links {
  249. arguments = append(arguments, "--links")
  250. }
  251. if options.CopyLinks {
  252. arguments = append(arguments, "--copy-links")
  253. }
  254. if options.CopyUnsafeLinks {
  255. arguments = append(arguments, "--copy-unsafe-links")
  256. }
  257. if options.SafeLinks {
  258. arguments = append(arguments, "--safe-links")
  259. }
  260. if options.CopyDirLinks {
  261. arguments = append(arguments, "--copy-dir-links")
  262. }
  263. if options.KeepDirLinks {
  264. arguments = append(arguments, "--keep-dir-links")
  265. }
  266. if options.HardLinks {
  267. arguments = append(arguments, "--hard-links")
  268. }
  269. if options.Perms {
  270. arguments = append(arguments, "--perms")
  271. }
  272. if options.Executability {
  273. arguments = append(arguments, "--executability")
  274. }
  275. if options.ACLs {
  276. arguments = append(arguments, "--acls")
  277. }
  278. if options.XAttrs {
  279. arguments = append(arguments, "--xattrs")
  280. }
  281. if options.Owner {
  282. arguments = append(arguments, "--owner")
  283. }
  284. if options.Group {
  285. arguments = append(arguments, "--group")
  286. }
  287. if options.Devices {
  288. arguments = append(arguments, "--devices")
  289. }
  290. if options.Port > 0 {
  291. arguments = append(arguments, fmt.Sprintf("--port=%d", options.Port))
  292. }
  293. if options.Specials {
  294. arguments = append(arguments, "--specials")
  295. }
  296. if options.Times {
  297. arguments = append(arguments, "--times")
  298. }
  299. if options.OmitDirTimes {
  300. arguments = append(arguments, "--omit-dir-times")
  301. }
  302. if options.Super {
  303. arguments = append(arguments, "--super")
  304. }
  305. if options.FakeSuper {
  306. arguments = append(arguments, "--fake-super")
  307. }
  308. if options.Sparse {
  309. arguments = append(arguments, "--sparse")
  310. }
  311. if options.DryRun {
  312. arguments = append(arguments, "--dry-run")
  313. }
  314. if options.WholeFile {
  315. arguments = append(arguments, "--whole-file")
  316. }
  317. if options.OneFileSystem {
  318. arguments = append(arguments, "--one-file-system")
  319. }
  320. if options.BlockSize > 0 {
  321. arguments = append(arguments, "--block-size", strconv.Itoa(options.BlockSize))
  322. }
  323. if options.Rsh != "" {
  324. arguments = append(arguments, "--rsh", options.Rsh)
  325. }
  326. if options.RsyncProgramm != "" {
  327. arguments = append(arguments, "--rsync-programm", options.RsyncProgramm)
  328. }
  329. if options.Existing {
  330. arguments = append(arguments, "--existing")
  331. }
  332. if options.IgnoreExisting {
  333. arguments = append(arguments, "--ignore-existing")
  334. }
  335. if options.RemoveSourceFiles {
  336. arguments = append(arguments, "--remove-source-files")
  337. }
  338. if options.Delete {
  339. arguments = append(arguments, "--delete")
  340. }
  341. if options.DeleteBefore {
  342. arguments = append(arguments, "--delete-before")
  343. }
  344. if options.DeleteDuring {
  345. arguments = append(arguments, "--delete-during")
  346. }
  347. if options.DeleteDelay {
  348. arguments = append(arguments, "--delete-delay")
  349. }
  350. if options.DeleteAfter {
  351. arguments = append(arguments, "--delete-after")
  352. }
  353. if options.DeleteExcluded {
  354. arguments = append(arguments, "--delete-excluded")
  355. }
  356. if options.IgnoreErrors {
  357. arguments = append(arguments, "--ignore-errors")
  358. }
  359. if options.Force {
  360. arguments = append(arguments, "--force")
  361. }
  362. if options.MaxDelete > 0 {
  363. arguments = append(arguments, "--max-delete", strconv.Itoa(options.MaxDelete))
  364. }
  365. if options.MaxSize > 0 {
  366. arguments = append(arguments, "--max-size", strconv.Itoa(options.MaxSize))
  367. }
  368. if options.MinSize > 0 {
  369. arguments = append(arguments, "--min-size", strconv.Itoa(options.MinSize))
  370. }
  371. if options.Partial {
  372. arguments = append(arguments, "--partial")
  373. }
  374. if options.PartialDir != "" {
  375. arguments = append(arguments, "--partial-dir", options.PartialDir)
  376. }
  377. if options.DelayUpdates {
  378. arguments = append(arguments, "--delay-updates")
  379. }
  380. if options.PruneEmptyDirs {
  381. arguments = append(arguments, "--prune-empty-dirs")
  382. }
  383. if options.NumericIDs {
  384. arguments = append(arguments, "--numeric-ids")
  385. }
  386. if options.Timeout > 0 {
  387. arguments = append(arguments, "--timeout", strconv.Itoa(options.Timeout))
  388. }
  389. if options.Contimeout > 0 {
  390. arguments = append(arguments, "--contimeout", strconv.Itoa(options.Contimeout))
  391. }
  392. if options.IgnoreTimes {
  393. arguments = append(arguments, "--ignore-times")
  394. }
  395. if options.SizeOnly {
  396. arguments = append(arguments, "--size-only")
  397. }
  398. if options.ModifyWindow {
  399. arguments = append(arguments, "--modify-window")
  400. }
  401. if options.TempDir != "" {
  402. arguments = append(arguments, "--temp-dir", options.TempDir)
  403. }
  404. if options.Fuzzy {
  405. arguments = append(arguments, "--fuzzy")
  406. }
  407. if options.CompareDest != "" {
  408. arguments = append(arguments, "--compare-dest", options.CompareDest)
  409. }
  410. if options.CopyDest != "" {
  411. arguments = append(arguments, "--copy-dest", options.CopyDest)
  412. }
  413. if options.LinkDest != "" {
  414. arguments = append(arguments, "--link-dest", options.LinkDest)
  415. }
  416. if options.Compress {
  417. arguments = append(arguments, "--compress")
  418. }
  419. if options.CompressLevel > 0 {
  420. arguments = append(arguments, "--compress-level", strconv.Itoa(options.CompressLevel))
  421. }
  422. if len(options.SkipCompress) > 0 {
  423. arguments = append(arguments, "--skip-compress", strings.Join(options.SkipCompress, ","))
  424. }
  425. if options.CVSExclude {
  426. arguments = append(arguments, "--cvs-exclude")
  427. }
  428. if options.Stats {
  429. arguments = append(arguments, "--stats")
  430. }
  431. if options.HumanReadable {
  432. arguments = append(arguments, "--human-readable")
  433. }
  434. if options.Progress {
  435. arguments = append(arguments, "--progress")
  436. }
  437. if options.IPv4 {
  438. arguments = append(arguments, "--ipv4")
  439. }
  440. if options.IPv6 {
  441. arguments = append(arguments, "--ipv6")
  442. }
  443. if options.Info != "" {
  444. arguments = append(arguments, "--info", options.Info)
  445. }
  446. if options.PasswordFile != "" {
  447. arguments = append(arguments, "--password-file", options.PasswordFile)
  448. }
  449. return arguments
  450. }
  451. func createDir(dir string) error {
  452. cmd := exec.Command("mkdir", "-p", dir)
  453. if err := cmd.Start(); err != nil {
  454. return err
  455. }
  456. return cmd.Wait()
  457. }
  458. func isExist(p string) bool {
  459. stat, err := os.Stat(p)
  460. return os.IsExist(err) && stat.IsDir()
  461. }