melon 0.5.0 → 0.6.0

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,3 +1,12 @@
1
+ === 0.6.0 2011-02-10
2
+ * Major improvements
3
+ * melon now expands symlinks by default
4
+ * Added --preserve-symlinks option
5
+
6
+ * Minor improvements
7
+ * Fixed bug with add --update
8
+ * Fixed 'melon help'
9
+
1
10
  === 0.5.0 2011-02-09
2
11
  * Major improvements:
3
12
  * Added --recursive option to 'check' subcommand
@@ -9,7 +18,7 @@
9
18
 
10
19
  === 0.3.0 2011-01-28
11
20
  * Major improvements:
12
- * added 'help' command'
21
+ * added 'help' command
13
22
 
14
23
  === 0.2.0 2011-01-26
15
24
  * Major improvements:
@@ -61,12 +61,25 @@ Feature: Adding files to the database
61
61
  And the output should contain "dir/test/test3"
62
62
  And the output should contain "test_file"
63
63
 
64
- Scenario: Adding as an update
64
+ Scenario: Updating via add
65
65
  Given a file named "test2" with:
66
66
  """
67
67
  Also a test file
68
68
  """
69
69
  And I run "melon -d test.db add -q test_file"
70
- When I run "melon -d test.db add -u test_file test2"
70
+ When I run "melon -d test.db add -u test2 test_file"
71
71
  Then the output should contain "test2"
72
72
  And the output should not contain "test_file"
73
+
74
+ Scenario: Adding a symlinked file
75
+ Given I run "ln -s test_file link"
76
+ When I run "melon -d test.db add link"
77
+ Then the output should contain "test_file"
78
+ And the output should not contain "link"
79
+
80
+ Scenario: Adding a symlinked file, preserving symlinks
81
+ Given I run "ln -s test_file link"
82
+ When I run "melon -d test.db add -p link"
83
+ Then the output should not contain "test_file"
84
+ And the output should contain "link"
85
+
@@ -0,0 +1,15 @@
1
+ Feature: Getting help
2
+ In order to use all of melon's features correctly
3
+ As a user
4
+ I should be able to get help using melon
5
+
6
+ Scenario: General help
7
+ When I run "melon help"
8
+ Then the output should contain "Usage:"
9
+ And the output should contain "Commands:"
10
+ And the output should contain "Options:"
11
+
12
+ Scenario: Help with a particular command
13
+ When I run "melon help add"
14
+ Then the output should contain "Usage: melon add"
15
+ And the output should contain "Options:"
@@ -14,7 +14,7 @@ module Melon
14
14
  new(arguments).run
15
15
  end
16
16
 
17
- attr_accessor :arguments
17
+ attr_accessor :arguments, :options, :parser
18
18
 
19
19
  def initialize(arguments)
20
20
  self.arguments = arguments
@@ -26,40 +26,8 @@ module Melon
26
26
  options
27
27
  end
28
28
 
29
- def run
30
- options = parse_options
31
- options.database = PStore.new(File.expand_path(options.database_path))
32
-
33
- # prepare db
34
- options.database.transaction do
35
- options.database[:by_hash] ||= {}
36
- options.database[:by_path] ||= {}
37
- end
38
-
39
- unless arguments.empty?
40
- run_command(options)
41
- end
42
- end
43
-
44
- def run_command(options)
45
- # look for command class in args.shift
46
- command_name = arguments.shift
47
- begin
48
- c = Commands[command_name.capitalize]
49
- rescue NameError => e
50
- # don't swallow NoMethodErrors
51
- raise e unless e.instance_of?(NameError)
52
- error "unrecognized command: #{command_name}"
53
- end
54
- c.new(arguments, options).run
55
- end
56
-
57
- def parse_options
58
- options = self.class.default_options
59
-
60
- # TODO: empty args should be -h
61
-
62
- parser = OptionParser.new do |p|
29
+ def parser
30
+ @parser ||= OptionParser.new do |p|
63
31
  p.banner = "Usage: melon [options] COMMAND [command-options] [ARGS]"
64
32
 
65
33
  p.separator ""
@@ -67,7 +35,6 @@ module Melon
67
35
  p.separator ""
68
36
 
69
37
  Commands.each do |command|
70
- # help goes last
71
38
  if command.command_name == 'help'
72
39
  next
73
40
  end
@@ -75,9 +42,6 @@ module Melon
75
42
  p.separator format_command(command.command_name,
76
43
  command.description)
77
44
  end
78
- # TODO: add help command back into parser helptext
79
- # p.separator format_command(Commands::Help.command_name,
80
- # Commands::Help.description)
81
45
  p.separator ""
82
46
  p.separator "Options:"
83
47
  p.separator ""
@@ -87,17 +51,61 @@ module Melon
87
51
  options.database_path = database
88
52
  end
89
53
 
90
- p.on_tail("-v", "--version", "Show version") do
54
+ p.on("-v", "--version", "Show version") do
91
55
  puts Melon.version_string
92
56
  exit 0
93
57
  end
94
58
 
95
- p.on_tail("-h", "--help", "This is it") do
59
+ p.on("-h", "--help", "This is it") do
96
60
  puts p
97
61
  exit 0
98
62
  end
63
+
64
+ p.separator ""
65
+ p.separator "For more information on a specific command," +
66
+ " use 'melon help COMMAND'"
99
67
  end
100
68
 
69
+ end
70
+
71
+ def run
72
+ parse_options
73
+ options.database = PStore.new(File.expand_path(options.database_path))
74
+
75
+ # prepare db
76
+ options.database.transaction do
77
+ options.database[:by_hash] ||= {}
78
+ options.database[:by_path] ||= {}
79
+ end
80
+
81
+ if arguments.empty?
82
+ puts parser
83
+ exit
84
+ else
85
+ # look for command class in args.shift
86
+ command_name = arguments.shift
87
+
88
+ run_command(command_name)
89
+ end
90
+ end
91
+
92
+ def run_command(command_name)
93
+ begin
94
+ command_class = Commands[command_name.capitalize]
95
+ rescue NameError => e
96
+ # don't swallow NoMethodErrors
97
+ raise e unless e.instance_of?(NameError)
98
+ error "unrecognized command: #{command_name}"
99
+ end
100
+ c = command_class.new(arguments, options)
101
+ (command_name == 'help' ? c.run(self) : c.run)
102
+ end
103
+
104
+ def parse_options
105
+ self.options = self.class.default_options
106
+
107
+ # TODO: empty args should be -h
108
+
101
109
  begin
102
110
  parser.order!(arguments)
103
111
  rescue OptionParser::ParseError => e
@@ -7,7 +7,7 @@ module Melon
7
7
  self.constants.sort.each do |c|
8
8
  const = self.const_get(c)
9
9
 
10
- if const.superclass == Base
10
+ if const.respond_to?(:superclass) && const.superclass == Base
11
11
  consts << const
12
12
  yield const
13
13
  end
@@ -22,12 +22,12 @@ module Melon
22
22
 
23
23
  # 1.0 list
24
24
  # TODO: check needs -r
25
+ # TODO: update- a function of add, ignore files that are already present in the db
25
26
  # TODO: needs a 'remove' command, or some way to deal with deletes/renames
26
27
  # remove: given a tracked file, removes it
27
28
  # given an untracked file, it hashes it
28
29
  # and attempts to remove it by hash
29
30
  # TODO: list needs --paths(only) and --hashes(only)
30
- # TODO: update- a function of add, ignore files that are already present in the db
31
31
  # TODO: handle moving a file somehow -- hopefully a function of update
32
32
  # could be:
33
33
  # 1. move file
@@ -1,5 +1,6 @@
1
1
  require 'melon/hasher'
2
2
  require 'melon/commands/base'
3
+ require 'melon/commands/common_options'
3
4
 
4
5
  module Melon
5
6
  module Commands
@@ -13,14 +14,18 @@ module Melon
13
14
  options.quiet = true
14
15
  end
15
16
 
16
- parser.on("-r", "--recursive", "Recursively add directory contents") do
17
- options.recursive = true
18
- end
17
+ CommonOptions.recursive(parser, options)
19
18
 
20
- parser.on("-u" "--update",
19
+ parser.on("-u", "--update",
21
20
  "Skip paths already present in the database") do
22
21
  options.update = true
23
- end
22
+ end
23
+
24
+ CommonOptions.preserve_symlinks(parser, options)
25
+ end
26
+
27
+ def usageargs
28
+ "FILE [FILE [FILE ...]]"
24
29
  end
25
30
 
26
31
  def run
@@ -33,6 +38,7 @@ module Melon
33
38
  options.database.transaction do
34
39
  args.each do |arg|
35
40
  filename = File.expand_path(arg)
41
+ filename = resolve_symlinks(filename) unless options.preserve_symlinks
36
42
 
37
43
  if File.directory?(filename)
38
44
  error "argument is a directory: #{arg}"
@@ -48,10 +48,13 @@ module Melon
48
48
  def usageargs; end
49
49
  def helptext; end
50
50
 
51
+ def run; raise; end
52
+
51
53
  def self.description
52
54
  raise
53
55
  end
54
56
 
57
+
55
58
  def parse_options!
56
59
  begin
57
60
  parser.parse!(args)
@@ -1,4 +1,5 @@
1
1
  require 'melon/commands/base'
2
+ require 'melon/commands/common_options'
2
3
 
3
4
  module Melon
4
5
  module Commands
@@ -15,13 +16,12 @@ EOS
15
16
  end
16
17
 
17
18
  def usageargs
18
- "file [file [file ...]"
19
+ "FILE [FILE [FILE ...]]"
19
20
  end
20
21
 
21
22
  def parser_options(parser)
22
- parser.on("-r", "--recursive", "Recursively check directory contents") do
23
- options.recursive = true
24
- end
23
+ CommonOptions.recursive(parser, options)
24
+ CommonOptions.preserve_symlinks(parser, options)
25
25
  end
26
26
 
27
27
  def run
@@ -32,14 +32,17 @@ EOS
32
32
  end
33
33
 
34
34
  options.database.transaction do
35
- args.each do |filename|
35
+ args.each do |arg|
36
+ filename = File.expand_path(arg)
37
+ filename = resolve_symlinks(filename) unless options.preserve_symlinks
38
+
36
39
  if File.directory?(filename)
37
40
  error "argument is a directory: #{arg}"
38
41
  end
39
42
 
40
43
  hash = Hasher.digest(filename)
41
44
  unless options.database[:by_hash][hash]
42
- puts File.expand_path(filename)
45
+ puts filename
43
46
  end
44
47
  end
45
48
  end
@@ -0,0 +1,17 @@
1
+ module Melon
2
+ module Commands
3
+ module CommonOptions
4
+ def self.recursive(parser, options)
5
+ parser.on("-r", "--recursive", "Recursively process directories") do
6
+ options.recursive = true
7
+ end
8
+ end
9
+
10
+ def self.preserve_symlinks(parser, options)
11
+ parser.on("-p", "--preserve-symlinks", "Don't expand symlinks") do
12
+ options.preserve_symlinks = true
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,4 @@
1
+ require 'melon/cli'
1
2
  require 'melon/commands/base'
2
3
  require 'melon/commands'
3
4
 
@@ -8,10 +9,15 @@ module Melon
8
9
  "Get help with a specific command"
9
10
  end
10
11
 
11
- def run
12
+ def run(cli)
13
+ if args.empty?
14
+ puts cli.parser
15
+ exit
16
+ end
12
17
  help = args.shift
13
18
  begin
14
19
  puts Commands[help.capitalize].new(args, options).parser
20
+ exit
15
21
  rescue NameError => e
16
22
  # don't swallow NoMethodErrors
17
23
  raise e unless e.instance_of?(NameError)
@@ -8,7 +8,7 @@ module Melon
8
8
  end
9
9
 
10
10
  def usageargs
11
- "file [file [file ...]]"
11
+ "FILE [FILE [FILE ...]"
12
12
  end
13
13
 
14
14
  def helptext
@@ -53,5 +53,9 @@ module Melon
53
53
  end
54
54
  end.flatten.reject { |arg| File.directory?(arg) }
55
55
  end
56
+
57
+ def resolve_symlinks(file)
58
+ Pathname.new(file).realpath.to_s
59
+ end
56
60
  end
57
61
  end
@@ -1,6 +1,6 @@
1
1
  module Melon
2
2
  def self.version
3
- "0.5.0"
3
+ "0.6.0"
4
4
  end
5
5
 
6
6
  def self.version_string
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: melon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andrew Roberts
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-09 00:00:00 -05:00
18
+ date: 2011-02-10 00:00:00 -05:00
19
19
  default_executable: melon
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -81,6 +81,7 @@ files:
81
81
  - features/add.feature
82
82
  - features/check.feature
83
83
  - features/edges.feature
84
+ - features/help.feature
84
85
  - features/list.feature
85
86
  - features/show.feature
86
87
  - features/step_definitions/basic_steps.rb
@@ -91,6 +92,7 @@ files:
91
92
  - lib/melon/commands/add.rb
92
93
  - lib/melon/commands/base.rb
93
94
  - lib/melon/commands/check.rb
95
+ - lib/melon/commands/common_options.rb
94
96
  - lib/melon/commands/help.rb
95
97
  - lib/melon/commands/list.rb
96
98
  - lib/melon/commands/show.rb
@@ -143,6 +145,7 @@ test_files:
143
145
  - features/add.feature
144
146
  - features/check.feature
145
147
  - features/edges.feature
148
+ - features/help.feature
146
149
  - features/list.feature
147
150
  - features/show.feature
148
151
  - features/step_definitions/basic_steps.rb