melon 0.1.0 → 0.2.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.
- 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
|