rsync_cron 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|