duplicati 0.0.1 → 0.0.2

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.
@@ -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