revenc 0.1.3 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gemfiles +53 -0
  2. data/.gitignore +4 -8
  3. data/Gemfile.lock +42 -37
  4. data/HISTORY.markdown +9 -2
  5. data/LICENSE +1 -1
  6. data/README.markdown +33 -38
  7. data/Rakefile +24 -34
  8. data/TODO.markdown +3 -0
  9. data/VERSION +1 -1
  10. data/bin/revenc +30 -13
  11. data/config/cucumber.yml +4 -3
  12. data/examples/rsync/encrypted_data/key/encfs6.xml +27 -27
  13. data/examples/rsync/revenc.conf +2 -2
  14. data/examples/simple/encfs6.xml +27 -27
  15. data/features/app.feature +17 -17
  16. data/features/bin.feature +6 -6
  17. data/features/configuration.feature +9 -9
  18. data/features/copy.feature +15 -12
  19. data/features/generator.feature +1 -1
  20. data/features/mount.feature +14 -14
  21. data/features/settings.feature +119 -0
  22. data/features/step_definitions/revenc_steps.rb +1 -2
  23. data/features/support/aruba.rb +9 -9
  24. data/features/support/env.rb +8 -2
  25. data/features/unmount.feature +8 -8
  26. data/lib/revenc.rb +12 -3
  27. data/lib/revenc/app.rb +27 -53
  28. data/lib/revenc/core/array.rb +11 -0
  29. data/lib/revenc/core/hash.rb +45 -0
  30. data/lib/revenc/encfs_wrapper.rb +20 -24
  31. data/lib/revenc/errors.rb +3 -3
  32. data/lib/revenc/io.rb +13 -13
  33. data/lib/revenc/settings.rb +98 -0
  34. data/revenc.gemspec +28 -17
  35. data/spec/aruba_helper.rb +25 -0
  36. data/spec/basic_app/array_spec.rb +48 -0
  37. data/spec/basic_gem/aruba_helper_spec.rb +33 -0
  38. data/spec/basic_gem/basic_gem_spec.rb +71 -1
  39. data/spec/basic_gem/gemspec_spec.rb +68 -0
  40. data/spec/revenc/error_spec.rb +2 -2
  41. data/spec/revenc/io_spec.rb +12 -12
  42. data/spec/spec_helper.rb +4 -9
  43. data/spec/watchr.rb +48 -26
  44. metadata +120 -177
  45. data/.yardopts +0 -6
  46. data/spec/spec.opts +0 -2
@@ -0,0 +1,119 @@
1
+ @announce
2
+ Feature: Configuration via yaml file
3
+
4
+ In order to configure options, as an interactive user or automated script,
5
+ the program should process configuration options via yaml. These options
6
+ should override hard coded defaults but not command line options.
7
+
8
+ Config files are read from multiple locations in order of priority. Once a
9
+ config file is found, all other config files are ignored.
10
+
11
+ All command line options can be read from the config file from the "options:"
12
+ block. The "options" block is optional.
13
+
14
+ NOTE: All file system testing is done via the Aruba gem. The home folder
15
+ config file is stubbed to prevent testing contamination in case it exists.
16
+
17
+
18
+ Scenario: Specified config file exists
19
+ Given an empty file named "config.conf"
20
+ When I run `revenc action --verbose --config config.conf`
21
+ Then the output should contain:
22
+ """
23
+ config file: config.conf
24
+ """
25
+
26
+ Scenario: Specified config file option but not given on command line
27
+ When I run `revenc action --verbose --config`
28
+ Then the exit status should be 1
29
+ And the output should contain:
30
+ """
31
+ missing argument: --config
32
+ """
33
+
34
+ Scenario: Specified config file not found
35
+ When I run `revenc path --verbose --config config.conf`
36
+ Then the exit status should be 1
37
+ And the output should contain:
38
+ """
39
+ config file not found
40
+ """
41
+
42
+ Scenario: Reading options from specified config file, ignoring the
43
+ default config file
44
+ Given a file named "revenc.conf" with:
45
+ """
46
+ ---
47
+ options:
48
+ coloring: true
49
+ """
50
+ And a file named "no_coloring.conf" with:
51
+ """
52
+ ---
53
+ options:
54
+ coloring: false
55
+ """
56
+ When I run `revenc action --verbose --config no_coloring.conf`
57
+ Then the output should contain:
58
+ """
59
+ :coloring=>false
60
+ """
61
+ And the output should not contain:
62
+ """
63
+ :coloring=>true
64
+ """
65
+
66
+ Scenario: Reading options from specified config file, ignoring the
67
+ default config file with override on command line
68
+ Given a file named "revenc.conf" with:
69
+ """
70
+ ---
71
+ options:
72
+ coloring: true
73
+ """
74
+ And a file named "no_coloring.conf" with:
75
+ """
76
+ ---
77
+ options:
78
+ coloring: false
79
+ """
80
+ When I run `revenc action --verbose --config no_coloring.conf --coloring`
81
+ Then the output should contain:
82
+ """
83
+ :coloring=>"AUTO"
84
+ """
85
+ And the output should not contain:
86
+ """
87
+ :coloring=>false
88
+ """
89
+ And the output should not contain:
90
+ """
91
+ :coloring=>true
92
+ """
93
+
94
+ Scenario: Reading options from config file with negative override on command line
95
+ And a file named "with_coloring.conf" with:
96
+ """
97
+ ---
98
+ options:
99
+ coloring: true
100
+ """
101
+ When I run `revenc action --verbose --config with_coloring.conf --no-coloring`
102
+ Then the output should contain:
103
+ """
104
+ :coloring=>false
105
+ """
106
+
107
+ Scenario: Reading text options from config file
108
+ Given a file named "with_always_coloring.conf" with:
109
+ """
110
+ ---
111
+ options:
112
+ coloring: ALWAYS
113
+ """
114
+ When I run `revenc action --verbose --config with_always_coloring.conf`
115
+ Then the output should contain:
116
+ """
117
+ :coloring=>"ALWAYS"
118
+ """
119
+
@@ -47,7 +47,7 @@
47
47
  When /^I run with a lock file present "(.*)"$/ do |cmd|
48
48
  lockfile = File.join(current_dir, 'revenc.lck')
49
49
  Mutagem::Mutex.new(lockfile).execute do
50
- run(unescape(cmd), false)
50
+ run_simple(unescape(cmd), false)
51
51
  end
52
52
  end
53
53
 
@@ -62,4 +62,3 @@
62
62
  folder.exists?.should be_true
63
63
  folder.should_not be_empty
64
64
  end
65
-
@@ -1,21 +1,21 @@
1
- require 'aruba'
1
+ require 'aruba/api'
2
2
  require 'fileutils'
3
3
 
4
- APP_BIN_PATH = File.join(ENV['PWD'], 'bin', 'revenc')
4
+ APP_BIN_PATH = File.join(FileUtils.pwd, 'bin', 'revenc')
5
5
 
6
6
  module Aruba
7
7
  module Api
8
8
 
9
- alias_method :old_run, :run
9
+ alias_method :old_run_simple, :run_simple
10
+
11
+ # override aruba
12
+ def run_simple(cmd, fail_on_error=true)
10
13
 
11
- # override aruba
12
- def run(cmd, fail_on_error=true)
13
-
14
14
  # run development version in verbose mode
15
- cmd = cmd.gsub(/^revenc/, "#{APP_BIN_PATH} --verbose")
15
+ cmd = cmd.gsub(/^revenc/, "ruby -S #{APP_BIN_PATH} --verbose")
16
16
 
17
- # run original aruba 'run'
18
- old_run(cmd, fail_on_error)
17
+ # run original aruba 'run'
18
+ old_run_simple(cmd, fail_on_error)
19
19
  end
20
20
  end
21
21
  end
@@ -1,4 +1,10 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'rubygems'
2
3
  require 'revenc'
3
- require 'aruba'
4
- require 'spec/expectations'
4
+ require 'aruba/cucumber'
5
+ require 'rspec/expectations'
6
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec/aruba_helper')
7
+
8
+ Before do
9
+ @aruba_timeout_seconds = 10
10
+ end
@@ -14,21 +14,21 @@ Feature: Unmounting a reverse mounted encrypted folder using encfs
14
14
  """
15
15
  test
16
16
  """
17
- And I successfully run "revenc mount unencrypted_source_folder encrypted_destination_folder"
18
-
17
+ And I successfully run `revenc mount unencrypted_source_folder encrypted_destination_folder`
18
+
19
19
  Scenario: Successful unmount
20
- When I run "revenc unmount encrypted_destination_folder"
20
+ When I run `revenc unmount encrypted_destination_folder`
21
21
  Then the exit status should be 0
22
22
  And the folder "encrypted_destination_folder" should not be mounted
23
-
23
+
24
24
 
25
25
  Scenario: Successful unmount dry run
26
- When I run "revenc --dry-run unmount encrypted_destination_folder"
26
+ When I run `revenc --dry-run unmount encrypted_destination_folder`
27
27
  Then the exit status should be 0
28
28
  And the folder "encrypted_destination_folder" should be mounted
29
29
 
30
30
  Scenario: Unmount folder not specified
31
- When I run "revenc unmount"
31
+ When I run `revenc unmount`
32
32
  Then the exit status should be 1
33
33
  And the output should contain:
34
34
  """
@@ -37,7 +37,7 @@ Feature: Unmounting a reverse mounted encrypted folder using encfs
37
37
 
38
38
  Scenario: Unmount folder doesn't exist
39
39
  Given a directory named "encrypted_destination_folder"
40
- When I run "revenc unmount unencrypted_source_folder"
40
+ When I run `revenc unmount unencrypted_source_folder`
41
41
  Then the exit status should be 1
42
42
  And the output should contain:
43
43
  """
@@ -50,7 +50,7 @@ Feature: Unmounting a reverse mounted encrypted folder using encfs
50
50
  unmount:
51
51
  executable: missing_bin_file
52
52
  """
53
- When I run "revenc unmount unencrypted_source_folder"
53
+ When I run `revenc unmount unencrypted_source_folder`
54
54
  Then the exit status should be 1
55
55
  And the output should contain:
56
56
  """
@@ -1,6 +1,9 @@
1
1
  # require all files here
2
- require 'rubygems'
2
+ require 'rbconfig'
3
+ require 'revenc/core/hash'
4
+ require 'revenc/core/array'
3
5
  require 'revenc/app'
6
+ require 'revenc/settings'
4
7
  require 'revenc/io'
5
8
  require 'revenc/errors'
6
9
  require 'revenc/encfs_wrapper'
@@ -16,9 +19,15 @@ module Revenc
16
19
  def self.version
17
20
  version_info_file = File.join(File.dirname(__FILE__), *%w[.. VERSION])
18
21
  File.open(version_info_file, "r") do |f|
19
- f.read
22
+ f.read.strip
20
23
  end
21
24
  end
22
-
25
+
26
+ # Platform constants
27
+ unless defined?(Revenc::WINDOWS)
28
+ WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i
29
+ CYGWIN = RbConfig::CONFIG['host_os'] =~ /cygwin/i
30
+ end
31
+
23
32
  end
24
33
 
@@ -1,4 +1,3 @@
1
- require 'configatron'
2
1
  require 'term/ansicolor'
3
2
 
4
3
  class String
@@ -11,21 +10,26 @@ module Revenc
11
10
 
12
11
  class App
13
12
 
14
- def initialize(base_dir, options={})
15
- @base_dir = base_dir
13
+ def initialize(working_dir, argv=[], options={})
14
+ @working_dir = working_dir
16
15
  @options = options
16
+ @argv = argv
17
17
  if @options[:verbose]
18
- puts "base_dir: #{@base_dir}".cyan
18
+ puts "working_dir: #{@working_dir}".cyan
19
19
  puts "options: #{@options.inspect}".cyan
20
+ puts "base_dir: #{@options[:base_dir]}".cyan if @options[:base_dir]
21
+ puts "config file: #{@options[:config]}".cyan if @options[:config]
20
22
  end
21
- configure(options)
23
+ $stdout.sync = true
22
24
  end
23
25
 
24
- def run
26
+ def execute
25
27
  begin
26
28
 
27
29
  if action_argument_required?
28
- action = ARGV.shift
30
+ action = @argv.shift
31
+ args = @argv
32
+
29
33
  unless AVAILABLE_ACTIONS.include?(action)
30
34
  if action.nil?
31
35
  puts "revenc action required"
@@ -35,9 +39,9 @@ def run
35
39
  puts "revenc --help for more information"
36
40
  exit 1
37
41
  end
38
- puts "revenc run action: #{action}".cyan if @options[:verbose]
42
+ puts "revenc run action: #{action} #{args.join(' ')}".cyan if @options[:verbose]
39
43
  raise "action #{action} not implemented" unless respond_to?(action)
40
- result = send(action)
44
+ result = send(action, args)
41
45
  else
42
46
  #
43
47
  # default action if action_argument_required? is false
@@ -45,7 +49,12 @@ def run
45
49
  result = 0
46
50
  end
47
51
 
48
- exit(result ? 0 : 1)
52
+ if result.is_a?(Numeric)
53
+ exit(result)
54
+ else
55
+ # handle all other return types
56
+ exit(result ? 0 : 1)
57
+ end
49
58
 
50
59
  rescue SystemExit => e
51
60
  # This is the normal exit point, exit code from the send result
@@ -55,6 +64,7 @@ def run
55
64
  rescue Exception => e
56
65
  STDERR.puts("revenc command failed, error(s) follow:")
57
66
  STDERR.puts("#{e.message}".red)
67
+ STDERR.puts("Use '--verbose' for backtrace.") unless @options[:verbose]
58
68
  STDERR.puts(e.backtrace.join("\n")) if @options[:verbose]
59
69
  exit(1)
60
70
  end
@@ -65,18 +75,18 @@ def run
65
75
  #
66
76
  # TODO: Add status command, use encfsctl
67
77
 
68
- def mount
69
- EncfsWrapper.new(@base_dir, @options).mount(ARGV.shift, ARGV.shift)
78
+ def mount(args)
79
+ EncfsWrapper.new(@base_dir, @options).mount(args.shift, args.shift)
70
80
  end
71
81
 
72
- def unmount
73
- EncfsWrapper.new(@base_dir, @options).unmount(ARGV.shift)
82
+ def unmount(args)
83
+ EncfsWrapper.new(@base_dir, @options).unmount(args.shift)
74
84
  end
75
85
 
76
- def copy
77
- EncfsWrapper.new(@base_dir, @options).copy(ARGV.shift, ARGV.shift)
86
+ def copy(args)
87
+ EncfsWrapper.new(@base_dir, @options).copy(args.shift, args.shift)
78
88
  end
79
-
89
+
80
90
  #
81
91
  # app commands end
82
92
  #
@@ -88,41 +98,5 @@ def action_argument_required?
88
98
  !AVAILABLE_ACTIONS.empty?
89
99
  end
90
100
 
91
- # read options for YAML config with ERB processing and initialize configatron
92
- def configure(options)
93
- # TODO: read ~/.revenc.conf before looking in the current folder for revenc.conf, read BOTH files
94
- config = @options[:config]
95
- config = File.join(@base_dir, 'revenc.conf') unless config
96
- if File.exists?(config)
97
- # load configatron options from the config file
98
- puts "loading config file: #{config}".cyan if @options[:verbose]
99
- configatron.configure_from_yaml(config)
100
- else
101
- # user specified a config file?
102
- raise "config file not found" if @options[:config]
103
- # no error if user did not specify config file
104
- puts "#{config} not found".yellow if @options[:verbose]
105
- end
106
-
107
- #
108
- # set defaults, these will NOT override setting read from YAML
109
- #
110
- configatron.mount.source.set_default(:name, nil)
111
- configatron.mount.mountpoint.set_default(:name, nil)
112
- configatron.mount.passphrasefile.set_default(:name, 'passphrase')
113
- configatron.mount.keyfile.set_default(:name, 'encfs6.xml')
114
- configatron.mount.set_default(:cmd, nil)
115
- configatron.mount.set_default(:executable, nil)
116
-
117
- configatron.unmount.mountpoint.set_default(:name, nil)
118
- configatron.unmount.set_default(:cmd, nil)
119
- configatron.unmount.set_default(:executable, nil)
120
-
121
- configatron.copy.source.set_default(:name, nil)
122
- configatron.copy.destination.set_default(:name, nil)
123
- configatron.copy.set_default(:cmd, nil)
124
- configatron.copy.set_default(:executable, nil)
125
- end
126
-
127
101
  end
128
102
  end
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def recursively_symbolize_keys!
3
+ self.each do |item|
4
+ if item.is_a? Hash
5
+ item.recursively_symbolize_keys!
6
+ elsif item.is_a? Array
7
+ item.recursively_symbolize_keys!
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ class Hash
2
+
3
+ # sorted yaml
4
+ def to_yaml( opts = {} )
5
+ YAML::quick_emit( object_id, opts ) do |out|
6
+ out.map( taguri, to_yaml_style ) do |map|
7
+ sorted_keys = keys
8
+ sorted_keys = begin
9
+ sorted_keys.sort
10
+ rescue
11
+ sorted_keys.sort_by {|k| k.to_s} rescue sorted_keys
12
+ end
13
+
14
+ sorted_keys.each do |k|
15
+ map.add( k, fetch(k) )
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # active_support hash key functions
22
+ def symbolize_keys!
23
+ self.replace(self.symbolize_keys)
24
+ end
25
+
26
+ def symbolize_keys
27
+ inject({}) do |options, (key, value)|
28
+ options[(key.to_sym rescue key) || key] = value
29
+ options
30
+ end
31
+ end
32
+
33
+ def recursively_symbolize_keys!
34
+ self.symbolize_keys!
35
+ self.values.each do |v|
36
+ if v.is_a? Hash
37
+ v.recursively_symbolize_keys!
38
+ elsif v.is_a? Array
39
+ v.recursively_symbolize_keys!
40
+ end
41
+ end
42
+ self
43
+ end
44
+
45
+ end