melon 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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