snapsync 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +2 -1
- data/install.sh +2 -2
- data/lib/snapsync/cli.rb +91 -20
- data/lib/snapsync/exceptions.rb +2 -0
- data/lib/snapsync/local_target.rb +38 -10
- data/lib/snapsync/test.rb +1 -1
- data/lib/snapsync/timeline_sync_policy.rb +4 -1
- data/lib/snapsync/version.rb +1 -1
- data/snapsync.gemspec +2 -1
- metadata +20 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6537d4331f2602702b307130fda024bdab894efa
|
4
|
+
data.tar.gz: ee06446c1c840e41217616528ec5ac10e29db0cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a128cafd4224ebac10c98d333e90c3fee57812d19e9c57f5460b626d7008c302e28f7b3730d1b0535ae3f8230d80578f1020a0d0f926071ddd5de2d861526c63
|
7
|
+
data.tar.gz: 32cb9bb06f3340f10f7b2087ee4eb63a8f4411f7c421155420c7b1b264b03f6118e25fb93c05d95d7b2cd1e7bc307fa36b03b6801347ba0b5536e8effb241f47
|
data/Rakefile
CHANGED
data/install.sh
CHANGED
@@ -10,8 +10,9 @@ GEMFILE
|
|
10
10
|
bundler install --standalone --binstubs
|
11
11
|
if test -d /opt/snapsync; then
|
12
12
|
sudo rm -rf /opt/snapsync
|
13
|
-
sudo cp -r . /opt/snapsync
|
14
13
|
fi
|
14
|
+
sudo cp -r . /opt/snapsync
|
15
|
+
sudo chmod go+rX /opt/snapsync
|
15
16
|
|
16
17
|
if test -d /lib/systemd/system; then
|
17
18
|
snapsync_gem=`bundler show snapsync`
|
@@ -22,4 +23,3 @@ if test -d /lib/systemd/system; then
|
|
22
23
|
fi
|
23
24
|
|
24
25
|
rm -rf $target
|
25
|
-
|
data/lib/snapsync/cli.rb
CHANGED
@@ -52,6 +52,11 @@ module Snapsync
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
def partition_of(dir)
|
57
|
+
partitions = PartitionsMonitor.new
|
58
|
+
PartitionsMonitor.new.partition_of(dir)
|
59
|
+
end
|
55
60
|
end
|
56
61
|
|
57
62
|
desc 'sync CONFIG DIR', 'synchronizes the snapper configuration CONFIG with the snapsync target DIR'
|
@@ -91,8 +96,27 @@ module Snapsync
|
|
91
96
|
end
|
92
97
|
end
|
93
98
|
|
94
|
-
|
99
|
+
no_commands do
|
100
|
+
def normalize_policy(args)
|
101
|
+
policy =
|
102
|
+
if args.empty?
|
103
|
+
['default', Array.new]
|
104
|
+
elsif args.size == 1
|
105
|
+
args + [Array.new]
|
106
|
+
else
|
107
|
+
[args.shift, args]
|
108
|
+
end
|
109
|
+
|
110
|
+
LocalTarget.parse_policy(*policy)
|
111
|
+
return *policy
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
desc 'init [NAME] DIR [POLICY]', 'creates a synchronization target, optionally adding it to the auto-sync targets and specifying the synchronization and cleanup policies'
|
95
116
|
long_desc <<-EOD
|
117
|
+
NAME must be provided if DIR is to be added to the auto-sync targets (which
|
118
|
+
is the default).
|
119
|
+
|
96
120
|
By default, the default policy is used. To change this, provide additional
|
97
121
|
arguments as would be expected by the policy subcommand. Run snapsync help
|
98
122
|
policy for more information
|
@@ -103,13 +127,52 @@ policy for more information
|
|
103
127
|
desc: "if true (the default), add the newly created target to auto-sync"
|
104
128
|
option :automount, type: :boolean, default: true,
|
105
129
|
desc: 'whether the supporting partition should be auto-mounted by snapsync when needed or not (the default is yes). Only useful if --no-auto has not been provided on the command line.'
|
106
|
-
|
130
|
+
option :config_file, default: '/etc/snapsync.conf',
|
131
|
+
desc: 'the configuration file that should be updated'
|
132
|
+
def init(*args)
|
133
|
+
if options[:auto] && !options[:all]
|
134
|
+
raise ArgumentError, "cannot use --auto without --all"
|
135
|
+
end
|
136
|
+
|
137
|
+
if options[:auto]
|
138
|
+
if args.size < 2
|
139
|
+
self.class.handle_argument_error(self.class.all_commands['init'], nil, args, 2)
|
140
|
+
end
|
141
|
+
name, dir, *policy = *args
|
142
|
+
else
|
143
|
+
if args.size < 1
|
144
|
+
self.class.handle_argument_error(self.class.all_commands['init'], nil, args, 1)
|
145
|
+
end
|
146
|
+
dir, *policy = *args
|
147
|
+
end
|
107
148
|
dir = Pathname.new(dir)
|
108
149
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
150
|
+
# Parse the policy option early to avoid breaking later
|
151
|
+
begin
|
152
|
+
policy = normalize_policy(policy)
|
153
|
+
rescue Exception
|
154
|
+
# Try to see if the user forgot to add the NAME option or added
|
155
|
+
# the name option but should not have
|
156
|
+
if options[:auto]
|
157
|
+
valid_policy = begin normalize_policy(args[1..-1])
|
158
|
+
true
|
159
|
+
rescue InvalidConfiguration
|
160
|
+
false
|
161
|
+
end
|
162
|
+
if valid_policy
|
163
|
+
raise ArgumentError, "--auto is set but it seems that you did not provide a name"
|
164
|
+
end
|
165
|
+
else
|
166
|
+
valid_policy = begin normalize_policy(args[2..-1])
|
167
|
+
true
|
168
|
+
rescue InvalidConfiguration
|
169
|
+
false
|
170
|
+
end
|
171
|
+
if valid_policy
|
172
|
+
raise ArgumentError, "--auto is not set but it seems that you provided a name"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
raise ArgumentError, "invalid policy #{policy}"
|
113
176
|
end
|
114
177
|
|
115
178
|
dirs = Array.new
|
@@ -134,31 +197,39 @@ policy for more information
|
|
134
197
|
end
|
135
198
|
end
|
136
199
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
auto_add(name, dir)
|
142
|
-
end
|
200
|
+
# We check that both options are set together for some added safety,
|
201
|
+
# but it's checked at the top of the method
|
202
|
+
if options[:auto] && options[:all]
|
203
|
+
auto_add(name, dir)
|
143
204
|
end
|
144
205
|
end
|
145
206
|
|
146
207
|
desc 'auto-add NAME DIR', "add DIR to the set of targets for auto-sync"
|
147
208
|
option :automount, type: :boolean, default: true,
|
148
209
|
desc: 'whether the supporting partition should be auto-mounted by snapsync when needed or not (the default is yes)'
|
210
|
+
option :config_file, default: '/etc/snapsync.conf',
|
211
|
+
desc: 'the configuration file that should be updated'
|
149
212
|
def auto_add(name, dir)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
conf_path = Pathname.new('/etc/snapsync.conf')
|
213
|
+
uuid, relative = partition_of(Pathname.new(dir))
|
214
|
+
conf_path = Pathname.new(options[:config_file])
|
154
215
|
|
155
216
|
autosync = AutoSync.new
|
156
|
-
|
217
|
+
if conf_path.exist?
|
218
|
+
autosync.load_config(conf_path)
|
219
|
+
end
|
157
220
|
exists = autosync.each_autosync_target.find do |t|
|
158
221
|
t.partition_uuid == uuid && t.path.cleanpath == relative.cleanpath
|
159
222
|
end
|
160
223
|
if exists
|
161
|
-
if exists.
|
224
|
+
if !exists.name
|
225
|
+
if (exists.automount ^ options[:automount]) && name
|
226
|
+
Snapsync.info "already exists without a name, setting the name to #{name}"
|
227
|
+
elsif name
|
228
|
+
Snapsync.info "already exists without a name and a different automount flag, setting the name to #{name} and updating the automount flag"
|
229
|
+
else
|
230
|
+
Snapsync.info "already exists with different automount flag, updating"
|
231
|
+
end
|
232
|
+
elsif exists.automount == options[:automount]
|
162
233
|
Snapsync.info "already exists under the name #{exists.name}"
|
163
234
|
else
|
164
235
|
Snapsync.info "already exists under the name #{exists.name} but with a different automount flag, changing"
|
@@ -197,6 +268,8 @@ for 10 days). snapsync understands the following period names: year month day ho
|
|
197
268
|
EOD
|
198
269
|
def policy(dir, type, *options)
|
199
270
|
handle_class_options
|
271
|
+
# Parse the policy early to avoid breaking later
|
272
|
+
LocalTarget.parse_policy(*policy)
|
200
273
|
each_target(dir) do |_, target|
|
201
274
|
target.change_policy(type, options)
|
202
275
|
target.write_config
|
@@ -231,9 +304,7 @@ While it can easily be done manually, this command makes sure that the snapshots
|
|
231
304
|
desc 'list [DIR]', 'list the snapshots present on DIR. If DIR is omitted, tries to access all targets defined as auto-sync targets'
|
232
305
|
def list(dir = nil)
|
233
306
|
handle_class_options
|
234
|
-
matched_uuids = Set.new
|
235
307
|
each_target(dir) do |_, target|
|
236
|
-
matched_uuids << target.uuid
|
237
308
|
puts "== #{target.dir}"
|
238
309
|
puts "UUID: #{target.uuid}"
|
239
310
|
puts "Enabled: #{target.enabled?}"
|
data/lib/snapsync/exceptions.rb
CHANGED
@@ -5,4 +5,6 @@ module Snapsync
|
|
5
5
|
# Exception raised when a snapshot directory is given to {Snapshot} but
|
6
6
|
# snapshot_dir/info.xml does not look like a valid snapper info file.
|
7
7
|
class InvalidInfoFile < InvalidSnapshot; end
|
8
|
+
# Invalid configuration requested
|
9
|
+
class InvalidConfiguration < ArgumentError; end
|
8
10
|
end
|
@@ -75,14 +75,17 @@ module Snapsync
|
|
75
75
|
config['enabled'] = enabled?
|
76
76
|
config['autoclean'] = autoclean?
|
77
77
|
|
78
|
-
|
79
|
-
|
78
|
+
config_path.open('w') do |io|
|
79
|
+
YAML.dump(config, io)
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
83
|
def read_config
|
84
84
|
begin
|
85
|
-
raw_config = YAML.load(config_path.read)
|
85
|
+
if !(raw_config = YAML.load(config_path.read))
|
86
|
+
raise NoUUIDError, "empty configuration file found in #{config_path}"
|
87
|
+
end
|
88
|
+
|
86
89
|
rescue Errno::ENOENT => e
|
87
90
|
raise NoUUIDError, e.message, e.backtrace
|
88
91
|
end
|
@@ -113,26 +116,51 @@ module Snapsync
|
|
113
116
|
def config_path
|
114
117
|
dir + "snapsync.config"
|
115
118
|
end
|
116
|
-
|
117
|
-
|
119
|
+
|
120
|
+
# Parse a policy specification as provided on the command line or saved
|
121
|
+
# in the config file into sync and cleanup policy objects
|
122
|
+
#
|
123
|
+
# @param [String] type the policy type, either default, timeline or last
|
124
|
+
# @param [Array<String>] options to be passed to the #from_config method
|
125
|
+
# on the underlying policy classes
|
126
|
+
#
|
127
|
+
# @return [(#filter_snapshots,#filter_snapshots)] the sync policy
|
128
|
+
# and the cleanup policy. The cleanup policy might be nil
|
129
|
+
# @raise [InvalidConfiguration] if the policy type is unknown
|
130
|
+
# @see DefaultSyncPolicy TimelineSyncPolicy SyncLastPolicy
|
131
|
+
def self.parse_policy(type, options)
|
118
132
|
case type
|
119
133
|
when 'default'
|
120
134
|
sync_policy = DefaultSyncPolicy
|
121
|
-
cleanup
|
135
|
+
cleanup = nil
|
122
136
|
when 'timeline'
|
123
137
|
sync_policy = TimelineSyncPolicy
|
124
|
-
cleanup
|
138
|
+
cleanup = TimelineSyncPolicy
|
125
139
|
when 'last'
|
126
140
|
sync_policy = SyncLastPolicy
|
127
|
-
cleanup
|
141
|
+
cleanup = SyncLastPolicy
|
128
142
|
else
|
129
143
|
raise InvalidConfiguration, "synchronization policy #{type} does not exist"
|
130
144
|
end
|
131
|
-
|
132
|
-
|
145
|
+
sync_policy = sync_policy.from_config(options)
|
146
|
+
cleanup =
|
133
147
|
if cleanup
|
134
148
|
Cleanup.new(cleanup.from_config(options))
|
135
149
|
end
|
150
|
+
return sync_policy, cleanup
|
151
|
+
end
|
152
|
+
|
153
|
+
# Verifies that the given policy type and options are valid
|
154
|
+
def self.valid_policy?(type, options)
|
155
|
+
parse_policy(type, options)
|
156
|
+
true
|
157
|
+
rescue InvalidConfiguration
|
158
|
+
false
|
159
|
+
end
|
160
|
+
|
161
|
+
def change_policy(type, options)
|
162
|
+
@sync_policy, @cleanup =
|
163
|
+
self.class.parse_policy(type, options)
|
136
164
|
end
|
137
165
|
|
138
166
|
def delete(s, dry_run: false)
|
data/lib/snapsync/test.rb
CHANGED
@@ -19,7 +19,10 @@ module Snapsync
|
|
19
19
|
|
20
20
|
def parse_config(config)
|
21
21
|
config.each_slice(2) do |period, count|
|
22
|
-
add(period.to_sym, Integer(count))
|
22
|
+
begin add(period.to_sym, Integer(count))
|
23
|
+
rescue ArgumentError
|
24
|
+
raise InvalidConfiguration, "invalid timeline period or count #{period} #{count}"
|
25
|
+
end
|
23
26
|
end
|
24
27
|
end
|
25
28
|
|
data/lib/snapsync/version.rb
CHANGED
data/snapsync.gemspec
CHANGED
@@ -31,5 +31,6 @@ EOD
|
|
31
31
|
spec.add_development_dependency "bundler", "~> 1.10"
|
32
32
|
spec.add_development_dependency "rake", "~> 10.0"
|
33
33
|
spec.add_development_dependency "minitest", "~> 5.0", ">= 5.7"
|
34
|
-
spec.add_development_dependency "flexmock", "~>
|
34
|
+
spec.add_development_dependency "flexmock", "~> 2.0", ">= 2.0"
|
35
|
+
spec.add_development_dependency "fakefs"
|
35
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snapsync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Joyeux
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logging
|
@@ -144,20 +144,34 @@ dependencies:
|
|
144
144
|
requirements:
|
145
145
|
- - "~>"
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version: '
|
147
|
+
version: '2.0'
|
148
148
|
- - ">="
|
149
149
|
- !ruby/object:Gem::Version
|
150
|
-
version:
|
150
|
+
version: '2.0'
|
151
151
|
type: :development
|
152
152
|
prerelease: false
|
153
153
|
version_requirements: !ruby/object:Gem::Requirement
|
154
154
|
requirements:
|
155
155
|
- - "~>"
|
156
156
|
- !ruby/object:Gem::Version
|
157
|
-
version: '
|
157
|
+
version: '2.0'
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '2.0'
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: fakefs
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
type: :development
|
169
|
+
prerelease: false
|
170
|
+
version_requirements: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
158
172
|
- - ">="
|
159
173
|
- !ruby/object:Gem::Version
|
160
|
-
version:
|
174
|
+
version: '0'
|
161
175
|
description: |
|
162
176
|
Snapsync is a tool that automates transferring snapper snapshots to
|
163
177
|
external media (USB drives ...) and managing these snapshots (e.g.
|