Class: Cowtech::Lib::Shell
Overview
A class which provides some useful method for interaction with files and processes.
Instance Method Summary collapse
-
#copy(args) ⇒ Object
Copy files to a destination directory.
-
#create_directories(args) ⇒ Object
Create directories (and any missing parent directory).
-
#delete_files!(args) ⇒ Object
Delete files/directories.
-
#file_check?(args) ⇒ Boolean
Perform a check on a file or directory.
-
#find_by_extension(args) ⇒ Object
Returns a list of files in specified paths which have one of requested extensions.
-
#find_by_pattern(args) ⇒ Object
Returns a list of files in specified paths which matchs one of requested patterns.
-
#initialize(console = nil) ⇒ Shell
constructor
Creates a new shell.
-
#open_file(args) ⇒ Object
Opens a file.
-
#rename(args) ⇒ Object
Rename a file.
-
#run(args) ⇒ Object
Run a command.
Constructor Details
Instance Method Details
#copy(args) ⇒ Object
Copy files to a destination directory.
Arguments:
-
files: List of entries to copy/move
-
dest: Destination file/directory
-
must_move: Move instead of copy
-
dest_is_dir: Whether destination is a directory
-
exit_on_fail: Whether abort on failure
-
show_error: Whether show errors occurred
Returns: true if operation had success, false otherwise.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/cowtech-lib/shell.rb', line 206 def copy(args) rv = true move = args[:move] dest = args[:dest] # If we are copy or moving to a directory if args[:destination_is_directory] then files = (args[:files] || []).force_array dest += "/" if self.file_check?(file: dest, tests: :directory) && dest !~ /\/$/ files.each do |file| begin if move == true then FileUtils.move(file, dest, {noop: @console.skip_commands, verbose: @console.skip_commands}) else FileUtils.cp_r(file, dest, {noop: @console.skip_commands, verbose: @console.skip_commands, remove_destination: true}) end rescue StandardError => e if args[:show_errors] && e. =~ /^Permission denied - (.+)/ then self.error("Cannot #{must_move ? "move" : "copy"} entry <text style=\"bold white\">#{file}</text> to non-writable entry <text style=\"bold white\">#{dest}</text>", false, false, false) if m != nil end rv = false rescue Exception => e if args[:show_errors] then @console.error("Cannot #{move ? "move" : "copy"} following entries to <text style=\"bold white\">#{dest}</text>:", dots: false) @console.indent_region(3) do files.each do |afile| @console.write(msg: afile, dots: false) end end @console.write("#{@console.indentator * @console.indent_level}due to an error: #{e}\n", dots: false, fatal: args[:fatal]) end rv = false end break if !rv end else # If we are copying or moving to a file files = args[:files] if !files.kind_of?(String) && !dest.kind_of?(String) == true then @console.error("Cowtech::Lib::Shell#copy: To copy a single file, both files and dest arguments must be a string.", dots: false, fatal: args[:fatal]) rv = false else dst_dir = File.dirname(dest) if !self.file_check?(file: dst_dir, tests: [:exists, :directory]) then self.create_directories(files: dst_dir, mode: 0755, fatal: args[:fatal], show_errors: args[:show_errors]) end begin if move then FileUtils.move(files, dest, {noop: @console.skip_commands, verbose: @console.skip_commands}) else FileUtils.cp(files, dest, {noop: @console.skip_commands, verbose: @console.skip_commands}) end rescue StandardError => e @console.error("Cannot #{move ? "move" : "copy"} entry <text style=\"bold white\">#{files}</text> to non-writable entry<text style=\"bold white\"> #{dest}</text>", dots: false, fatal: args[:fatal]) if args[:show_errors] && (e. =~ /^Permission denied - (.+)/) rv = false rescue Exception => e @console.error("Cannot #{move ? "move" : "copy"} <text style=\"bold white\">#{files}</text> to <text style=\"bold_white\">#{dest}</text> due to an error: <text style=\"bold red\">#{e}</text>", dots: false, fatal: args[:fatal]) if args[:show_errors] rv = false end end end rv ? rv : @console.status(:fail, fatal: args[:fatal]) end |
#create_directories(args) ⇒ Object
Create directories (and any missing parent directory).
Arguments:
-
files: List of directories to create
-
mode: Octal mode for newly created directories
-
exit_on_fail: Whether abort on failure
-
show_error: Whether show errors occurred
Returns: true if operation had success, false otherwise.
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 |
# File 'lib/cowtech-lib/shell.rb', line 150 def create_directories(args) rv = true files = args[:files].force_array files.each do |file| if self.file_check?(files: file, tests: :exists) then if self.file_check?(files: file, tests: :directory) == true then @console.error("Cannot create following directory <text style=\"bold white\">#{file}</text> because it already exists.", dots: false, fatal: args[:fatal]) else @console.error("Cannot create following directory <text style=\"bold white\">#{file}</text> because it already exists as a file", dots: false, fatal: args[:fatal]) end rv = false end if rv then begin FileUtils.makedirs(file, {mode: args[:mode] || 0755, noop: @console.skip_commands, verbose: @console.skip_commands}) rescue StandardError => e if args[:show_errors] && e. =~ /^Permission denied - (.+)/ then @console.error("Cannot create following directory in non writable parent: <text style=\"bold white\">#{$1}</text>.", dots: false, fatal: args[:fatal]) end rv = false rescue Exception => e if args[:show_errors] == true then @console.error("Cannot create following directory:", dots: false) @console.indent_region(3) do files.each do |afile| @console.write(msg: afile, dots: false) end end @console.write("#{@console.indentator * @console.indent_level}due to an error: #{e}\n", dots: false, fatal: args[:fatal]) end rv = false end end break if !rv end rv ? rv : @console.status(:fail, fatal: args[:fatal]) end |
#delete_files!(args) ⇒ Object
Delete files/directories.
Arguments:
-
files: List of entries to delete
-
exit_on_fail: Whether abort on failure
-
show_error: Whether show errors occurred
Returns: true if operation had success, false otherwise.
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 |
# File 'lib/cowtech-lib/shell.rb', line 108 def delete_files!(args) rv = true files = args[:files].force_array begin FileUtils.rm_r(files, {noop: @console.skip_commands, verbose: @console.skip_commands, secure: true}) rescue StandardError => e if args[:show_errors] == true then if e. =~ /^Permission denied - (.+)/ then @console.error("Cannot remove following non writable entry: #{$1}", dots: false, fatal: args[:fatal]) elsif e. =~ /^No such file or directory - (.+)/ then @console.error("Cannot remove following non existent entry: #{$1}", dots: false, fatal: args[:fatal]) end end rv = false rescue Exception => e if args[:show_error] == true then @console.error("Cannot remove following entries:", dots: false) @console.indent_region(3) do files.each do |afile| @console.write(msg: afile, dots: false) end end @console.write(msg: "#{@console.indentator * @console.indent_level}due to an error: #{e}\n", dots: false, fatal: args[:fatal]) end rv = false end rv ? rv : @console.status(:fail, fatal: args[:fatal]) end |
#file_check?(args) ⇒ Boolean
Perform a check on a file or directory.
Arguments:
-
name: The file/directory path
-
tests: A list of tests to execute
Valid tests are:
-
:fc_exists: Check if the file exists
-
:fc_read: Check if the file is readable
-
:fc_write: Check if the file writeable
-
:fc_exec: Check if the file executable
-
:fc_dir: Check if the file is a directory
-
:fc_symlink: Check if the file is symbolic link
Returns: true if any of tests had success, false otherwise
85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/cowtech-lib/shell.rb', line 85 def file_check?(args) rv = false tests = (args[:tests] || [:exists]).force_array if args[:file] then rv = true tests.each do |test| method = (test.to_s + "?").to_sym rv = rv && (FileTest.respond_to?(method) ? FileTest.send(method, args[:file]) : false) end end rv end |
#find_by_extension(args) ⇒ Object
Returns a list of files in specified paths which have one of requested extensions.
Arguments:
-
paths: List of path in which seach
-
extensions: List of requested extensions
Returns: List of found files.
346 347 348 349 350 351 352 |
# File 'lib/cowtech-lib/shell.rb', line 346 def find_by_extension(args) args[:patterns] = (args[:extensions] || "").force_array.collect do |extension| Regexp.new(extension + "$", Regexp::IGNORECASE) end self.find_by_pattern(args) end |
#find_by_pattern(args) ⇒ Object
Returns a list of files in specified paths which matchs one of requested patterns.
Arguments:
-
paths: List of path in which seach
-
patterns: List of requested patterns
Returns: List of found files.
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/cowtech-lib/shell.rb', line 306 def find_by_pattern(args) # TODO: E se patterns รจ vuoto? rv = [] paths = args[:paths].force_array string_patterns = args[:patterns].force_array if paths.length > 0 then # Convert patterns to regexp patterns = string_patterns.collect do |pattern| pattern.is_a?(Regexp) ? pattern : Regexp.new(pattern, Regexp::IGNORECASE) end # For each path paths.each do |path| Find.find(path) do |file| # Find files matchs = false patterns.each do |pattern| # Match patterns if file =~ pattern then matchs = true break end end rv << file if matchs end end rv end end |
#open_file(args) ⇒ Object
Opens a file.
Arguments:
-
name: The file path
-
mode: Open mode, like the one in File.new
-
codec: The encoding used to open the file. UNUSED FOR NOW!
Returns: A new File object
60 61 62 63 64 65 66 67 |
# File 'lib/cowtech-lib/shell.rb', line 60 def open_file(args) begin File.new(args[:name], (args[:mode] || "r") + (args[:codec] ? ":#{args[:codec]}" : "")) rescue Exception => e @console.write(error: "Unable to open file #{name}: #{e}") nil end end |
#rename(args) ⇒ Object
Rename a file.
Arguments:
-
src: The file to rename
-
dst: The new name
-
exit_on_fail: Whether abort on failure
-
show_error: Whether show errors occurred
Returns: true if operation had success, false otherwise.
286 287 288 289 290 291 292 293 294 295 296 297 |
# File 'lib/cowtech-lib/shell.rb', line 286 def rename(args) rv = true if src.is_a?(String) && dst.is_a?(String) then rv = self.copy(from: src, to: dst, show_errors: args[:show_errors], fatal: args[:fatal]) else @console.error("Cowtech::Lib::Shell#rename: Both :src and :dst arguments must be a string.", dots: false, fatal: args[:fatal]) if args[:show_error] rv = false end rv ? rv : @console.status(:fail, fatal: args[:fatal]) end |
#run(args) ⇒ Object
Run a command.
Arguments:
-
msg: The message to show
-
command: The command to run
-
show_msg: If show the exit message
-
show_exit: If show the exit code
-
fatal: If abort on failure
Returns: An object which the status attribute is the exit status of the process, and the output attribute is the output of the command
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 |
# File 'lib/cowtech-lib/shell.rb', line 26 def run(args) rv = {status: 0, output: []} command = args[:command] @console.write(begin: args[:msg]) if args[:show_msg] if @console.show_commands then @console.warn("Will run command: \"#{command}\"", dots: false) @console.status(:ok) end if !@console.skip_commands then rv[:status] = Open4::open4(command + " 2>&1") { |pid, stdin, stdout, stderr| stdout.each_line do |line| rv[:output] << line print line if @console.show_outputs end }.exitstatus end rv[:output] = rv[:output].join("\n") @console.status(status: rv[:status] == 0 ? :ok : :fail, fatal: false) if args[:show_exit] exit(1) if args[:fatal] && rv[:status] != 0 rv end |