melon 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/features/add.feature +57 -0
- data/features/check.feature +27 -0
- data/features/edges.feature +8 -1
- data/features/list.feature +18 -0
- data/features/show.feature +28 -0
- data/lib/melon/cli.rb +11 -31
- data/lib/melon/commands.rb +125 -13
- data/lib/melon/helpers.rb +43 -0
- data/lib/melon/version.rb +1 -1
- data/script/console +8 -5
- metadata +13 -9
- data/features/basic.feature +0 -33
- data/lib/melon/commands/add.rb +0 -10
- data/lib/melon/commands/basic_command.rb +0 -19
- data/lib/melon/commands/help.rb +0 -51
data/History.txt
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
Feature: Adding files to the database
|
2
|
+
In order to have something to compare new files to
|
3
|
+
As a user
|
4
|
+
I should be able to add files to the database
|
5
|
+
|
6
|
+
|
7
|
+
Background:
|
8
|
+
Given a file named "test_file" with:
|
9
|
+
"""
|
10
|
+
This file is a test file
|
11
|
+
"""
|
12
|
+
|
13
|
+
Scenario: Adding files to a melon database
|
14
|
+
When I run "melon -d test.db add test_file"
|
15
|
+
Then the output should contain a hash
|
16
|
+
And the output should contain "test_file"
|
17
|
+
|
18
|
+
Scenario: Adding a file that already exists
|
19
|
+
When I run "melon -d test.db add test_file"
|
20
|
+
And I run "melon -d test.db add test_file"
|
21
|
+
Then it should fail with:
|
22
|
+
"""
|
23
|
+
melon: path already present in database
|
24
|
+
"""
|
25
|
+
|
26
|
+
Scenario: Adding a directory itself
|
27
|
+
Given a directory named "testo"
|
28
|
+
When I run "melon -d test.db add testo"
|
29
|
+
Then it should fail with:
|
30
|
+
"""
|
31
|
+
directory
|
32
|
+
"""
|
33
|
+
|
34
|
+
Scenario: Adding a file that doesn't exist
|
35
|
+
When I run "melon -d test.db add nonexistant_file"
|
36
|
+
Then it should fail with:
|
37
|
+
"""
|
38
|
+
melon: no such file: nonexistant_file
|
39
|
+
"""
|
40
|
+
|
41
|
+
Scenario: Adding a directory recursively
|
42
|
+
Given a file named "dir/test1" with:
|
43
|
+
"""
|
44
|
+
First test file
|
45
|
+
"""
|
46
|
+
And a file named "dir/test2" with:
|
47
|
+
"""
|
48
|
+
Second test file
|
49
|
+
"""
|
50
|
+
And a file named "dir/test/test3" with:
|
51
|
+
"""
|
52
|
+
Third test file
|
53
|
+
"""
|
54
|
+
When I run "melon -d test.db add -r dir"
|
55
|
+
Then the output should contain "dir/test1"
|
56
|
+
And the output should contain "dir/test2"
|
57
|
+
And the output should contain "dir/test/test3"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Feature: Check
|
2
|
+
In order to see if a given file is tracked by the database
|
3
|
+
As a user
|
4
|
+
I should be able to query the database with a file
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given a file named "test_file" with:
|
8
|
+
"""
|
9
|
+
This file is a test file
|
10
|
+
"""
|
11
|
+
|
12
|
+
Scenario: Checking a file that is not in the database
|
13
|
+
When I run "melon -d test.db check test_file"
|
14
|
+
Then the output should contain "test_file"
|
15
|
+
And the output should start with "/"
|
16
|
+
|
17
|
+
Scenario: Checking a file that is in the database:
|
18
|
+
When I run "melon -d test.db add -q test_file"
|
19
|
+
And I run "melon -d test.db check test_file"
|
20
|
+
Then the output should be empty
|
21
|
+
|
22
|
+
Scenario: Checking a file that doesn't exist
|
23
|
+
When I run "melon -d test.db check nonexistant_file"
|
24
|
+
Then it should fail with:
|
25
|
+
"""
|
26
|
+
melon: no such file: nonexistant_file
|
27
|
+
"""
|
data/features/edges.feature
CHANGED
@@ -7,7 +7,14 @@ Feature: Edge cases
|
|
7
7
|
"""
|
8
8
|
When I run "cp test_file test_file_2"
|
9
9
|
And I run "melon -d test.db add test_file test_file_2"
|
10
|
-
Then
|
10
|
+
Then it should fail with:
|
11
11
|
"""
|
12
12
|
melon: file exists elsewhere in the database
|
13
13
|
"""
|
14
|
+
|
15
|
+
Scenario: Unrecognized command
|
16
|
+
When I run "melon whizzle bang"
|
17
|
+
Then it should fail with:
|
18
|
+
"""
|
19
|
+
melon: unrecognized command: whizzle
|
20
|
+
"""
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: List
|
2
|
+
In order to see what's tracked by the database
|
3
|
+
As a user
|
4
|
+
I should be able to get a list of tracked files
|
5
|
+
|
6
|
+
Scenario: Listing files
|
7
|
+
Given a file named "test_file" with:
|
8
|
+
"""
|
9
|
+
Test file 1
|
10
|
+
"""
|
11
|
+
And a file named "file_test" with:
|
12
|
+
"""
|
13
|
+
Test file 2
|
14
|
+
"""
|
15
|
+
And I run "melon -d test.db add -q test_file file_test"
|
16
|
+
When I run "melon -d test.db list"
|
17
|
+
Then the output should contain "test_file"
|
18
|
+
And the output should contain "file_test"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Feature: Show
|
2
|
+
In order to see where a file is stored (according the database)
|
3
|
+
As a user
|
4
|
+
I should be able to query the database with a file
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given a file named "dir/test_file" with:
|
8
|
+
"""
|
9
|
+
This file is a test file
|
10
|
+
"""
|
11
|
+
And I run "cp dir/test_file ."
|
12
|
+
|
13
|
+
Scenario: Showing a file that is not in the database
|
14
|
+
When I run "melon -d test.db show test_file"
|
15
|
+
Then the output should be empty
|
16
|
+
|
17
|
+
Scenario: Showing a file that is in the database:
|
18
|
+
When I run "melon -d test.db add -q dir/test_file"
|
19
|
+
And I run "melon -d test.db show test_file"
|
20
|
+
Then the output should contain "dir/test_file"
|
21
|
+
And the output should start with "/"
|
22
|
+
|
23
|
+
Scenario: Showing a file that doesn't exist
|
24
|
+
When I run "melon -d test.db show nonexistant_file"
|
25
|
+
Then it should fail with:
|
26
|
+
"""
|
27
|
+
melon: no such file: nonexistant_file
|
28
|
+
"""
|
data/lib/melon/cli.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'ostruct'
|
2
|
+
require 'pstore'
|
2
3
|
require 'optparse'
|
3
4
|
|
4
5
|
require 'melon/version'
|
5
6
|
require 'melon/commands'
|
7
|
+
require 'melon/helpers'
|
6
8
|
|
7
9
|
module Melon
|
8
10
|
class CLI
|
11
|
+
include Helpers
|
9
12
|
|
10
13
|
def self.execute(arguments=[])
|
11
14
|
new(arguments).run
|
@@ -42,15 +45,17 @@ module Melon
|
|
42
45
|
# look for command class in args.shift
|
43
46
|
command_name = arguments.shift
|
44
47
|
begin
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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}"
|
49
53
|
end
|
54
|
+
c.new(arguments, options).run
|
50
55
|
end
|
51
56
|
|
52
57
|
def parse_options
|
53
|
-
options =
|
58
|
+
options = self.class.default_options
|
54
59
|
|
55
60
|
parser = OptionParser.new do |p|
|
56
61
|
p.banner = "Usage: melon [options] COMMAND [command-options] [ARGS]"
|
@@ -82,40 +87,15 @@ module Melon
|
|
82
87
|
puts p
|
83
88
|
exit 0
|
84
89
|
end
|
85
|
-
|
86
90
|
end
|
87
91
|
|
88
92
|
begin
|
89
93
|
parser.order!(arguments)
|
90
94
|
rescue OptionParser::ParseError => e
|
91
|
-
|
95
|
+
error e
|
92
96
|
end
|
93
97
|
|
94
98
|
options
|
95
99
|
end
|
96
|
-
|
97
|
-
def format_command(name, desc, margin = 4, width = 22, wrapdesc = 80)
|
98
|
-
pad = "\n" + ' ' * width
|
99
|
-
desc = wrap_text(desc, wrapdesc - width).split("\n").join(pad)
|
100
|
-
|
101
|
-
' ' * margin + "#{name.ljust(width-margin)}#{desc}"
|
102
|
-
end
|
103
|
-
|
104
|
-
def wrap_text(txt, col = 80)
|
105
|
-
txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
|
106
|
-
"\\1\\3\n")
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
-
def self.error(error_obj_or_str, code = 1)
|
111
|
-
if error_obj_or_str.respond_to?('to_s')
|
112
|
-
error_str = error_obj_or_str.to_s
|
113
|
-
else
|
114
|
-
error_str = error_obj_or_str.inspect
|
115
|
-
end
|
116
|
-
|
117
|
-
$stderr.puts "melon: #{error_str}"
|
118
|
-
exit code
|
119
|
-
end
|
120
100
|
end
|
121
101
|
end
|
data/lib/melon/commands.rb
CHANGED
@@ -1,16 +1,32 @@
|
|
1
|
-
require 'pstore'
|
2
|
-
require 'ftools'
|
3
|
-
|
4
1
|
require 'melon/hasher'
|
5
|
-
require 'melon/
|
6
|
-
|
7
|
-
# TODO: in commands, parse arguments with parse! in CLI, parse with order!
|
2
|
+
require 'melon/helpers'
|
8
3
|
|
9
4
|
module Melon
|
10
5
|
module Commands
|
6
|
+
def self.each
|
7
|
+
consts = []
|
8
|
+
base = self.const_get('Base')
|
9
|
+
self.constants.each do |c|
|
10
|
+
const = self.const_get(c)
|
11
|
+
if const.superclass == base
|
12
|
+
consts << const
|
13
|
+
yield const
|
14
|
+
end
|
15
|
+
end
|
16
|
+
consts
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
alias :[] :const_get
|
21
|
+
end
|
22
|
+
|
11
23
|
# needs a 'verify' command to check integrity of database
|
24
|
+
# both internal 2-hash consistency (consistency) and db<->filesystem
|
25
|
+
# matching up (integrity) [file exists, hashes match]
|
12
26
|
# needs a 'remove' command, or some way to deal with deletes/renames
|
27
|
+
# needs a 'list' command
|
13
28
|
class Base
|
29
|
+
include Helpers
|
14
30
|
attr_accessor :args, :options
|
15
31
|
attr_reader :description
|
16
32
|
|
@@ -31,10 +47,18 @@ module Melon
|
|
31
47
|
begin
|
32
48
|
parser.parse!(args)
|
33
49
|
rescue OptionParser::ParseError => e
|
34
|
-
|
50
|
+
error "#{self.class.to_s.split("::").last.downcase}: #{e}"
|
35
51
|
end
|
52
|
+
|
53
|
+
# verify remaining args are files - overrideable
|
54
|
+
verify_args
|
36
55
|
end
|
37
56
|
|
57
|
+
def verify_args
|
58
|
+
args.each do |arg|
|
59
|
+
error "no such file: #{arg}" unless File.exists?(arg)
|
60
|
+
end
|
61
|
+
end
|
38
62
|
end
|
39
63
|
|
40
64
|
class Add < Base
|
@@ -47,12 +71,20 @@ module Melon
|
|
47
71
|
@parser ||= OptionParser.new do |p|
|
48
72
|
p.banner = "Usage: melon add [options] file [file [file ...]]"
|
49
73
|
p.separator ""
|
50
|
-
p.separator Add.description
|
74
|
+
p.separator blockquote(Add.description + ".")
|
51
75
|
|
52
76
|
p.separator ""
|
53
77
|
p.separator "Options:"
|
54
78
|
p.separator ""
|
55
79
|
|
80
|
+
p.on("-q", "--quiet", "Suppress printing of hash and path") do
|
81
|
+
options.quiet = true
|
82
|
+
end
|
83
|
+
|
84
|
+
p.on("-r", "--recursive", "Recursively add directory contents") do
|
85
|
+
options.recursive = true
|
86
|
+
end
|
87
|
+
|
56
88
|
# p.on("-f", "--force",
|
57
89
|
# "Force the recalculation of the path that",
|
58
90
|
# " already exists in the database") do
|
@@ -64,29 +96,73 @@ module Melon
|
|
64
96
|
def run
|
65
97
|
parse_options!
|
66
98
|
|
99
|
+
if options.recursive
|
100
|
+
self.args = args.collect do |arg|
|
101
|
+
if File.directory?(arg)
|
102
|
+
Dir["#{arg}/**/*"]
|
103
|
+
else
|
104
|
+
arg
|
105
|
+
end
|
106
|
+
end.flatten.reject { |arg| File.directory?(arg) }
|
107
|
+
end
|
108
|
+
|
67
109
|
options.database.transaction do
|
68
110
|
args.each do |arg|
|
69
111
|
filename = File.expand_path(arg)
|
70
112
|
|
71
113
|
if File.directory?(filename)
|
72
|
-
|
114
|
+
error "argument is a directory: #{arg}"
|
73
115
|
end
|
74
116
|
|
75
117
|
if options.database[:by_path][filename]# and !options.force
|
76
|
-
|
118
|
+
error "path already present in database: #{arg}"
|
77
119
|
end
|
78
120
|
|
79
121
|
# hash strategy should be encapsulated, ergo indirection here
|
80
122
|
hash = Hasher.digest(filename)
|
81
123
|
|
82
124
|
if options.database[:by_hash][hash]
|
83
|
-
|
125
|
+
error "file exists elsewhere in the database: #{arg}"
|
84
126
|
end
|
85
127
|
|
86
128
|
|
87
129
|
options.database[:by_hash][hash] = filename
|
88
130
|
options.database[:by_path][filename] = hash
|
89
|
-
puts "#{hash}:#{filename}"
|
131
|
+
puts "#{hash}:#{filename}" unless options.quiet
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Show < Base
|
138
|
+
def self.description
|
139
|
+
"Show where the database thinks a file is located"
|
140
|
+
end
|
141
|
+
|
142
|
+
def parser
|
143
|
+
@parser ||= OptionParser.new do |p|
|
144
|
+
p.banner = "Usage: melon show file [file [file ...]]"
|
145
|
+
p.separator ""
|
146
|
+
p.separator blockquote(self.class.description + <<EOS
|
147
|
+
. If the file's hash matches a hash in the database, then
|
148
|
+
the associated path in the database is printed. Otherwise,
|
149
|
+
nothing is printed.
|
150
|
+
EOS
|
151
|
+
)
|
152
|
+
p.separator ""
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def run
|
158
|
+
parse_options!
|
159
|
+
|
160
|
+
options.database.transaction do
|
161
|
+
args.each do |filename|
|
162
|
+
hash = Hasher.digest(filename)
|
163
|
+
if path = options.database[:by_hash][hash]
|
164
|
+
puts path
|
165
|
+
end
|
90
166
|
end
|
91
167
|
end
|
92
168
|
end
|
@@ -101,7 +177,13 @@ module Melon
|
|
101
177
|
@parser ||= OptionParser.new do |p|
|
102
178
|
p.banner = "Usage: melon check file [file [file ...]]"
|
103
179
|
p.separator ""
|
104
|
-
p.separator
|
180
|
+
p.separator blockquote(self.class.description + <<EOS
|
181
|
+
. If the file's hash matches a hash in the database, nothing is
|
182
|
+
printed. Otherwise, the full path to the file is printed.
|
183
|
+
EOS
|
184
|
+
)
|
185
|
+
p.separator ""
|
186
|
+
|
105
187
|
end
|
106
188
|
end
|
107
189
|
|
@@ -118,5 +200,35 @@ module Melon
|
|
118
200
|
end
|
119
201
|
end
|
120
202
|
end
|
203
|
+
|
204
|
+
class List < Base
|
205
|
+
def self.description
|
206
|
+
"List the files tracked by the database"
|
207
|
+
end
|
208
|
+
|
209
|
+
def parser
|
210
|
+
@parser ||= OptionParser.new do |p|
|
211
|
+
p.banner = "Usage: melon list"
|
212
|
+
p.separator ""
|
213
|
+
p.separator blockquote(self.class.description)
|
214
|
+
p.separator ""
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def verify_args
|
220
|
+
error "invalid argument: #{args.shift}" unless args.empty?
|
221
|
+
end
|
222
|
+
|
223
|
+
def run
|
224
|
+
parse_options!
|
225
|
+
|
226
|
+
options.database.transaction do
|
227
|
+
options.database[:by_hash].each_pair do |hash, path|
|
228
|
+
puts "#{path}:#{hash}"
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
121
233
|
end
|
122
234
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Melon
|
2
|
+
module Helpers
|
3
|
+
def format_command(name, desc, options = {})
|
4
|
+
options = {
|
5
|
+
:margin => 4,
|
6
|
+
:width => 22,
|
7
|
+
:wrap => 80
|
8
|
+
}.update(options)
|
9
|
+
|
10
|
+
pad = "\n" + ' ' * options[:width]
|
11
|
+
desc = self.wrap_text(desc, options[:wrap] - options[:width])
|
12
|
+
desc = desc.split("\n").join(pad)
|
13
|
+
|
14
|
+
' ' * options[:margin] +
|
15
|
+
"#{name.ljust(options[:width] - options[:margin])}#{desc}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def wrap_text(txt, col = 80)
|
19
|
+
txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
|
20
|
+
"\\1\\3\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
def blockquote(string, options = {})
|
24
|
+
options = {
|
25
|
+
:margin => 4,
|
26
|
+
:wrap => 70
|
27
|
+
}.update(options)
|
28
|
+
options[:width] = options.delete(:margin)
|
29
|
+
format_command('', string.gsub(/\s+/,' ').gsub('\. ', '. '), options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(error_obj_or_str, code = 1)
|
33
|
+
if error_obj_or_str.respond_to?('to_s')
|
34
|
+
error_str = error_obj_or_str.to_s
|
35
|
+
else
|
36
|
+
error_str = error_obj_or_str.inspect
|
37
|
+
end
|
38
|
+
|
39
|
+
$stderr.puts "melon: #{error_str}"
|
40
|
+
exit code
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/melon/version.rb
CHANGED
data/script/console
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
|
3
3
|
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
|
7
|
+
libs = []
|
8
|
+
libs << " -I #{lib_dir}"
|
9
|
+
libs << " -r irb/completion"
|
10
|
+
libs << " -r irb/ext/save-history"
|
7
11
|
|
8
|
-
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
9
|
-
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
10
12
|
libs << " -r #{File.dirname(__FILE__) + '/../lib/melon.rb'}"
|
11
13
|
puts "Loading melon gem"
|
14
|
+
|
12
15
|
exec "#{irb} #{libs} --simple-prompt"
|
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:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.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-01-
|
18
|
+
date: 2011-01-26 00:00:00 -05:00
|
19
19
|
default_executable: melon
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -78,18 +78,19 @@ files:
|
|
78
78
|
- Rakefile
|
79
79
|
- TODO
|
80
80
|
- bin/melon
|
81
|
-
- features/
|
81
|
+
- features/add.feature
|
82
|
+
- features/check.feature
|
82
83
|
- features/edges.feature
|
84
|
+
- features/list.feature
|
85
|
+
- features/show.feature
|
83
86
|
- features/step_definitions/basic_steps.rb
|
84
87
|
- features/support/env.rb
|
85
88
|
- lib/melon.rb
|
86
89
|
- lib/melon/cli.rb
|
87
90
|
- lib/melon/commands.rb
|
88
|
-
- lib/melon/commands/add.rb
|
89
|
-
- lib/melon/commands/basic_command.rb
|
90
|
-
- lib/melon/commands/help.rb
|
91
91
|
- lib/melon/example.rb
|
92
92
|
- lib/melon/hasher.rb
|
93
|
+
- lib/melon/helpers.rb
|
93
94
|
- lib/melon/version.rb
|
94
95
|
- melon.gemspec
|
95
96
|
- script/console
|
@@ -133,8 +134,11 @@ signing_key:
|
|
133
134
|
specification_version: 3
|
134
135
|
summary: A media catalog
|
135
136
|
test_files:
|
136
|
-
- features/
|
137
|
+
- features/add.feature
|
138
|
+
- features/check.feature
|
137
139
|
- features/edges.feature
|
140
|
+
- features/list.feature
|
141
|
+
- features/show.feature
|
138
142
|
- features/step_definitions/basic_steps.rb
|
139
143
|
- features/support/env.rb
|
140
144
|
- spec/melon/cli_spec.rb
|
data/features/basic.feature
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
Feature: Basic usage
|
2
|
-
|
3
|
-
Background:
|
4
|
-
Given a file named "test_file" with:
|
5
|
-
"""
|
6
|
-
This file is a test file
|
7
|
-
"""
|
8
|
-
|
9
|
-
Scenario: Adding files to a melon database
|
10
|
-
When I run "melon -d test.db add test_file"
|
11
|
-
Then the output should contain a hash
|
12
|
-
And the output should contain "test_file"
|
13
|
-
|
14
|
-
Scenario: Adding a file that already exists
|
15
|
-
When I run "melon -d test.db add test_file"
|
16
|
-
And I run "melon -d test.db add test_file"
|
17
|
-
Then the output should contain:
|
18
|
-
"""
|
19
|
-
melon: path already present in database
|
20
|
-
"""
|
21
|
-
And the exit status should not be 0
|
22
|
-
|
23
|
-
Scenario: Checking a file that is not in the database
|
24
|
-
When I run "melon -d test.db check test_file"
|
25
|
-
Then the output should contain "test_file"
|
26
|
-
And the output should start with "/"
|
27
|
-
|
28
|
-
Scenario: Adding a directory
|
29
|
-
Given a directory named "testo"
|
30
|
-
When I run "melon -d test.db add testo"
|
31
|
-
Then the output should contain "directory"
|
32
|
-
And the exit status should not be 0
|
33
|
-
|
data/lib/melon/commands/add.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Melon
|
2
|
-
module Commands
|
3
|
-
module BasicCommand
|
4
|
-
|
5
|
-
def execute(arguments, options)
|
6
|
-
new(arguments, options).run
|
7
|
-
end
|
8
|
-
|
9
|
-
# returns name {padding} description, for usage"
|
10
|
-
def short_usage(padding=" ")
|
11
|
-
name = Melon::Commands.translate_command(self)
|
12
|
-
extra_spaces = Melon::Commands.commands.collect do |c|
|
13
|
-
c.length
|
14
|
-
end.max - name.length
|
15
|
-
"#{name}#{padding}#{' ' * extra_spaces}#{self.description}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/melon/commands/help.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'melon/commands/basic_command'
|
2
|
-
|
3
|
-
module Melon
|
4
|
-
module Commands
|
5
|
-
class Help
|
6
|
-
# Help is a basic command that also ties itself in to cli#usage, so
|
7
|
-
# it's a little bit unconventional. Retrospectively, I should not
|
8
|
-
# have written it first.
|
9
|
-
extend BasicCommand
|
10
|
-
|
11
|
-
def self.description
|
12
|
-
"Get help with a specific command, or with Melon in general"
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_accessor :arguments
|
16
|
-
|
17
|
-
def initialize(arguments, options)
|
18
|
-
self.arguments = arguments
|
19
|
-
end
|
20
|
-
|
21
|
-
def parser
|
22
|
-
@parser ||= OptionParser.new do |opts|
|
23
|
-
Melon::Commands.command_hash.each do |name, command|
|
24
|
-
next if command == self.class
|
25
|
-
# TODO help banner: gem help help
|
26
|
-
# TODO flesh out parsing - give short_usage for each command
|
27
|
-
opts.on(name) { command.parser }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def run
|
33
|
-
begin
|
34
|
-
parser.parse!(arguments)
|
35
|
-
rescue OptionParser::InvalidOption => e
|
36
|
-
puts "melon: #{e.to_s}"
|
37
|
-
exit 1
|
38
|
-
end
|
39
|
-
|
40
|
-
if arguments == ['help']
|
41
|
-
puts parser
|
42
|
-
exit
|
43
|
-
end
|
44
|
-
|
45
|
-
# if arguments are empty, we handled it in CLI
|
46
|
-
puts "melon: '#{arguments.join(' ')}' is not a recognized command."
|
47
|
-
exit 1
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|