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 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
@@ -0,0 +1,7 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.8
5
+ - 2.2.1
6
+ - 2.4.1
7
+ before_install: gem install bundler -v 1.15.4
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in rsync_cron.gemspec
6
+ gemspec
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
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << "spec"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["spec/**/*_spec.rb"]
8
+ end
9
+
10
+ task :default => :spec
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
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.expand_path("../../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require "rsync_cron"
6
+
7
+ RsyncCron::CLI.new(ARGV.clone).call
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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
@@ -0,0 +1,3 @@
1
+ module RsyncCron
2
+ VERSION = "1.0.5"
3
+ end
data/lib/rsync_cron.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "rsync_cron/version"
2
+ require "rsync_cron/cli"
@@ -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: []