synco 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c010b88d796296e7d601db57d7668bea27452bf4
4
- data.tar.gz: 38defa9392d35ccdf751bf407a003492447ba8fc
2
+ SHA256:
3
+ metadata.gz: 5836163e56294236c873d3ed73f1f10ae20f164db3339118a3477831e9551f2d
4
+ data.tar.gz: 59f01018eaa9cd7bb703efc6f4f23c2c0b2eadc89d031482decf15398417d8cd
5
5
  SHA512:
6
- metadata.gz: 48ced35efeb57e29b8f9e063f171f08af459e58aa1d9f12f16edd59c5dee5b015e6820549ba646e2235b24153d3f46e7ee542377723a489861e0b3f71193febe
7
- data.tar.gz: 7868549488bc957338966e87f1d676e70e064012f47060c6e057fbab3bef12d71206b052cad4431a308bb7c81b452136ab125d9dd8d333b6fbeff39b0efc6641
6
+ metadata.gz: 42ec3e6db31d1d9c723509c200a36b41db10a95023374d9a6506704c344e8306090680c1524c08f400a78967f067085e24fb90aaa8dd4fe1014a97a4eb664d32
7
+ data.tar.gz: 92577fbd8cde9a481648fffeca5301401e19353fc5d85149e6b19eb8590811093f1f7ba9fd3ccb0c96fa960ab6af4457dd48d62269c53eb184366484985225f7
@@ -0,0 +1,40 @@
1
+ name: Development
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ os: [ubuntu-latest, macos-latest]
11
+ ruby: [2.3, 2.4, 2.5, 2.6, 2.7]
12
+ runs-on: ${{matrix.os}}
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+
16
+ - uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{matrix.ruby}}
19
+
20
+ - uses: actions/cache@v1
21
+ with:
22
+ path: vendor/bundle
23
+ key: bundle-use-ruby-${{matrix.os}}-${{matrix.ruby}}-${{hashFiles('**/Gemfile')}}
24
+ restore-keys: |
25
+ bundle-use-ruby-${{matrix.os}}-${{matrix.ruby}}-
26
+
27
+ - name: Installing packages (ubuntu)
28
+ if: matrix.os == 'ubuntu-latest'
29
+ run: sudo apt-get install rsync
30
+
31
+ - name: Installing packages (macos)
32
+ if: matrix.os == 'macos-latest'
33
+ run: brew install rsync
34
+
35
+ - name: Bundle install...
36
+ run: |
37
+ bundle config path vendor/bundle
38
+ bundle install
39
+
40
+ - run: bundle exec rake
data/.rspec CHANGED
@@ -1,4 +1,4 @@
1
- --color
2
1
  --format documentation
3
2
  --backtrace
3
+ --require spec_helper
4
4
  --warnings
data/Gemfile CHANGED
@@ -4,8 +4,5 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  group :test do
7
- gem 'simplecov'
8
- gem 'coveralls', require: false
9
-
10
7
  gem 'fssm'
11
8
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Synco
1
+ # Synco ![Development](https://github.com/ioquatix/synco/workflows/Development/badge.svg)
2
2
 
3
3
  Synco is a tool for scripted synchronization and backups. It provides a custom Ruby DSL for describing backup and synchronization tasks involving one more more system and disk. It is designed to provide flexibility while reducing the complexity multi-server backups.
4
4
 
@@ -8,10 +8,6 @@ Synco is a tool for scripted synchronization and backups. It provides a custom R
8
8
  * Backup verification using [Fingerprint](https://github.com/ioquatix/fingerprint).
9
9
  * Data backup redundancy controlled via DNS.
10
10
 
11
- [![Build Status](https://secure.travis-ci.org/ioquatix/synco.svg)](http://travis-ci.org/ioquatix/synco)
12
- [![Code Climate](https://codeclimate.com/github/ioquatix/synco.svg)](https://codeclimate.com/github/ioquatix/synco)
13
- [![Coverage Status](https://coveralls.io/repos/ioquatix/synco/badge.svg)](https://coveralls.io/r/ioquatix/synco)
14
-
15
11
  ## Installation
16
12
 
17
13
  Add this line to your application's Gemfile:
@@ -32,28 +28,30 @@ Synco imposes a particular structure regarding the organisation of backup script
32
28
 
33
29
  A simple backup script might look something like this:
34
30
 
35
- #!/usr/bin/env ruby
36
-
37
- require 'synco'
38
- require 'synco/methods/rsync'
39
-
40
- Synco::run_script do |script|
41
- script.method = Synco::Methods::RSync.new(archive: true)
42
-
43
- server(:master) do |server|
44
- server.host = "server.example.com"
45
- server.root = "/"
46
- end
47
-
48
- server(:backup) do |server|
49
- server.host = "backup.example.com"
50
- server.root = "/tank/backups/server.example.com"
51
- end
52
-
53
- backup('etc', 'var', 'srv', 'home',
54
- arguments: %W{--exclude cache/ --exclude tmp/}
55
- )
31
+ ```ruby
32
+ #!/usr/bin/env ruby
33
+
34
+ require 'synco'
35
+ require 'synco/methods/rsync'
36
+
37
+ Synco::run_script do |script|
38
+ script.method = Synco::Methods::RSync.new(archive: true)
39
+
40
+ server(:master) do |server|
41
+ server.host = "server.example.com"
42
+ server.root = "/"
43
+ end
44
+
45
+ server(:backup) do |server|
46
+ server.host = "backup.example.com"
47
+ server.root = "/tank/backups/server.example.com"
56
48
  end
49
+
50
+ backup('etc', 'var', 'srv', 'home',
51
+ arguments: %W{--exclude cache/ --exclude tmp/}
52
+ )
53
+ end
54
+ ```
57
55
 
58
56
  This will produce an identical copy using rsync of the specified directories. As an example `server.example.com:/etc` would be copied to `backup.example.com:/tank/backups/server.example.com/etc`.
59
57
 
@@ -61,61 +59,69 @@ This will produce an identical copy using rsync of the specified directories. As
61
59
 
62
60
  Building on the above backup, you can use `Synco::Methods::RSyncSnapshot` which supports snapshot based backups. It creates a snapshot into a sub-directory called `latest.snapshot` and uses RSync's `--link-dest` to hard-link files when unchanged. Synco provides scripts to rotate and prune these backups as required, but you must invoke them as part of the script:
63
61
 
64
- server(:backup) do |server|
65
- server.host = "backup.example.com"
66
- server.root = "/"
67
-
68
- server.on(:success) do
69
- run "synco", "rotate", chdir: target_server.root
70
- run "synco", "prune", chdir: target_server.root
71
- end
62
+ ```ruby
63
+ server(:backup) do |server|
64
+ server.host = "backup.example.com"
65
+ server.root = "/"
66
+
67
+ server.on(:success) do
68
+ run "synco", "rotate", chdir: target_server.root
69
+ run "synco", "prune", chdir: target_server.root
72
70
  end
71
+ end
72
+ ```
73
73
 
74
74
  These commands can also be run from the command line.
75
75
 
76
- rotate [--format <name>] [--latest <name>] [--snapshot <name>]
77
- Rotate a backup snapshot into a timestamped directory.
78
-
79
- [--format <name>] Set the name of the backup rotations, including strftime expansions. Default: %Y.%m.%d-%H.%M.%S
80
- [--latest <name>] The name of the latest backup symlink. Default: latest
81
- [--snapshot <name>] The name of the in-progress backup snapshot. Default: latest.snapshot
82
-
83
- prune [--hourly <count>] [--daily <count>] [--weekly <count>] [--monthly <count>] [--quarterly <count>] [--yearly <count>] [--format <name>] [--latest <name>] [--keep <new|old>] [--dry]
84
- Prune old backups to reduce disk usage according to a given policy.
85
-
86
- [--hourly <count>] Set the number of hourly backups to keep. Default: 24
87
- [--daily <count>] Set the number of daily backups to keep. Default: 28
88
- [--weekly <count>] Set the number of weekly backups to keep. Default: 52
89
- [--monthly <count>] Set the number of monthly backups to keep. Default: 36
90
- [--quarterly <count>] Set the number of quaterly backups to keep. Default: 40
91
- [--yearly <count>] Set the number of yearly backups to keep. Default: 20
92
- [--format <name>] Set the name of the backup rotations, including strftime expansions. Default: %Y.%m.%d-%H.%M.%S
93
- [--latest <name>] The name of the latest backup symlink. Default: latest
94
- [--keep <new|old>] Keep the younger or older backups within the same period division Default: old
95
- [--dry] Print out what would be done rather than doing it.
76
+ ```
77
+ rotate [--format <name>] [--latest <name>] [--snapshot <name>]
78
+ Rotate a backup snapshot into a timestamped directory.
79
+
80
+ [--format <name>] Set the name of the backup rotations, including strftime expansions. Default: %Y.%m.%d-%H.%M.%S
81
+ [--latest <name>] The name of the latest backup symlink. Default: latest
82
+ [--snapshot <name>] The name of the in-progress backup snapshot. Default: latest.snapshot
83
+
84
+ prune [--hourly <count>] [--daily <count>] [--weekly <count>] [--monthly <count>] [--quarterly <count>] [--yearly <count>] [--format <name>] [--latest <name>] [--keep <new|old>] [--dry]
85
+ Prune old backups to reduce disk usage according to a given policy.
86
+
87
+ [--hourly <count>] Set the number of hourly backups to keep. Default: 24
88
+ [--daily <count>] Set the number of daily backups to keep. Default: 28
89
+ [--weekly <count>] Set the number of weekly backups to keep. Default: 52
90
+ [--monthly <count>] Set the number of monthly backups to keep. Default: 36
91
+ [--quarterly <count>] Set the number of quaterly backups to keep. Default: 40
92
+ [--yearly <count>] Set the number of yearly backups to keep. Default: 20
93
+ [--format <name>] Set the name of the backup rotations, including strftime expansions. Default: %Y.%m.%d-%H.%M.%S
94
+ [--latest <name>] The name of the latest backup symlink. Default: latest
95
+ [--keep <new|old>] Keep the younger or older backups within the same period division Default: old
96
+ [--dry] Print out what would be done rather than doing it.
97
+ ```
96
98
 
97
99
  ### Mounting Disks
98
100
 
99
101
  Synco supports mounting disks before the backup begins and unmounting them after done. The specifics of this process may require some adjustment based on your OS. For example on linux, `sudo` is used to invoke `mount` and `umount`.
100
102
 
101
- server(:destination) do |server|
102
- self.mountpoint = '/mnt/backups'
103
- self.root = File.join(server.mountpoint, 'laptop')
104
-
105
- server.on(:prepare) do
106
- # synco mount uses labels, e.g. the disk partition has LABEL=backups
107
- target_server.run "synco", "mount", target_server.mountpoint, 'backups'
108
- end
109
-
110
- server.on(:finish) do
111
- target_server.run "synco", "unmount", target_server.mountpoint
112
- end
103
+ ```ruby
104
+ server(:destination) do |server|
105
+ self.mountpoint = '/mnt/backups'
106
+ self.root = File.join(server.mountpoint, 'laptop')
107
+
108
+ server.on(:prepare) do
109
+ # synco mount uses labels, e.g. the disk partition has LABEL=backups
110
+ target_server.run "synco", "mount", target_server.mountpoint, 'backups'
111
+ end
112
+
113
+ server.on(:finish) do
114
+ target_server.run "synco", "unmount", target_server.mountpoint
113
115
  end
116
+ end
117
+ ```
114
118
 
115
119
  On Linux, you might want to create the file `/etc/sudoers.d/synco` with the following contents:
116
120
 
117
- %wheel ALL=(root) NOPASSWD: /bin/mount
118
- %wheel ALL=(root) NOPASSWD: /bin/umount
121
+ ```
122
+ %wheel ALL=(root) NOPASSWD: /bin/mount
123
+ %wheel ALL=(root) NOPASSWD: /bin/umount
124
+ ```
119
125
 
120
126
  Please make sure you take the time to educate yourself on the security of such a setup.
121
127
 
@@ -123,47 +129,53 @@ Please make sure you take the time to educate yourself on the security of such a
123
129
 
124
130
  If you'd like to dump data before running the backup, it's possible using the event handling mechanisms:
125
131
 
126
- server(:master) do |server|
127
- server.host = "server.example.com"
128
- server.root = "/"
129
-
130
- server.on(:prepare) do
131
- # Dump MySQL to /srv/mysql
132
- run '/etc/lsync/mysql-backup.sh'
133
- end
132
+ ```ruby
133
+ server(:master) do |server|
134
+ server.host = "server.example.com"
135
+ server.root = "/"
136
+
137
+ server.on(:prepare) do
138
+ # Dump MySQL to /srv/mysql
139
+ run '/etc/lsync/mysql-backup.sh'
134
140
  end
141
+ end
142
+ ```
135
143
 
136
144
  The exact contents of `mysql-backup.sh` will depend on your requirements, but here is an example:
137
145
 
138
- #!/usr/bin/env bash
146
+ ```bash
147
+ #!/usr/bin/env bash
139
148
 
140
- BACKUP_DIR=/srv/mysql
141
- MYSQL=/usr/bin/mysql
142
- MYSQLDUMP=/usr/bin/mysqldump
143
-
144
- databases=`mysql --user=backup -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|_test|_restore)"`
145
-
146
- # http://stackoverflow.com/questions/451404/how-to-obtain-a-correct-dump-using-mysqldump-and-single-transaction-when-ddl-is
147
- MYSQLDUMP_OPTIONS="--force --skip-opt --single-transaction --add-drop-table --create-options --quick --extended-insert --set-charset --disable-keys"
148
-
149
- for db in $databases; do
150
- echo "Dumping database $db to $BACKUP_DIR/$db.sql.xz..."
151
- mysqldump --user=backup $MYSQLDUMP_OPTIONS --databases $db | xz > "$BACKUP_DIR/$db.sql.xz"
152
- done
149
+ BACKUP_DIR=/srv/mysql
150
+ MYSQL=/usr/bin/mysql
151
+ MYSQLDUMP=/usr/bin/mysqldump
152
+
153
+ databases=`mysql --user=backup -e "SHOW DATABASES;" | grep -Ev "(Database|information_schema|performance_schema|_test|_restore)"`
154
+
155
+ # http://stackoverflow.com/questions/451404/how-to-obtain-a-correct-dump-using-mysqldump-and-single-transaction-when-ddl-is
156
+ MYSQLDUMP_OPTIONS="--force --skip-opt --single-transaction --add-drop-table --create-options --quick --extended-insert --set-charset --disable-keys"
157
+
158
+ for db in $databases; do
159
+ echo "Dumping database $db to $BACKUP_DIR/$db.sql.xz..."
160
+ mysqldump --user=backup $MYSQLDUMP_OPTIONS --databases $db | xz > "$BACKUP_DIR/$db.sql.xz"
161
+ done
162
+ ```
153
163
 
154
164
  ### Fingerprint Integration
155
165
 
156
166
  It is possible to make a [cryptographic checksum of the data](https://github.com/ioquatix/fingerprint). On a filesystem that support immutable snapshots, you can do this before the data is copied. For traditional filesystems, you generally need to do this afterwards.
157
167
 
158
- server(:master) do |server|
159
- server.host = "server.example.com"
160
- server.root = "/"
161
-
162
- server.on(:success) do
163
- # Run fingerprint on the backup data:
164
- run 'fingerprint', '--root', target_server.root, 'analyze'
165
- end
168
+ ```ruby
169
+ server(:master) do |server|
170
+ server.host = "server.example.com"
171
+ server.root = "/"
172
+
173
+ server.on(:success) do
174
+ # Run fingerprint on the backup data:
175
+ run 'fingerprint', '--root', target_server.root, 'analyze'
166
176
  end
177
+ end
178
+ ```
167
179
 
168
180
  Fingerprint is used in many of the specs to verify file copies.
169
181
 
@@ -173,11 +185,15 @@ Fingerprint is used in many of the specs to verify file copies.
173
185
 
174
186
  Synco can manage synchronization and backups of ZFS partitions. However, to use the standard tools, it is necessary to enable `zfs_admin_snapshot`, in `/etc/modprobe.d/zfs.conf`:
175
187
 
176
- options zfs zfs_admin_snapshot=1
188
+ ```
189
+ options zfs zfs_admin_snapshot=1
190
+ ```
177
191
 
178
192
  Propagate user permissions for the ZFS partition:
179
193
 
180
- sudo zfs allow -ld -u `whoami` create,mount,send,receive,snapshot tank/test
194
+ ```bash
195
+ sudo zfs allow -ld -u `whoami` create,mount,send,receive,snapshot tank/test
196
+ ```
181
197
 
182
198
  ### Backup staging
183
199
 
@@ -193,23 +209,25 @@ Firstly, a backup script defaults to the server with the name `:master` as the m
193
209
 
194
210
  However, it is possible instead to specify a hostname, e.g. `primary.example.com`. Then, specify several servers, e.g. `s01.example.com`, `s02.example.com` and so on:
195
211
 
196
- Synco::run_script do |script|
197
- script.method = Synco::Methods::RSync.new(archive: true)
198
-
199
- script.master = "primary.example.com"
200
-
201
- server("s01.example.com") do |server|
202
- server.root = "/"
203
- end
204
-
205
- server("s02.example.com") do |server|
206
- server.root = "/"
207
- end
208
-
209
- backup('srv/http',
210
- arguments: %W{--exclude cache/ --exclude tmp/}
211
- )
212
+ ```ruby
213
+ Synco::run_script do |script|
214
+ script.method = Synco::Methods::RSync.new(archive: true)
215
+
216
+ script.master = "primary.example.com"
217
+
218
+ server("s01.example.com") do |server|
219
+ server.root = "/"
212
220
  end
221
+
222
+ server("s02.example.com") do |server|
223
+ server.root = "/"
224
+ end
225
+
226
+ backup('srv/http',
227
+ arguments: %W{--exclude cache/ --exclude tmp/}
228
+ )
229
+ end
230
+ ```
213
231
 
214
232
  When you run the script, the behaviour will depend on whether `primary.example.com` points to `s01.example.com` or `s02.example.com`. The data will always be copied from the master server to the other servers.
215
233
 
data/Rakefile CHANGED
@@ -1,8 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
3
 
4
- RSpec::Core::RakeTask.new(:spec) do |task|
5
- task.rspec_opts = ["--require", "simplecov"] if ENV['COVERAGE']
6
- end
4
+ RSpec::Core::RakeTask.new
7
5
 
8
6
  task :default => :spec
data/bin/synco CHANGED
@@ -26,5 +26,4 @@
26
26
 
27
27
  require 'synco/command'
28
28
 
29
- application = Synco::Command::Top.new(ARGV)
30
- application.invoke
29
+ Synco::Command::Top.call
@@ -48,21 +48,22 @@ module Synco
48
48
  end
49
49
  end
50
50
 
51
- nested '<command>',
51
+ nested :command, {
52
52
  'spawn' => Spawn,
53
53
  'rotate' => Rotate,
54
54
  'prune' => Prune,
55
55
  'mount' => Mount,
56
56
  'unmount' => Unmount
57
+ }
57
58
 
58
- def invoke(program_name: File.basename($0))
59
+ def call
59
60
  if @options[:version]
60
61
  puts "synco v#{Synco::VERSION}"
61
62
  elsif @options[:help] or @command.nil?
62
63
  print_usage(program_name)
63
64
  else
64
65
  chdir do
65
- @command.invoke(self)
66
+ @command.call
66
67
  end
67
68
  end
68
69
  end
@@ -34,7 +34,7 @@ module Synco
34
34
  one :path, "The disk mount point."
35
35
  one :name, "The symbolic name of the disk to mount, e.g. disk label."
36
36
 
37
- def invoke(parent)
37
+ def call
38
38
  # We may not have permission to make this directory, but we should still try:
39
39
  FileUtils.mkpath(@path) rescue nil
40
40
 
@@ -47,7 +47,7 @@ module Synco
47
47
 
48
48
  one :path, "The disk mount point."
49
49
 
50
- def invoke(parent)
50
+ def call
51
51
  Disk.unmount(@path)
52
52
  end
53
53
  end
@@ -138,7 +138,7 @@ module Synco
138
138
  end
139
139
  end
140
140
 
141
- def invoke(parent)
141
+ def call
142
142
  backups = current_backups
143
143
 
144
144
  retain, erase = policy.filter(backups, keep: @options[:keep].to_sym, &:time)
@@ -53,7 +53,7 @@ module Synco
53
53
  backup_timestamp.strftime(@options[:format])
54
54
  end
55
55
 
56
- def invoke(parent)
56
+ def call
57
57
  snapshot_name = @options[:snapshot]
58
58
  unless File.exist? snapshot_name
59
59
  $stderr.puts "Snapshot directory #{snapshot_name} does not exist!"
@@ -31,7 +31,7 @@ module Synco
31
31
 
32
32
  split :argv, "Command to spawn."
33
33
 
34
- def invoke(parent)
34
+ def call
35
35
  Process.exec(*@argv)
36
36
  end
37
37
  end
@@ -22,7 +22,7 @@ require_relative 'script'
22
22
 
23
23
  require 'process/group'
24
24
 
25
- require 'logger'
25
+ require 'console'
26
26
  require 'delegate'
27
27
 
28
28
  module Synco
@@ -39,22 +39,13 @@ module Synco
39
39
  end
40
40
 
41
41
  class Runner
42
- def initialize(*scripts, logger: nil, verbose: false)
42
+ include Console
43
+
44
+ def initialize(*scripts)
43
45
  @scripts = scripts
44
-
45
- @logger = logger || Logger.new($stderr).tap do |logger|
46
- logger.formatter = CompactFormatter.new
47
-
48
- if verbose or ENV['SYNCO_VERBOSE']
49
- logger.level = Logger::DEBUG
50
- else
51
- logger.level = Logger::INFO
52
- end
53
- end
54
46
  end
55
47
 
56
48
  attr :scripts
57
- attr :logger
58
49
 
59
50
  def call
60
51
  start_time = Time.now
@@ -64,7 +55,7 @@ module Synco
64
55
  Process::Group.wait do |group|
65
56
  @scripts.each do |script|
66
57
  Fiber.new do
67
- ScriptScope.new(script, @logger, group).call
58
+ ScriptScope.new(script, logger, group).call
68
59
  end.resume
69
60
  end
70
61
  end
@@ -23,8 +23,6 @@ require_relative 'server'
23
23
  require_relative 'directory'
24
24
  require_relative 'controller'
25
25
 
26
- require_relative 'compact_formatter'
27
-
28
26
  require 'socket'
29
27
 
30
28
  require 'process/group'
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Synco
22
- VERSION = "1.1.0"
22
+ VERSION = "1.2.0"
23
23
  end
@@ -0,0 +1,34 @@
1
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'bundler/setup'
22
+ require 'covered/rspec'
23
+
24
+ RSpec.configure do |config|
25
+ # Enable flags like --only-failures and --next-failure
26
+ config.example_status_persistence_file_path = ".rspec_status"
27
+
28
+ # Disable RSpec exposing methods globally on `Module` and `main`
29
+ config.disable_monkey_patching!
30
+
31
+ config.expect_with :rspec do |c|
32
+ c.syntax = :expect
33
+ end
34
+ end
@@ -22,7 +22,7 @@
22
22
 
23
23
  require 'synco/directory'
24
24
 
25
- describe Synco::Directory.new(".", arguments: ['--foo']) do
25
+ RSpec.describe Synco::Directory.new(".", arguments: ['--foo']) do
26
26
  it "should have arguments" do
27
27
  expect(subject.arguments).to include('--foo')
28
28
  end
@@ -25,7 +25,7 @@ require 'synco/methods/scp'
25
25
 
26
26
  require_relative 'backup_script'
27
27
 
28
- describe Synco::Methods::SCP do
28
+ RSpec.describe Synco::Methods::SCP do
29
29
  include_context "backup script"
30
30
 
31
31
  let(:test_server) {ENV.fetch('TEST_SERVER', 'localhost')}
@@ -27,7 +27,7 @@ require 'synco/methods/rsync'
27
27
 
28
28
  require_relative 'backup_script'
29
29
 
30
- describe Synco::Methods::RSync do
30
+ RSpec.describe Synco::Methods::RSync do
31
31
  include_context "backup script"
32
32
 
33
33
  it 'should copy files using rsync' do
@@ -81,7 +81,7 @@ describe Synco::Methods::RSync do
81
81
  end
82
82
  end
83
83
 
84
- describe Synco::Methods::RSyncSnapshot do
84
+ RSpec.describe Synco::Methods::RSyncSnapshot do
85
85
  it 'should generate correct command for ssh shell' do
86
86
  expect(subject.escape(['ssh', '-o', 'BatchMode=yes'])).to be == 'ssh -o BatchMode=yes'
87
87
  end
@@ -27,7 +27,7 @@ require 'synco/methods/scp'
27
27
 
28
28
  require_relative 'backup_script'
29
29
 
30
- describe Synco::Methods::SCP do
30
+ RSpec.describe Synco::Methods::SCP do
31
31
  include_context "backup script"
32
32
 
33
33
  it 'should build a script with desired configuration' do
@@ -24,7 +24,7 @@ require 'logger'
24
24
  require 'synco/script'
25
25
  require 'synco/methods/scp'
26
26
 
27
- describe Synco::Script do
27
+ RSpec.describe Synco::Script do
28
28
  it 'should build a script with desired configuration' do
29
29
  script = Synco::Script.build do |script|
30
30
  script.server(:master) do |server|
@@ -23,20 +23,18 @@
23
23
  require 'synco/server'
24
24
  require 'synco/shells/ssh'
25
25
 
26
- module Synco::ShellSpec
27
- describe Synco::Shells::SSH do
28
- let(:server) {Synco::Server.new('localhost')}
29
-
30
- it 'should generate a connection command' do
31
- expect(subject.connection_command(server)).to be == ['ssh', 'localhost']
32
- end
26
+ RSpec.describe Synco::Shells::SSH do
27
+ let(:server) {Synco::Server.new('localhost')}
28
+
29
+ it 'should generate a connection command' do
30
+ expect(subject.connection_command(server)).to be == ['ssh', 'localhost']
33
31
  end
32
+ end
33
+
34
+ RSpec.describe Synco::Shells::SSH.new(batch_mode: true) do
35
+ let(:server) {Synco::Server.new('localhost')}
34
36
 
35
- describe Synco::Shells::SSH.new(batch_mode: true) do
36
- let(:server) {Synco::Server.new('localhost')}
37
-
38
- it 'should generate a connection command with options' do
39
- expect(subject.connection_command(server)).to be == ['ssh', '-o', 'BatchMode=yes', 'localhost']
40
- end
37
+ it 'should generate a connection command with options' do
38
+ expect(subject.connection_command(server)).to be == ['ssh', '-o', 'BatchMode=yes', 'localhost']
41
39
  end
42
40
  end
@@ -24,7 +24,7 @@ require 'synco/disk'
24
24
  require 'synco/methods/rsync'
25
25
  require_relative 'backup_script'
26
26
 
27
- describe Synco::Methods::RSyncSnapshot, if: Synco::Disk.available?('TEST') do
27
+ RSpec.describe Synco::Methods::RSyncSnapshot, if: Synco::Disk.available?('TEST') do
28
28
  include_context "backup script"
29
29
 
30
30
  before(:each) do
@@ -25,7 +25,7 @@ require 'synco/script'
25
25
  require 'synco/scope'
26
26
  require 'synco/methods/zfs'
27
27
 
28
- describe Synco::Methods::ZFS do
28
+ RSpec.describe Synco::Methods::ZFS do
29
29
  xit 'should mirror two ZFS partitions' do
30
30
  script = Synco::Script.build(master: :source) do |script|
31
31
  script.method = Synco::Methods::ZFS.new
@@ -1,7 +1,5 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'synco/version'
1
+
2
+ require_relative 'lib/synco/version'
5
3
 
6
4
  Gem::Specification.new do |spec|
7
5
  spec.name = "synco"
@@ -11,25 +9,23 @@ Gem::Specification.new do |spec|
11
9
  spec.summary = %q{Synco is a tool for scripted synchronization and backups.}
12
10
  spec.homepage = ""
13
11
  spec.license = "MIT"
14
-
12
+
15
13
  spec.files = `git ls-files -z`.split("\x0")
16
14
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
15
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
16
  spec.require_paths = ["lib"]
19
-
17
+
20
18
  spec.add_dependency("periodical", "~> 1.1")
21
- spec.add_dependency("samovar", "~> 1.3")
22
- spec.add_dependency("fingerprint", "~> 2.0")
19
+ spec.add_dependency("samovar", "~> 2.0")
20
+ spec.add_dependency("fingerprint", "~> 3.0")
23
21
  spec.add_dependency("mapping", "~> 1.0")
24
22
  spec.add_dependency("build-files", "~> 1.0")
25
23
  spec.add_dependency("process-group", "~> 1.1")
26
24
 
27
25
  spec.add_dependency("lockfile")
28
- spec.add_dependency("rainbow", "~> 2.0")
29
-
30
- spec.has_rdoc = "yard"
31
-
32
- spec.add_development_dependency "bundler", "~> 1.11"
26
+
27
+ spec.add_development_dependency "covered"
28
+ spec.add_development_dependency "bundler"
33
29
  spec.add_development_dependency "rspec", "~> 3.4"
34
30
  spec.add_development_dependency "rake"
35
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synco
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-27 00:00:00.000000000 Z
11
+ date: 2020-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: periodical
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.3'
33
+ version: '2.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.3'
40
+ version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: fingerprint
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.0'
47
+ version: '3.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.0'
54
+ version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: mapping
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -109,33 +109,33 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rainbow
112
+ name: covered
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '2.0'
118
- type: :runtime
117
+ version: '0'
118
+ type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: '2.0'
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: bundler
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - "~>"
129
+ - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: '1.11'
131
+ version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - ">="
137
137
  - !ruby/object:Gem::Version
138
- version: '1.11'
138
+ version: '0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rspec
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -172,10 +172,9 @@ executables:
172
172
  extensions: []
173
173
  extra_rdoc_files: []
174
174
  files:
175
+ - ".github/workflows/development.yml"
175
176
  - ".gitignore"
176
177
  - ".rspec"
177
- - ".simplecov"
178
- - ".travis.yml"
179
178
  - Gemfile
180
179
  - README.md
181
180
  - Rakefile
@@ -186,7 +185,6 @@ files:
186
185
  - lib/synco/command/prune.rb
187
186
  - lib/synco/command/rotate.rb
188
187
  - lib/synco/command/spawn.rb
189
- - lib/synco/compact_formatter.rb
190
188
  - lib/synco/controller.rb
191
189
  - lib/synco/directory.rb
192
190
  - lib/synco/disk.rb
@@ -200,10 +198,7 @@ files:
200
198
  - lib/synco/shell.rb
201
199
  - lib/synco/shells/ssh.rb
202
200
  - lib/synco/version.rb
203
- - media/LSync Logo.artx/Preview/preview.png
204
- - media/LSync Logo.artx/QuickLook/Preview.pdf
205
- - media/LSync Logo.artx/doc.thread
206
- - media/LSync Logo.png
201
+ - spec/spec_helper.rb
207
202
  - spec/synco/backup_script.rb
208
203
  - spec/synco/directory_spec.rb
209
204
  - spec/synco/local_backup.rb
@@ -235,12 +230,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
230
  - !ruby/object:Gem::Version
236
231
  version: '0'
237
232
  requirements: []
238
- rubyforge_project:
239
- rubygems_version: 2.5.1
233
+ rubygems_version: 3.0.6
240
234
  signing_key:
241
235
  specification_version: 4
242
236
  summary: Synco is a tool for scripted synchronization and backups.
243
237
  test_files:
238
+ - spec/spec_helper.rb
244
239
  - spec/synco/backup_script.rb
245
240
  - spec/synco/directory_spec.rb
246
241
  - spec/synco/local_backup.rb
data/.simplecov DELETED
@@ -1,9 +0,0 @@
1
-
2
- SimpleCov.start do
3
- add_filter "/spec/"
4
- end
5
-
6
- if ENV['TRAVIS']
7
- require 'coveralls'
8
- Coveralls.wear!
9
- end
@@ -1,14 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- rvm:
4
- - 2.1.8
5
- - 2.2.4
6
- - 2.3.0
7
- - ruby-head
8
- - rbx-2
9
- env: COVERAGE=true
10
- matrix:
11
- fast_finish: true
12
- allow_failures:
13
- - rvm: "ruby-head"
14
- - rvm: "rbx-2"
@@ -1,115 +0,0 @@
1
- # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'rainbow'
22
- require 'shellwords'
23
-
24
- module Synco
25
- class CompactFormatter
26
- def initialize(verbose: true)
27
- @start = Time.now
28
- @verbose = verbose
29
- end
30
-
31
- def time_offset_prefix
32
- offset = Time.now - @start
33
- minutes = (offset/60).floor
34
- seconds = (offset - (minutes*60))
35
-
36
- if minutes > 0
37
- "#{minutes}m#{seconds.floor}s"
38
- else
39
- "#{seconds.round(2)}s"
40
- end.rjust(6)
41
- end
42
-
43
- def chdir_string(options)
44
- if options[:chdir]
45
- " in #{options[:chdir]}"
46
- else
47
- ""
48
- end
49
- end
50
-
51
- def format_command(arguments, buffer)
52
- arguments = arguments.dup
53
-
54
- # environment = arguments.first.is_a?(Hash) ? arguments.shift : nil
55
- options = arguments.last.is_a?(Hash) ? arguments.pop : nil
56
-
57
- arguments = arguments.flatten.collect(&:to_s)
58
-
59
- buffer << Rainbow(arguments.shelljoin).bright.blue
60
-
61
- if options
62
- buffer << chdir_string(options)
63
- end
64
-
65
- buffer << "\n"
66
-
67
- # if environment
68
- # environment.each do |key,value|
69
- # buffer << "\texport #{key}=#{value.dump}\n"
70
- # end
71
- # end
72
- end
73
-
74
- def format_exception(exception, buffer)
75
- buffer << Rainbow("#{exception.class}: #{exception}").bright.red << "\n"
76
- exception.backtrace.each do |line|
77
- buffer << "\t" << Rainbow(line).red << "\n"
78
- end
79
- end
80
-
81
- def format_line(message, severity)
82
- if severity == 'ERROR'
83
- Rainbow(message).red
84
- else
85
- message
86
- end
87
- end
88
-
89
- def call(severity, datetime, progname, message)
90
- buffer = []
91
- prefix = ""
92
-
93
- if @verbose
94
- prefix = time_offset_prefix
95
- buffer << Rainbow(prefix).cyan + ": "
96
- prefix = " " * (prefix.size) + "| "
97
- end
98
-
99
- if progname == 'shell' and message.kind_of? Array
100
- format_command(message, buffer)
101
- elsif message.kind_of? Exception
102
- format_exception(message, buffer)
103
- else
104
- buffer << format_line(message, severity) << "\n"
105
- end
106
-
107
- result = buffer.join
108
-
109
- # This fancy regex indents lines correctly depending on the prefix:
110
- result.gsub!(/\n(?!$)/, "\n#{prefix}") unless prefix.empty?
111
-
112
- return result
113
- end
114
- end
115
- end
Binary file