rsync_cron 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +22 -0
- data/README.md +43 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/rsync_cron +7 -0
- data/bin/setup +8 -0
- data/lib/rsync_cron/cli.rb +67 -0
- data/lib/rsync_cron/command.rb +34 -0
- data/lib/rsync_cron/cron.rb +51 -0
- data/lib/rsync_cron/host.rb +38 -0
- data/lib/rsync_cron/options.rb +38 -0
- data/lib/rsync_cron/scheduler.rb +17 -0
- data/lib/rsync_cron/version.rb +3 -0
- data/lib/rsync_cron.rb +2 -0
- data/rsync_cron.gemspec +24 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e873d38cb9348864b4a9ca645b6462f4491017e9
|
4
|
+
data.tar.gz: 296d2b7efe73ade8ddd131c5ea5082fe700ecaea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c379474c98d3291d6154ae3ff9be4c25e49be30e1c2fc141920caf6115177a38670f234ca215a2dbdaf64b1c3a47925ef41780e4547253cb9a555b528765f186
|
7
|
+
data.tar.gz: e0f51f2fb215b8a656cc8eec3e9fdba9f967e0f56780b17feb07a712c05c512feeaa710dac684ef1dceb41a0c91a865d1f7140b981f0bffedbd569822693abde
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rsync_cron (1.0.5)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
minitest (5.10.3)
|
10
|
+
rake (10.5.0)
|
11
|
+
|
12
|
+
PLATFORMS
|
13
|
+
ruby
|
14
|
+
|
15
|
+
DEPENDENCIES
|
16
|
+
bundler (~> 1.15)
|
17
|
+
minitest (~> 5.0)
|
18
|
+
rake (~> 10.0)
|
19
|
+
rsync_cron!
|
20
|
+
|
21
|
+
BUNDLED WITH
|
22
|
+
1.15.4
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
## Table of Contents
|
2
|
+
|
3
|
+
* [Scope](#scope)
|
4
|
+
* [Installation](#installation)
|
5
|
+
* [Usage](#usage)
|
6
|
+
|
7
|
+
# Scope
|
8
|
+
The scope of this gem is to wrap the `rsync` command and to trigger it via the `crontab` schedule.
|
9
|
+
|
10
|
+
# Installation
|
11
|
+
Install the gem from your shell:
|
12
|
+
```shell
|
13
|
+
gem install rsync_cron
|
14
|
+
```
|
15
|
+
|
16
|
+
# Usage
|
17
|
+
The gem comes with a CLI interface. You can print its help by:
|
18
|
+
```shell
|
19
|
+
rsync_cron -h
|
20
|
+
Usage: rsync_cron --cron=15,30 21 * * * --src=/ --dest=/tmp --log=/var/log/rsync.log
|
21
|
+
-c, --cron=CRON The cron string, i.e.: 15 21 * * *
|
22
|
+
-s, --src=SRC The rsync source, i.e. user@src.com:files
|
23
|
+
-d, --dest=DEST The rsync dest, i.e. user@dest.com:home/
|
24
|
+
-l, --log=LOG log command output to specified file
|
25
|
+
-p, --print Print crontab command without installing it
|
26
|
+
-k, --check Check src and dest before installing crontab
|
27
|
+
-h, --help Prints this help
|
28
|
+
```
|
29
|
+
|
30
|
+
## Default schedule
|
31
|
+
The `crontab` is scheduled one per day by default (at midnight).
|
32
|
+
You can specify a different schedule directly on the command line:
|
33
|
+
```shell
|
34
|
+
# run every sunday
|
35
|
+
rsync_cron --cron=* * * * 0 --src=user@src.com:files --dest=~/tmp
|
36
|
+
```
|
37
|
+
|
38
|
+
## Log to a file
|
39
|
+
It is possible to log the `rsync` output to a file:
|
40
|
+
```shell
|
41
|
+
rsync_cron --src=user@src.com:files --dest=~/tmp --log=./rsync.log
|
42
|
+
```
|
43
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "rsync_cron"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/rsync_cron
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "rsync_cron/host"
|
3
|
+
require "rsync_cron/command"
|
4
|
+
require "rsync_cron/scheduler"
|
5
|
+
require "rsync_cron/cron"
|
6
|
+
|
7
|
+
module RsyncCron
|
8
|
+
class CLI
|
9
|
+
SHELL = `which crontab`.strip
|
10
|
+
|
11
|
+
def initialize(args, io = STDOUT, shell = SHELL)
|
12
|
+
@args = args
|
13
|
+
@io = io
|
14
|
+
@cron = Cron.factory("* 0 * * *")
|
15
|
+
@shell = shell
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
parser.parse!(@args)
|
20
|
+
return @io.puts "specify valid src" unless @src
|
21
|
+
return @io.puts "specify valid dest" unless @dest
|
22
|
+
command = Command.new(src: @src, dest: @dest, log: @log, io: @io)
|
23
|
+
return unless command.valid? if @check
|
24
|
+
crontab = "#{@cron} #{command}"
|
25
|
+
return @io.puts crontab unless @shell
|
26
|
+
Scheduler.new(crontab, @shell).call.tap do |res|
|
27
|
+
@io.puts "new crontab installed" if res
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private def parser
|
32
|
+
OptionParser.new do |opts|
|
33
|
+
opts.banner = "Usage: rsync_cron --cron=15,30 21 * * * --src=/ --dest=/tmp --log=/var/log/rsync.log"
|
34
|
+
|
35
|
+
opts.on("-cCRON", "--cron=CRON", "The cron string, i.e.: 15 21 * * *") do |cron|
|
36
|
+
@cron = Cron.factory(cron)
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-sSRC", "--src=SRC", "The rsync source, i.e. user@src.com:files") do |src|
|
40
|
+
@src = Host.factory(src)
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-dDEST", "--dest=DEST", "The rsync dest, i.e. user@dest.com:home/") do |dest|
|
44
|
+
@dest = Host.factory(dest)
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("-lLOG", "--log=LOG", "log command output to specified file") do |log|
|
48
|
+
@log = log
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-p", "--print", "Print crontab command without installing it") do
|
52
|
+
@shell = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-k", "--check", "Check src and dest before installing crontab") do
|
56
|
+
@check = true
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("-h", "--help", "Prints this help") do
|
60
|
+
@io.puts opts
|
61
|
+
exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "rsync_cron/options"
|
2
|
+
|
3
|
+
module RsyncCron
|
4
|
+
class Command
|
5
|
+
NAME = `which rsync`.strip
|
6
|
+
|
7
|
+
def initialize(src:, dest:, options: Options.new, name: NAME, log: nil, io: STDOUT)
|
8
|
+
@src = src
|
9
|
+
@dest = dest
|
10
|
+
@options = options
|
11
|
+
@name = name
|
12
|
+
@log = log
|
13
|
+
@io = io
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
return "echo 'rsync not installed'" if @name.empty?
|
18
|
+
"#{@name} #{@options} #{@src} #{@dest}#{log}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
[@src, @dest].all? do |host|
|
23
|
+
host.exist?.tap do |check|
|
24
|
+
@io.puts "#{host} does not exist" unless check
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private def log
|
30
|
+
return unless @log
|
31
|
+
" >> #{File.expand_path(@log)} 2>&1"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RsyncCron
|
2
|
+
class Cron
|
3
|
+
ANY = "*"
|
4
|
+
|
5
|
+
def self.factory(s)
|
6
|
+
mins, hour, day, month, week = s.split(" ")
|
7
|
+
mins = mins.split(",")
|
8
|
+
new(mins: mins, hour: hour, day: day, month: month, week: week)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(mins: nil, hour: nil, day: nil, month: nil, week: nil)
|
12
|
+
@mins = mins.to_a
|
13
|
+
@hour = hour
|
14
|
+
@day = day
|
15
|
+
@month = month
|
16
|
+
@week = week
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{mins} #{hour} #{day} #{month} #{week}"
|
21
|
+
end
|
22
|
+
|
23
|
+
private def mins
|
24
|
+
return ANY if @mins.empty?
|
25
|
+
return ANY unless @mins.all? { |min| (0..59) === min.to_i }
|
26
|
+
@mins.join(",")
|
27
|
+
end
|
28
|
+
|
29
|
+
private def hour
|
30
|
+
return ANY if @hour == ANY || @hour.nil?
|
31
|
+
return ANY unless (0..23) === @hour.to_i
|
32
|
+
@hour
|
33
|
+
end
|
34
|
+
|
35
|
+
private def day
|
36
|
+
return ANY unless (1..31) === @day.to_i
|
37
|
+
@day
|
38
|
+
end
|
39
|
+
|
40
|
+
private def month
|
41
|
+
return ANY unless (1..12) === @month.to_i
|
42
|
+
@month
|
43
|
+
end
|
44
|
+
|
45
|
+
private def week
|
46
|
+
return ANY if @week == ANY || @week.nil?
|
47
|
+
return ANY unless (0..7) === @week.to_i
|
48
|
+
@week
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RsyncCron
|
2
|
+
class Host
|
3
|
+
def self.factory(s)
|
4
|
+
return new(path: s) unless s.index(":")
|
5
|
+
remote, path = s.split(":")
|
6
|
+
new(path: path, remote: remote)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(path:, remote: nil)
|
10
|
+
@path = path
|
11
|
+
@remote = remote
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
[remote, path].compact.join(":")
|
16
|
+
end
|
17
|
+
|
18
|
+
def exist?
|
19
|
+
return FileTest.exist?(path) unless remote?
|
20
|
+
%x[ssh #{remote} "test -e #{path}"]
|
21
|
+
$?.exitstatus.zero?
|
22
|
+
end
|
23
|
+
|
24
|
+
private def path
|
25
|
+
return @path if remote?
|
26
|
+
File.expand_path(@path)
|
27
|
+
end
|
28
|
+
|
29
|
+
private def remote
|
30
|
+
return unless remote?
|
31
|
+
@remote
|
32
|
+
end
|
33
|
+
|
34
|
+
private def remote?
|
35
|
+
@remote
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RsyncCron
|
2
|
+
class Options
|
3
|
+
BANDWITH_LIMIT = 5*1024
|
4
|
+
DEFAULT = {
|
5
|
+
rsh: "ssh",
|
6
|
+
bwlimit: BANDWITH_LIMIT,
|
7
|
+
exclude: "'DfsrPrivate'"
|
8
|
+
}
|
9
|
+
FLAGS = %w[v r t z p L]
|
10
|
+
|
11
|
+
def initialize(data: DEFAULT, flags: FLAGS)
|
12
|
+
@data = data.to_h
|
13
|
+
@flags = flags.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
[flags, data].compact.join(" ")
|
18
|
+
end
|
19
|
+
|
20
|
+
def merge(opt)
|
21
|
+
@data = @data.merge(opt)
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
private def flags
|
26
|
+
return if @flags.empty?
|
27
|
+
"-#{@flags.join}"
|
28
|
+
end
|
29
|
+
|
30
|
+
private def data
|
31
|
+
return if @data.empty?
|
32
|
+
@data.reduce([]) do |acc, (opt, val)|
|
33
|
+
acc << "--#{opt}=#{val}"
|
34
|
+
end.join(" ")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RsyncCron
|
2
|
+
class Scheduler
|
3
|
+
def initialize(content, shell)
|
4
|
+
@content = content
|
5
|
+
@shell = shell
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
return if @shell.empty?
|
10
|
+
IO.popen(@shell, "r+") do |pipe|
|
11
|
+
pipe.puts(@content)
|
12
|
+
pipe.close_write
|
13
|
+
end
|
14
|
+
$?.exitstatus.zero?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/rsync_cron.rb
ADDED
data/rsync_cron.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "rsync_cron/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "rsync_cron"
|
8
|
+
s.version = RsyncCron::VERSION
|
9
|
+
s.authors = ["costajob"]
|
10
|
+
s.email = ["costajob@gmail.com"]
|
11
|
+
s.summary = "Simple wrapper around rsync, enabled by crontab"
|
12
|
+
s.homepage = "https://github.com/costajob/rsync_cron"
|
13
|
+
s.license = "MIT"
|
14
|
+
s.required_ruby_version = ">= 2.1.8"
|
15
|
+
|
16
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
s.bindir = "bin"
|
18
|
+
s.executables << "rsync_cron"
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "bundler", "~> 1.15"
|
22
|
+
s.add_development_dependency "rake", "~> 10.0"
|
23
|
+
s.add_development_dependency "minitest", "~> 5.0"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rsync_cron
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- costajob
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- costajob@gmail.com
|
58
|
+
executables:
|
59
|
+
- rsync_cron
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".travis.yml"
|
64
|
+
- Gemfile
|
65
|
+
- Gemfile.lock
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/console
|
69
|
+
- bin/rsync_cron
|
70
|
+
- bin/setup
|
71
|
+
- lib/rsync_cron.rb
|
72
|
+
- lib/rsync_cron/cli.rb
|
73
|
+
- lib/rsync_cron/command.rb
|
74
|
+
- lib/rsync_cron/cron.rb
|
75
|
+
- lib/rsync_cron/host.rb
|
76
|
+
- lib/rsync_cron/options.rb
|
77
|
+
- lib/rsync_cron/scheduler.rb
|
78
|
+
- lib/rsync_cron/version.rb
|
79
|
+
- rsync_cron.gemspec
|
80
|
+
homepage: https://github.com/costajob/rsync_cron
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.1.8
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.6.11
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: Simple wrapper around rsync, enabled by crontab
|
104
|
+
test_files: []
|