-
Notifications
You must be signed in to change notification settings - Fork 6
/
prsync_transfer
executable file
·210 lines (190 loc) · 7.35 KB
/
prsync_transfer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/ruby
############################################################
#
# Title: Parallel rsync transfer utility
# Created: Nov 30, 2012
# Author: rshott@sfu.ca
############################################################
############################################################
# CONSTANTS
############################################################
A_TO_Z = ('a'..'z').to_a
############################################################
# Global - Needed for keeping track of child processes
############################################################
$children = Array.new
############################################################
# METHODS
############################################################
def start_parallel_rsync(group)
for i in group do
while max_prsyncs_reached?
sleep 30
end
$children << fork { system("/usr/bin/rsync" \
" #{ARGV[0]}" \
" --include='#{i}*'" \
" --include='#{i.upcase}*'" \
" --exclude='/*'" \
" #{ARGV[1].chomp('/')}/" \
" #{ARGV[2].chomp('/')}" \
" 1> #{ARGV[3].chomp('/')}/#{i}.log" \
" 2> #{ARGV[3].chomp('/')}/#{i}_error.log")
check_for_errors($?, i) }
Process.detach($children.last)
end
end
def max_prsyncs_reached?
return false if $children.length < 4
limit = Array.new
$children.each do |x|
limit << true if pid_exists?(x)
return true if limit.length == 4
end
return false
end
def wait_for_any_pids_running
$children.each { |p|
Process.wait(p) if pid_exists?(p)
}
end
def non_alpha_character_rsync
result = system("/usr/bin/rsync" \
" #{ARGV[0]}" \
" --exclude='[a-z]*'" \
" --exclude='[A-Z]*'" \
" --exclude='.*'" \
" --exclude=' *'" \
" #{ARGV[1].chomp('/')}/" \
" #{ARGV[2].chomp('/')}" \
" 1> #{ARGV[3].chomp('/')}/non-alpha_character.log" \
" 2> #{ARGV[3].chomp('/')}/non-alpha_character_error.log")
if result
puts "The non-alpha character transfers completed successfully"
else
puts "The non-alpha character transfers did not exit with 0 - #{$?} - check its logs"
end
end
def leading_whitespace_rsync
result = system("/usr/bin/rsync" \
" #{ARGV[0]}" \
" --include=' *'" \
" --exclude='/*'" \
" #{ARGV[1].chomp('/')}/" \
" #{ARGV[2].chomp('/')}" \
" 1> #{ARGV[3].chomp('/')}/leading_whitespace.log" \
" 2> #{ARGV[3].chomp('/')}/leading_whitespace_error.log")
if result
puts "The leading whitespace transfers completed successfully"
else
puts "The leading whitespace transfers did not exit with 0 - #{$?} - check its logs"
end
end
def hidden_rsync
result = system("/usr/bin/rsync" \
" #{ARGV[0]}" \
" --include='.*'" \
" --exclude='/*'" \
" #{ARGV[1].chomp('/')}/" \
" #{ARGV[2].chomp('/')}" \
" 1> #{ARGV[3].chomp('/')}/hidden_folders.log" \
" 2> #{ARGV[3].chomp('/')}/hidden_folders_error.log")
if result
puts "The hidden folders transfer completed successfully"
else
puts "The hidden folders transfer did not exit with 0 - #{$?} - check its logs"
end
end
def check_for_errors(exitcode, letter)
unless exitcode != 0
puts "The '#{letter}*' & '#{letter.upcase}*' transfers completed successfully"
else
puts "The '#{letter}*' & '#{letter.upcase}*' transfers did not exit with 0 - #{exitcode} - check its logs"
end
end
def pid_exists?(pid)
begin
Process.kill(0, pid)
return true
rescue
return false
end
end
def ctrl_c
puts " ctrl+c caught"
$children.each { |c| if pid_exists?(c)
puts "Killing child process #{c}"
Process.kill('KILL', c)
end }
exit 1
end
############################################################
# MAIN
############################################################
if ARGV[0].eql?('-h') or ARGV[0].eql?('--help')
puts "Version 2.0\n" \
"Author: Riley Shott (rshott@sfu.ca)\n" \
"https://github.com/Ginja/Admin_Scripts/blob/master/prsync_transfer\n\n" \
"Capabilities: This utility will rsync all the contents of one folder into another but perform some of the transfer in parallel.\n" \
"The alpha character rsync will be done in batches of 4. New alpha character transfers will start when old transfers finish (give or take 30 seconds).\n" \
"All other jobs are done serially. You will receive a report at the end of the command letting you know which transfers experienced errors.\n\n" \
"Job options & order:\n" \
" 1. alpha characters (i.e. Aa-Zz) \n" \
" 2. non-alpha characters (ex: 1_folder, _file)\n" \
" 3. files and folders with a leading whitespace (ex: ' somefoldername')\n" \
" 4. hidden files and folders (ex: .itsasecret) \n\n" \
"Usage: #{__FILE__} <-rsync_options> <source> <target> <log_location> (jobs_to_run EX: 1-3)\n" \
"By default, this utility will run jobs 1-4. You can specify the transfers you want to do:\n" \
" ./prsync_transfer -avP ~/source ~/target ~/log 3-4\n" \
" ./prsync_transfer -avP ~/source ~/target ~/log 1-2\n" \
"You can also specify your own includes and excludes (mind the quotes):\n" \
" ./prsync_transfer \"-avP --exclude=Caches*\" ~/source ~/target ~/log 1\n"
exit 0
end
# Fail early, fail hard
begin
message = Array.new
message << "Usage: #{__FILE__} <-rsync_options> <source> <target> <log_location> (jobs_to_run EX: 1-3)" unless ARGV.length == 4 or ARGV.length == 5
message << "Error: Could not find rsync at /usr/bin/rsync" unless File.exists?('/usr/bin/rsync')
message << "Error: Source destination does not exist" unless File.exists?(ARGV[1])
message << "Error: Target destination does not exist" unless File.exists?(ARGV[2])
message << "Error: Log location does not exist" unless File.exists?(ARGV[3])
message << "Error: Source destination must be a folder" unless File.directory?(ARGV[1])
message << "Error: Target desintation must be a folder" unless File.directory?(ARGV[2])
message << "Error: Log location must be a folder" unless File.directory?(ARGV[3])
raise unless message.empty?
rescue
message.each {|m| puts m}
exit 1
end
unless ARGV.length == 4
if ARGV[4].to_s.length == 1
rsyncs_to_run = ARGV[4]
else
rsyncs_to_run = ARGV[4].gsub(/[-]/,' ').split
rsyncs_to_run = (rsyncs_to_run[0]..rsyncs_to_run[1]).to_a
end
else
rsyncs_to_run = ('1'..'4').to_a
end
rsyncs_to_run.each {|n|
case n
when '1'
trap("SIGINT") { ctrl_c }
start_parallel_rsync(A_TO_Z)
when '2'
non_alpha_character_rsync
when '3'
leading_whitespace_rsync
when '4'
hidden_rsync
else
puts "Did not recognize the following job option - #{n}\n" \
"Job options:\n" \
" 1. alpha characters\n" \
" 2. non-alpha characters\n" \
" 3. files and folders with a leading whitespace\n" \
" 4. hidden files and folders\n"
end
}
wait_for_any_pids_running