divineflame-smurftp 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mkdn +59 -0
- data/VERSION.yml +4 -0
- data/bin/smurftp +30 -0
- data/lib/smurftp.rb +35 -0
- data/lib/smurftp/configuration.rb +45 -0
- data/lib/smurftp/shell.rb +268 -0
- data/lib/smurftp/templates/smurftp_config.yaml +10 -0
- data/lib/smurftp/templates/smurftp_multisite_config.yaml +41 -0
- data/lib/smurftp/version.rb +34 -0
- data/test/configuration_test.rb +29 -0
- data/test/shell_test.rb +91 -0
- metadata +66 -0
data/README.mkdn
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Smurftp
|
2
|
+
|
3
|
+
Smurftp is a command-line utility written in Ruby that searches a specified directory and creates a queue of recently modified files for quickly uploading to a remote server over FTP.
|
4
|
+
|
5
|
+
It was written for making web site edits where you might have a small group of files in multiple subdirectories that you want uploaded without having to manually go directory by directory.
|
6
|
+
|
7
|
+
## Install
|
8
|
+
|
9
|
+
$ gem sources -a http://gems.github.com
|
10
|
+
$ sudo gem install divineflame-smurftp
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
Start Smurftp with this command:
|
15
|
+
|
16
|
+
$ smurftp <directory or configuration file>
|
17
|
+
|
18
|
+
## Configuration
|
19
|
+
|
20
|
+
Smurftp requires a configuration file in YAML format that defines your FTP server and login information, as well as a local directory ('document_root').
|
21
|
+
|
22
|
+
When starting Smurftp, if you specify a directory, it looks for a 'smurftp_config.yaml' file in that directory. If the file is not found you'll be given the option for this file to be generated for you.
|
23
|
+
|
24
|
+
Alternatively, if you specify an existing configuration file (it doesn't require the 'smurftp_config.yaml' name) Smurftp will start by loading this file. Because the 'document_root' setting is defined in the configuration file, you can store the configuration file separately from your project files if you choose.
|
25
|
+
|
26
|
+
It's also possible to define multiple servers, sites, and login credentials in the same configuration file.
|
27
|
+
|
28
|
+
## File List
|
29
|
+
|
30
|
+
Smurftp will search the defined 'document_root' directory and list all files in all sub directories, ordered by modification date with newest files first. It skips any files defined in the configuration's 'exclusions' list.
|
31
|
+
|
32
|
+
### Sample Output
|
33
|
+
|
34
|
+
[1] foo.php
|
35
|
+
[2] images/bar.jpg
|
36
|
+
[3] includes/header.php
|
37
|
+
[4] images/logo.png
|
38
|
+
[5] yada.php
|
39
|
+
====================
|
40
|
+
smurftp>
|
41
|
+
|
42
|
+
At the `smurftp>` prompt enter the number identifier of the files you want uploaded. You can also enter a list or range of files.
|
43
|
+
|
44
|
+
### Example Commands
|
45
|
+
|
46
|
+
'1' uploads file [1]
|
47
|
+
'1-5' uploads files [1-5]
|
48
|
+
'1,2,4' uploads [1], [2], and [4]
|
49
|
+
'1-5,^4' uploads files [1-3], and [5], skipping file [4]
|
50
|
+
'1-5,!4' same as above
|
51
|
+
'all' uploads all listed files
|
52
|
+
|
53
|
+
To quit type `quit` or `exit` at the prompt. `e` or `q` will also quit.
|
54
|
+
|
55
|
+
## TODO
|
56
|
+
|
57
|
+
* support relative paths for :document_root
|
58
|
+
* add optional sftp
|
59
|
+
* automatically refresh file list
|
data/VERSION.yml
ADDED
data/bin/smurftp
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/smurftp'
|
4
|
+
|
5
|
+
input = ARGV[0]
|
6
|
+
site = ARGV[1]
|
7
|
+
|
8
|
+
if !input
|
9
|
+
puts "Please specify a directory or configuration file to run smurftp from"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
13
|
+
config_file = ''
|
14
|
+
|
15
|
+
if File.directory?(input)
|
16
|
+
directory = input
|
17
|
+
config_file = "#{input}/smurftp_config.yaml"
|
18
|
+
unless File.file?(config_file)
|
19
|
+
Smurftp::Configuration.generate_config_file(directory)
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
elsif File.file?(input)
|
23
|
+
config_file = input
|
24
|
+
else
|
25
|
+
puts "Invalid directory or configuration file."
|
26
|
+
exit
|
27
|
+
end
|
28
|
+
|
29
|
+
smurftp = Smurftp::Shell.new(config_file, site)
|
30
|
+
smurftp.run()
|
data/lib/smurftp.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'find'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'net/ftp'
|
5
|
+
require 'readline'
|
6
|
+
# require 'rubygems'
|
7
|
+
# other dependencies
|
8
|
+
|
9
|
+
# a bit of monkey patching
|
10
|
+
|
11
|
+
class String
|
12
|
+
def to_regex!
|
13
|
+
return /#{self}/
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class Hash
|
19
|
+
# Destructively convert all keys to symbols.
|
20
|
+
def symbolize_keys!
|
21
|
+
self.each do |key, value|
|
22
|
+
unless key.is_a?(Symbol)
|
23
|
+
self[key.to_sym] = self[key]
|
24
|
+
delete(key)
|
25
|
+
end
|
26
|
+
# recursively call this method on nested hashes
|
27
|
+
value.symbolize_keys! if value.class == Hash
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
%w(version configuration shell).each do |file|
|
34
|
+
require File.join(File.dirname(__FILE__), 'smurftp', file)
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Smurftp
|
2
|
+
class Configuration < Hash
|
3
|
+
|
4
|
+
def self.generate_config_file(dir)
|
5
|
+
# TODO ask before creating new file
|
6
|
+
# TODO fill out the config file by promption user for the info
|
7
|
+
templates_dir = File.dirname(__FILE__) + '/templates'
|
8
|
+
FileUtils.cp("#{templates_dir}/smurftp_config.yaml", "#{dir}/smurftp_config.yaml")
|
9
|
+
puts "No configuration file found. Creating new file."
|
10
|
+
puts "New configuration file created in #{dir}."
|
11
|
+
puts "Enter server and login info in this file and restart smurftp."
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(file, site=nil)
|
16
|
+
load_config_file(file)
|
17
|
+
if site # merge config settings with current site
|
18
|
+
tmp = self[site]
|
19
|
+
self.clear.merge! tmp
|
20
|
+
end
|
21
|
+
self.symbolize_keys!
|
22
|
+
validate
|
23
|
+
self[:exclusions] << file #exclude config file from upload if it's in the @base_dir
|
24
|
+
self[:queue_limit] ||= 15
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def load_config_file(file)
|
29
|
+
self.merge! YAML::load(File.open(file))
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def validate
|
34
|
+
%w[server server_root document_root login password].each do |setting|
|
35
|
+
unless self[setting.to_sym]
|
36
|
+
raise StandardError, "Error: \"#{setting}\" is missing from configuration file."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
unless File.directory?(self[:document_root])
|
40
|
+
raise StandardError, "Error: \"#{self[:document_root]}\" specified in configuration file is not a valid directory."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
# Smurftp::Shell is used to create an interactive shell. It is invoked by the smurftp binary.
|
2
|
+
module Smurftp
|
3
|
+
class Shell
|
4
|
+
|
5
|
+
attr_reader :upload_queue, :file_list
|
6
|
+
|
7
|
+
def initialize(config_file, site=nil)
|
8
|
+
#Readline.basic_word_break_characters = ""
|
9
|
+
#Readline.completion_append_character = nil
|
10
|
+
@configuration = Smurftp::Configuration.new(config_file, site)
|
11
|
+
@base_dir = @configuration[:document_root]
|
12
|
+
@file_list = []
|
13
|
+
@upload_queue = []
|
14
|
+
@last_upload = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# Run a single command.
|
19
|
+
def parse_command(cmd)
|
20
|
+
case cmd.downcase
|
21
|
+
when /^(a|all)$/
|
22
|
+
return lambda { upload_all }
|
23
|
+
when /\d+,/ # digit comma
|
24
|
+
files = parse_list(cmd)
|
25
|
+
command = lambda { upload }
|
26
|
+
return command, files
|
27
|
+
when /\d+(\.+|-)\d+/
|
28
|
+
files = parse_range(cmd)
|
29
|
+
command = lambda { upload }
|
30
|
+
return command, files
|
31
|
+
when /^\d+/
|
32
|
+
file = [cmd]
|
33
|
+
command = lambda { upload }
|
34
|
+
return command, file
|
35
|
+
# when /^(m|more)/: list_more_queued_files
|
36
|
+
when /^(r|refresh|l|ls|list)$/
|
37
|
+
command = lambda do
|
38
|
+
find_files
|
39
|
+
refresh_file_display
|
40
|
+
end
|
41
|
+
return command
|
42
|
+
else
|
43
|
+
return 'error'
|
44
|
+
# TODO needs error message as fallback
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Run the interactive shell using readline.
|
50
|
+
def run
|
51
|
+
find_files
|
52
|
+
refresh_file_display
|
53
|
+
loop do
|
54
|
+
cmd = Readline.readline('smurftp> ')
|
55
|
+
finish if cmd.nil? or cmd =~ /^(e|exit|q|quit)$/
|
56
|
+
next if cmd == ""
|
57
|
+
Readline::HISTORY.push(cmd)
|
58
|
+
command, files = parse_command(cmd)
|
59
|
+
if files
|
60
|
+
add_files_to_queue(files)
|
61
|
+
end
|
62
|
+
command.call
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
##
|
68
|
+
# Adds single file to upload queue, ensuring
|
69
|
+
# no duplicate additions
|
70
|
+
|
71
|
+
def add_file_to_queue(str)
|
72
|
+
str.gsub!(/[^\d]/, '') #strip non-digit characters
|
73
|
+
file = str.to_i-1
|
74
|
+
@upload_queue << file unless @upload_queue.include?(file)
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def add_files_to_queue(files)
|
79
|
+
files.each {|f| add_file_to_queue(f)}
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
##
|
84
|
+
# Extract a list of comma separated values from a string.
|
85
|
+
# Look for ranges and expand them, look for exceptions
|
86
|
+
# and remove them from the returned list.
|
87
|
+
|
88
|
+
def parse_list(str)
|
89
|
+
file_list = []
|
90
|
+
exceptions = []
|
91
|
+
str.split(',').each do |s|
|
92
|
+
if s =~ /-/
|
93
|
+
file_list += parse_range(s)
|
94
|
+
elsif s =~ /(\^|!)\d/
|
95
|
+
s.gsub!(/[^\d]/, '') #strip non-digit characters
|
96
|
+
exceptions << s
|
97
|
+
else
|
98
|
+
file_list << s
|
99
|
+
end
|
100
|
+
end
|
101
|
+
return file_list - exceptions
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
##
|
106
|
+
# Extract a range of numbers from a string.
|
107
|
+
# Expand the range into an array that represents files
|
108
|
+
# in the displayed list, and returns said array.
|
109
|
+
|
110
|
+
def parse_range(str)
|
111
|
+
delimiters = str.split(/\.+|-+/)
|
112
|
+
r_start, r_end = delimiters[0], delimiters[1]
|
113
|
+
# TODO assumes even number pairs for creating a range
|
114
|
+
range = r_start.to_i..r_end.to_i
|
115
|
+
file_list = []
|
116
|
+
range.each do |n|
|
117
|
+
file_list << n.to_s
|
118
|
+
end
|
119
|
+
return file_list
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def list_more_queued_files
|
124
|
+
# TODO
|
125
|
+
# not sure how this will work yet
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
##
|
130
|
+
# Format the output of the file list display by looping over
|
131
|
+
# @file_list and numbering each file up to the predefined queue limit.
|
132
|
+
|
133
|
+
def refresh_file_display
|
134
|
+
if @last_upload
|
135
|
+
puts 'Files changed since last upload:'
|
136
|
+
else
|
137
|
+
puts 'Recently modified files:'
|
138
|
+
end
|
139
|
+
|
140
|
+
file_count = 1
|
141
|
+
@file_list.each do |f|
|
142
|
+
unless file_count > @configuration[:queue_limit]
|
143
|
+
spacer = ' ' unless file_count > 9 #add space to even the file numbering column
|
144
|
+
puts "#{spacer}[#{file_count}] #{f[:base_name]}"
|
145
|
+
file_count += 1
|
146
|
+
else
|
147
|
+
remaining_files = @file_list.length - file_count
|
148
|
+
puts "(plus #{remaining_files} more)"
|
149
|
+
break
|
150
|
+
end
|
151
|
+
end
|
152
|
+
puts '===================='
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
##
|
157
|
+
# Find the files to process, ignoring temporary files, source
|
158
|
+
# configuration management files, etc., and add them to @file_list mapping
|
159
|
+
# filename to modification time.
|
160
|
+
|
161
|
+
def find_files
|
162
|
+
@file_list.clear
|
163
|
+
Find.find(@base_dir) do |f|
|
164
|
+
|
165
|
+
@configuration[:exclusions].each do |e|
|
166
|
+
Find.prune if f =~ e.to_regex!
|
167
|
+
# if e.class == Regexp
|
168
|
+
# Find.prune if f =~ e.to_regex!
|
169
|
+
# end
|
170
|
+
end
|
171
|
+
|
172
|
+
next if f =~ /(swp|~|rej|orig|bak|.git)$/ # temporary/patch files
|
173
|
+
next if f =~ /\/\.?#/ # Emacs autosave/cvs merge files
|
174
|
+
next if File.directory?(f) #skip directories
|
175
|
+
|
176
|
+
#TODO loop through exclusions that are regex objects
|
177
|
+
|
178
|
+
file_name = f.sub(/^\.\//, '')
|
179
|
+
mtime = File.stat(file_name).mtime
|
180
|
+
base_name = file_name.sub("#{@base_dir}/", '')
|
181
|
+
|
182
|
+
if @last_upload
|
183
|
+
if mtime > @last_upload
|
184
|
+
@file_list << {:name => file_name,
|
185
|
+
:base_name => base_name,
|
186
|
+
:mtime => mtime} rescue next
|
187
|
+
end
|
188
|
+
else #get all files, because we haven't uploaded yet
|
189
|
+
@file_list << {:name => file_name,
|
190
|
+
:base_name => base_name,
|
191
|
+
:mtime => mtime} rescue next
|
192
|
+
end
|
193
|
+
end
|
194
|
+
# sort list by mtime
|
195
|
+
@file_list.sort! { |x,y| y[:mtime] <=> x[:mtime] }
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
def upload
|
200
|
+
#TODO add timeout error handling
|
201
|
+
created_dirs = []
|
202
|
+
Net::FTP.open(@configuration[:server]) do |ftp|
|
203
|
+
ftp.login(@configuration[:login], @configuration[:password])
|
204
|
+
@upload_queue.each do |file_id|
|
205
|
+
file = @file_list[file_id]
|
206
|
+
|
207
|
+
dirs = parse_file_for_sub_dirs(file[:base_name])
|
208
|
+
dirs.each do |dir|
|
209
|
+
unless created_dirs.include? dir
|
210
|
+
begin
|
211
|
+
ftp.mkdir "#{@configuration[:server_root]}/#{dir}"
|
212
|
+
puts "created #{dir}..."
|
213
|
+
rescue Net::FTPPermError; end #ignore errors for existing dirs
|
214
|
+
created_dirs << dir
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
puts "uploading #{file[:base_name]}..."
|
219
|
+
ftp.put("#{file[:name]}", "#{@configuration[:server_root]}/#{file[:base_name]}")
|
220
|
+
# @file_list.delete_at file_id
|
221
|
+
# @upload_queue.delete file_id
|
222
|
+
end
|
223
|
+
end
|
224
|
+
@upload_queue.clear
|
225
|
+
puts "done"
|
226
|
+
@last_upload = Time.now
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
def upload_all
|
231
|
+
@file_list.length.times { |f| @upload_queue << f+1 }
|
232
|
+
upload
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
def parse_file_for_sub_dirs(file)
|
237
|
+
dirs = file.split(/\//)
|
238
|
+
return [] if dirs.length <= 1
|
239
|
+
dirs_expanded = []
|
240
|
+
|
241
|
+
while dirs.length > 1
|
242
|
+
dirs.pop
|
243
|
+
dirs_expanded << dirs.join('/')
|
244
|
+
end
|
245
|
+
|
246
|
+
return dirs_expanded.reverse
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
##
|
251
|
+
# Close the shell and exit the program with a cheesy message.
|
252
|
+
|
253
|
+
def finish
|
254
|
+
messages =
|
255
|
+
[
|
256
|
+
'Hasta La Vista, Baby!',
|
257
|
+
'Peace Out, Dawg!',
|
258
|
+
'Diggidy!',
|
259
|
+
'Up, up, and away!',
|
260
|
+
'Sally Forth Good Sir!'
|
261
|
+
]
|
262
|
+
random_msg = messages[rand(messages.length)]
|
263
|
+
puts random_msg
|
264
|
+
exit
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# smurftp multisite configuration
|
2
|
+
|
3
|
+
# multiple servers can be configured
|
4
|
+
# and shared across site settings
|
5
|
+
|
6
|
+
server1: &server1
|
7
|
+
server: ftp.yourserver.com
|
8
|
+
login: your_login
|
9
|
+
password: your_password
|
10
|
+
|
11
|
+
global_exclusions: &exclusions
|
12
|
+
exclusions:
|
13
|
+
- '_notes'
|
14
|
+
- 'resources'
|
15
|
+
- '/regex/'
|
16
|
+
|
17
|
+
# define multiple sites which can
|
18
|
+
# share server info and global_exclusions
|
19
|
+
# in addition to defining their own
|
20
|
+
|
21
|
+
site1:
|
22
|
+
<<: *server1
|
23
|
+
<<: *exclusions
|
24
|
+
server_root: 'web/'
|
25
|
+
document_root: '.'
|
26
|
+
|
27
|
+
site2:
|
28
|
+
<<: *server1
|
29
|
+
exclusions:
|
30
|
+
- 'psd'
|
31
|
+
- 'src'
|
32
|
+
server_root: 'web/'
|
33
|
+
document_root: '.'
|
34
|
+
|
35
|
+
site3:
|
36
|
+
server: ftp.anotherserver.com
|
37
|
+
login: site3_login
|
38
|
+
password: site3_password
|
39
|
+
server_root: 'web/'
|
40
|
+
document_root: '.'
|
41
|
+
<<: *exclusions
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Smurftp #:nodoc:
|
2
|
+
module VERSION #:nodoc:
|
3
|
+
MAJOR = 0
|
4
|
+
MINOR = 5
|
5
|
+
TINY = 0
|
6
|
+
|
7
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
8
|
+
URLIFIED = STRING.tr('.', '_')
|
9
|
+
|
10
|
+
# requirements_met? can take a hash with :major, :minor, :tiny set or
|
11
|
+
# a string in the format "major.minor.tiny"
|
12
|
+
def self.requirements_met?(minimum_version = {})
|
13
|
+
major = minor = tiny = 0
|
14
|
+
if minimum_version.is_a?(Hash)
|
15
|
+
major = minimum_version[:major].to_i if minimum_version.has_key?(:major)
|
16
|
+
minor = minimum_version[:minor].to_i if minimum_version.has_key?(:minor)
|
17
|
+
tiny = minimum_version[:tiny].to_i if minimum_version.has_key?(:tiny)
|
18
|
+
else
|
19
|
+
major, minor, tiny = minimum_version.to_s.split('.').collect { |v| v.to_i }
|
20
|
+
end
|
21
|
+
met = false
|
22
|
+
if Smurftp::VERSION::MAJOR > major
|
23
|
+
met = true
|
24
|
+
elsif Smurftp::VERSION::MAJOR == major
|
25
|
+
if Smurftp::VERSION::MINOR > minor
|
26
|
+
met = true
|
27
|
+
elsif Smurftp::VERSION::MINOR == minor
|
28
|
+
met = Smurftp::VERSION::TINY >= tiny
|
29
|
+
end
|
30
|
+
end
|
31
|
+
met
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/smurftp'
|
3
|
+
|
4
|
+
class SmurftpConfigurationTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@config_file = File.dirname(__FILE__) + '/../lib/smurftp/templates/smurftp_config.yaml'
|
7
|
+
@multisite_config_file = File.dirname(__FILE__) + '/../lib/smurftp/templates/smurftp_multisite_config.yaml'
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def test_hash_symbolize_keys
|
12
|
+
assert_equal({:yada => 'yada'}, {'yada' => 'yada'}.symbolize_keys!)
|
13
|
+
expected = {:yada => {:yada => {:yada => 'yada'}}}
|
14
|
+
sample = {'yada' => {'yada' => {'yada' => 'yada'}}}
|
15
|
+
assert_equal expected, sample.symbolize_keys!
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def test_configuration
|
20
|
+
config = Smurftp::Configuration.new(@config_file)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def test_multisite_configuration
|
25
|
+
config = Smurftp::Configuration.new(@multisite_config_file, 'site1')
|
26
|
+
puts config.inspect
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/test/shell_test.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/smurftp'
|
3
|
+
|
4
|
+
class SmurftpShellTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@config = File.dirname(__FILE__) + '/../lib/smurftp/templates/smurftp_config.yaml'
|
7
|
+
@smurftp = Smurftp::Shell.new(@config)
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def test_should_parse_list
|
12
|
+
lists = [
|
13
|
+
['1,2,3',['1','2','3']],
|
14
|
+
['1-4,^3',['1','2','4']],
|
15
|
+
['1,2,3-6,^4',['1','2','3','5','6']],
|
16
|
+
['1,2,3-6,!4',['1','2','3','5','6']],
|
17
|
+
['^4,1-6',['1','2','3','5','6']]
|
18
|
+
].each do |input, expected|
|
19
|
+
assert_equal expected, @smurftp.parse_list(input)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def test_should_parse_range
|
25
|
+
assert_equal ['1','2','3','4'], @smurftp.parse_range('1-4')
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def test_should_parse_file_for_sub_dirs
|
30
|
+
file_paths = [
|
31
|
+
['one/two/three/file.txt',['one','one/two','one/two/three']],
|
32
|
+
['file.txt',[]]
|
33
|
+
].each do |file,expanded|
|
34
|
+
assert_equal expanded, @smurftp.parse_file_for_sub_dirs(file)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def test_should_add_files_to_queue
|
40
|
+
@smurftp.add_files_to_queue(['1','2','3','4'])
|
41
|
+
assert_equal [0,1,2,3], @smurftp.upload_queue
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def test_upload_queue_should_be_unique
|
46
|
+
@smurftp.add_files_to_queue(['1','2','3','4','2','3','1','1','1'])
|
47
|
+
assert_equal [0,1,2,3], @smurftp.upload_queue
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def test_parse_command_should_parse_input
|
52
|
+
input = @smurftp.parse_command('all')
|
53
|
+
assert_equal Proc, input.class
|
54
|
+
|
55
|
+
input = @smurftp.parse_command('a')
|
56
|
+
assert_equal Proc, input.class
|
57
|
+
|
58
|
+
input = @smurftp.parse_command('ardvark')
|
59
|
+
assert_equal 'error', input
|
60
|
+
|
61
|
+
input = @smurftp.parse_command('allin')
|
62
|
+
assert_equal 'error', input
|
63
|
+
|
64
|
+
cmd, files = @smurftp.parse_command('1')
|
65
|
+
assert_equal ['1'], files
|
66
|
+
|
67
|
+
cmd = @smurftp.parse_command(' 1 ')
|
68
|
+
assert_equal 'error', cmd
|
69
|
+
|
70
|
+
cmd, files = @smurftp.parse_command('1,2,3,4')
|
71
|
+
assert_equal ['1','2','3','4'], files
|
72
|
+
|
73
|
+
cmd, files = @smurftp.parse_command('1-4')
|
74
|
+
assert_equal ['1','2','3','4'], files
|
75
|
+
|
76
|
+
cmd, files = @smurftp.parse_command('1-4,^3')
|
77
|
+
assert_equal ['1','2','4'], files
|
78
|
+
|
79
|
+
cmd, files = @smurftp.parse_command('^3,1-4')
|
80
|
+
assert_equal ['1','2','4'], files
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def test_hash_symbolize_keys
|
85
|
+
assert_equal({:yada => 'yada'}, {'yada' => 'yada'}.symbolize_keys!)
|
86
|
+
expected = {:yada => {:yada => {:yada => 'yada'}}}
|
87
|
+
sample = {'yada' => {'yada' => {'yada' => 'yada'}}}
|
88
|
+
assert_equal expected, sample.symbolize_keys!
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: divineflame-smurftp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Gruner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-05 00:00:00 -08:00
|
13
|
+
default_executable: smurftp
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Smurftp is a command-line utility that searches a specified directory and creates a queue of recently modified files for quickly uploading to a remote server over FTP.
|
17
|
+
email: andrew@divineflame.com
|
18
|
+
executables:
|
19
|
+
- smurftp
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- VERSION.yml
|
26
|
+
- README.mkdn
|
27
|
+
- bin/smurftp
|
28
|
+
- lib/smurftp
|
29
|
+
- lib/smurftp/shell.rb
|
30
|
+
- lib/smurftp/version.rb
|
31
|
+
- lib/smurftp/templates
|
32
|
+
- lib/smurftp/templates/smurftp_multisite_config.yaml
|
33
|
+
- lib/smurftp/templates/smurftp_config.yaml
|
34
|
+
- lib/smurftp/configuration.rb
|
35
|
+
- lib/smurftp.rb
|
36
|
+
- test/shell_test.rb
|
37
|
+
- test/configuration_test.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/divineflame/smurftp
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --inline-source
|
43
|
+
- --charset=UTF-8
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.2.0
|
62
|
+
signing_key:
|
63
|
+
specification_version: 2
|
64
|
+
summary: Command-line utility for uploading recently modified files to a server
|
65
|
+
test_files: []
|
66
|
+
|