duplicati 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,22 +1,59 @@
1
1
  class Duplicati
2
2
  class Backup
3
- def initialize(opts={})
4
- @opts = opts
3
+ def initialize(opts)
4
+ @duplicati_path = opts[:duplicati_path]
5
+ @backup_paths = opts[:backup_paths] or raise ":backup_paths option is missing for backup!"
6
+ @backup_store_path = opts[:backup_store_path] or raise ":backup_store_path option is missing for backup!"
7
+ @backup_encryption_key = opts[:backup_encryption_key]
8
+ @inclusion_filters = opts[:inclusion_filters] || []
9
+ @exclusion_filters = opts[:exclusion_filters] || []
10
+ @log_path = opts[:log_path]
5
11
  end
6
12
 
7
13
  def command
8
- %Q["#{@opts[:duplicati_path]}" backup "#{(@opts[:backup_paths] || []).join(File::PATH_SEPARATOR)}" "#{@opts[:backup_store_path]}"
9
- --passphrase="#{@opts[:backup_encryption_key]}"
14
+ %Q["#{@duplicati_path}" backup "#{backup_paths}" "#{@backup_store_path}"
15
+ #{encryption_option}
16
+ #{inclusion_filters}
17
+ #{exclusion_filters}
10
18
  --auto-cleanup
11
19
  --full-if-older-than=1M
12
20
  --usn-policy=on
13
21
  --snapshot-policy=on
14
22
  --full-if-sourcefolder-changed
15
- 2>&1 1>> "#{@opts[:log_path]}" &&
23
+ 2>&1 1>> "#{@log_path}" &&
16
24
 
17
- "#{@opts[:duplicati_path]}" delete-all-but-n 5 "#{@opts[:backup_store_path]}"
25
+ "#{@duplicati_path}" delete-all-but-n 5 "#{@backup_store_path}"
18
26
  --force
19
- 2>&1 1>> "#{@opts[:log_path]}"]
27
+ 2>&1 1>> "#{@log_path}"]
28
+ end
29
+
30
+ private
31
+
32
+ def encryption_option
33
+ @backup_encryption_key ?
34
+ %Q[--passphrase="#{@backup_encryption_key}"] :
35
+ %Q[--no-encryption]
36
+ end
37
+
38
+ def backup_paths
39
+ @backup_paths.map do |path|
40
+ path = path.strip.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
41
+ Dir.glob(path.gsub(/\/$/, ""))
42
+ end.flatten.join(File::PATH_SEPARATOR)
43
+ end
44
+
45
+ def inclusion_filters
46
+ filters "include", @inclusion_filters
47
+ end
48
+
49
+ def exclusion_filters
50
+ filters "exclude", @exclusion_filters
51
+ end
52
+
53
+ def filters(type, filters)
54
+ filters.reduce([]) do |memo, filter|
55
+ memo << %Q[--#{type}-regexp="#{filter.source}"]
56
+ end.join(" ")
20
57
  end
21
58
  end
22
59
  end
@@ -1,3 +1,3 @@
1
1
  class Duplicati
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/duplicati.rb CHANGED
@@ -16,12 +16,20 @@ class Duplicati
16
16
  opts[:log_path] ||= "duplicati.log"
17
17
  opts[:duplicati_path] = duplicati_path(opts[:duplicati_path])
18
18
  opts[:notifications] ||= [Notification::Growl]
19
+ opts[:inclusion_filters] ||= [opts[:inclusion_filter]].compact
20
+ opts[:exclusion_filters] ||= [opts[:exclusion_filter]].compact
21
+
22
+ if !opts[:inclusion_filters].empty? && opts[:exclusion_filters].empty?
23
+ opts[:exclusion_filters] = [%r{.*[^\\/]}]
24
+ end
25
+
19
26
  @opts = opts
20
27
  end
21
28
 
22
29
  def backup
23
30
  execute Backup.new(
24
- options :duplicati_path, :backup_paths, :backup_store_path, :backup_encryption_key, :log_path
31
+ options :duplicati_path, :backup_paths, :backup_store_path,
32
+ :backup_encryption_key, :inclusion_filters, :exclusion_filters, :log_path
25
33
  ).command
26
34
  end
27
35
 
@@ -34,7 +42,9 @@ class Duplicati
34
42
 
35
43
  def execute(command)
36
44
  old_log_file_size = File.read(@opts[:log_path]).strip.size rescue 0
37
- @execution_success = system(format command) && File.read(@opts[:log_path]).strip.size > old_log_file_size
45
+ formatted_command = format command
46
+ puts formatted_command if $DEBUG
47
+ @execution_success = system(formatted_command) && File.read(@opts[:log_path]).strip.size > old_log_file_size
38
48
  notify
39
49
  end
40
50
 
@@ -1,15 +1,39 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Duplicati::Backup do
4
- it "#command" do
5
- Duplicati::Backup.new(
6
- :duplicati_path => "/bin/duplicati-commandline",
7
- :backup_paths => ["/foo/bar", "/baz/bar"],
8
- :backup_store_path => "file:///foo/backup",
9
- :backup_encryption_key => "secret",
10
- :log_path => "/zzz/output.log"
11
- ).command.should == %Q["/bin/duplicati-commandline" backup "/foo/bar#{File::PATH_SEPARATOR}/baz/bar" "file:///foo/backup"
4
+
5
+ context "#initialize" do
6
+
7
+ it "raises an Exception if backup paths are not provided" do
8
+ expect {
9
+ Duplicati::Backup.new(:backup_store_path => "")
10
+ }.to raise_error(RuntimeError, ":backup_paths option is missing for backup!")
11
+ end
12
+
13
+ it "raises an Exception if backup store path is not provided" do
14
+ expect {
15
+ Duplicati::Backup.new(:backup_paths => [])
16
+ }.to raise_error(RuntimeError, ":backup_store_path option is missing for backup!")
17
+ end
18
+ end
19
+
20
+ context "#command" do
21
+
22
+ let(:basedir) { File.dirname(__FILE__) }
23
+
24
+ it "generates backup command for Duplicati using different options" do
25
+ Duplicati::Backup.new(
26
+ :duplicati_path => "/bin/duplicati-commandline",
27
+ :backup_paths => [basedir, File.join(basedir, "../")],
28
+ :backup_store_path => "file:///foo/backup",
29
+ :backup_encryption_key => "secret",
30
+ :inclusion_filters => [/include-me/],
31
+ :exclusion_filters => [/exclude-me/],
32
+ :log_path => "/zzz/output.log"
33
+ ).command.should == %Q["/bin/duplicati-commandline" backup "#{basedir}#{File::PATH_SEPARATOR}#{File.join(basedir, "../").chop}" "file:///foo/backup"
12
34
  --passphrase="secret"
35
+ --include-regexp="include-me"
36
+ --exclude-regexp="exclude-me"
13
37
  --auto-cleanup
14
38
  --full-if-older-than=1M
15
39
  --usn-policy=on
@@ -20,5 +44,55 @@ describe Duplicati::Backup do
20
44
  "/bin/duplicati-commandline" delete-all-but-n 5 "file:///foo/backup"
21
45
  --force
22
46
  2>&1 1>> "/zzz/output.log"]
47
+ end
48
+
49
+ it "generates backup command for Duplicati without using any encryption when encryption key is not provided" do
50
+ command = Duplicati::Backup.new(:backup_paths => [], :backup_store_path => "", :inclusion_filters => [], :exclusion_filters => []).command
51
+ command.should include("--no-encryption")
52
+ command.should_not include("--passphrase")
53
+ end
54
+
55
+ it "works with globs for backup paths" do
56
+ Duplicati::Backup.new(:backup_paths => [File.join(basedir, "../*_helper*")], :backup_store_path => "", :inclusion_filters => [], :exclusion_filters => []).
57
+ command.split(" ")[2].should == "\"#{File.join(basedir, "../spec_helper.rb")}\""
58
+ end
59
+
60
+ it "ignores not-existing backup paths" do
61
+ Duplicati::Backup.new(:backup_paths => ["/foo/bar", basedir, "/baz/bar"], :backup_store_path => "", :inclusion_filters => [], :exclusion_filters => []).
62
+ command.split(" ")[2].should == "\"#{basedir}\""
63
+ end
64
+
65
+ it "works with inclusion filters" do
66
+ command_parts = Duplicati::Backup.new(:backup_paths => [], :backup_store_path => "", :inclusion_filters => [/a\.exe/, /b\.exe/]).
67
+ command.split(" ")
68
+
69
+ command_parts[5].should == "--include-regexp=\"a\\.exe\""
70
+ command_parts[6].should == "--include-regexp=\"b\\.exe\""
71
+ end
72
+
73
+ it "works with exclusion filters" do
74
+ command_parts = Duplicati::Backup.new(:backup_paths => [], :backup_store_path => "", :exclusion_filters => [/a\.exe/, /b\.exe/]).
75
+ command.split(" ")
76
+
77
+ command_parts[5].should == "--exclude-regexp=\"a\\.exe\""
78
+ command_parts[6].should == "--exclude-regexp=\"b\\.exe\""
79
+ end
80
+
81
+ it "works with inclusion and exclusion filters together" do
82
+ command_parts = Duplicati::Backup.new(:backup_paths => [], :backup_store_path => "", :inclusion_filters => [/a/, /b/], :exclusion_filters => [/c/, /d/]).
83
+ command.split(" ")
84
+
85
+ command_parts[5].should == "--include-regexp=\"a\""
86
+ command_parts[6].should == "--include-regexp=\"b\""
87
+ command_parts[7].should == "--exclude-regexp=\"c\""
88
+ command_parts[8].should == "--exclude-regexp=\"d\""
89
+ end
90
+
91
+ it "does not include filters into command when they're not specified" do
92
+ command = Duplicati::Backup.new(:backup_paths => [], :backup_store_path => "").command
93
+ command.should_not include("--include-regexp")
94
+ command.should_not include("--exclude-regexp")
95
+ end
96
+
23
97
  end
24
98
  end
@@ -40,12 +40,40 @@ describe Duplicati do
40
40
  Duplicati.new(:foo => true).opts[:foo].should be_true
41
41
  end
42
42
 
43
+ it "has no inclusion filters by default" do
44
+ Duplicati.new.opts[:inclusion_filters].should == []
45
+ end
46
+
47
+ it "allows to specify a single inclusion filter" do
48
+ Duplicati.new(:inclusion_filter => /aa/).opts[:inclusion_filters].should == [/aa/]
49
+ end
50
+
51
+ it "allows to specify multiple inclusion filters" do
52
+ Duplicati.new(:inclusion_filters => [/aa/, /bb/]).opts[:inclusion_filters].should == [/aa/, /bb/]
53
+ end
54
+
55
+ it "will set up an 'exclude all others files' exclusion filter automatically when inclusion filter is used" do
56
+ Duplicati.new(:inclusion_filter => /aa/).opts[:exclusion_filters].should == [%r{.*[^\\/]}]
57
+ end
58
+
59
+ it "has no exclusion filters by default" do
60
+ Duplicati.new.opts[:exclusion_filters].should == []
61
+ end
62
+
63
+ it "allows to specify a single exclusion filter" do
64
+ Duplicati.new(:exclusion_filter => /aa/).opts[:exclusion_filters].should == [/aa/]
65
+ end
66
+
67
+ it "allows to specify multiple exclusion filters" do
68
+ Duplicati.new(:exclusion_filters => [/aa/, /bb/]).opts[:exclusion_filters].should == [/aa/, /bb/]
69
+ end
70
+
43
71
  end
44
72
 
45
73
  context "#backup" do
46
74
  it "executes the backup command" do
47
75
  Duplicati::Backup.any_instance.should_receive(:command).and_return("backup command")
48
- duplicati = Duplicati.new
76
+ duplicati = Duplicati.new(:backup_paths => [], :backup_store_path => "")
49
77
  duplicati.should_receive(:execute).with("backup command")
50
78
 
51
79
  duplicati.backup
@@ -58,6 +86,8 @@ describe Duplicati do
58
86
  :backup_paths => ["foo", "bar"],
59
87
  :backup_encryption_key => "secret",
60
88
  :backup_store_path => "baz",
89
+ :inclusion_filters => [],
90
+ :exclusion_filters => [],
61
91
  :log_path => "tmp"
62
92
  }
63
93
  expected_formatted_options = options.dup
@@ -74,7 +104,7 @@ describe Duplicati do
74
104
  Duplicati::Backup.any_instance.should_receive(:command).and_return("backup command")
75
105
  Duplicati.any_instance.should_receive(:execute).with("backup command")
76
106
 
77
- Duplicati.backup
107
+ Duplicati.backup(:backup_paths => [], :backup_store_path => "")
78
108
  end
79
109
  end
80
110
 
data/spec/spec_helper.rb CHANGED
@@ -6,4 +6,5 @@ require "duplicati"
6
6
  RSpec.configure do |config|
7
7
  config.color = true
8
8
  config.order = :random
9
+ config.add_formatter :documentation
9
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duplicati
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-28 00:00:00.000000000 Z
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake