class Blufin::Files
Constants
- JAVA_AUTO_GENERATED_EVERY_RUN
- JAVA_AUTO_GENERATED_ONCE
Public Class Methods
Create a directory recursively (if it doesn't already exist). @return String
# File lib/core/files.rb, line 387 def self.create_directory(path) begin path = File.expand_path(path) FileUtils.mkpath(path) unless path_exists(path) path rescue => e Blufin::Terminal::print_exception(e) end end
Proxy function for the above. @return void
# File lib/core/files.rb, line 399 def self.create_path(path) raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String) create_directory(path) end
Deletes a file (if exists) @return void
# File lib/core/files.rb, line 331 def self.delete_file(path_and_file) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) FileUtils.rm(File.expand_path(path_and_file)) if file_exists(path_and_file) end
Get the file name ONLY (from a full path). @return string
# File lib/core/files.rb, line 413 def self.extract_file_name(path_and_file, include_extension = true) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) return File.basename(File.expand_path(path_and_file)) if include_extension return File.basename(File.expand_path(path_and_file), '*') unless include_extension end
Get the path name ONLY (from a full path). @return string
# File lib/core/files.rb, line 406 def self.extract_path_name(path_and_file) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) File.dirname(File.expand_path(path_and_file)) end
Returns TRUE or FALSE depending whether a path exists. @return void
# File lib/core/files.rb, line 345 def self.file_exists(path_and_file) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) File.exist?(File.expand_path(path_and_file)) end
Get and array of directories in a directory. @return Array
# File lib/core/files.rb, line 366 def self.get_dirs_in_dir(path, recursive = false) raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String) path = "/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}" raise RuntimeError, "Directory doesn't exist: #{path}" unless path_exists(path) dirs = Dir.glob("#{path}/**/*/") unless recursive root_dirs = [] root_length = path.split('/').length dirs.each do |dir| root_dirs << dir if dir.split('/').length == root_length + 1 end dirs = root_dirs end dirs.map! { |value| value.gsub(/\/\z/, '') } dirs.uniq! dirs.sort! dirs end
Get and array of files in a directory. @return Array
# File lib/core/files.rb, line 352 def self.get_files_in_dir(path, only_with_extension = nil) raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String) unless only_with_extension.nil? raise RuntimeError, "Expected String, instead got: #{path.class}" unless only_with_extension.is_a?(String) raise RuntimeError, 'only_with_extension must be alphanumeric & lowercase (no periods)' unless only_with_extension =~ /[a-z0-9]/ end path = "/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}" raise RuntimeError, "Directory doesn't exist: #{path}" unless path_exists(path) files = Dir.glob("#{path}/**/*.#{only_with_extension.nil? ? '*' : only_with_extension}") files.uniq.sort end
Returns TRUE if file is empty. Ignores spaces and new-line characters. @return bool
# File lib/core/files.rb, line 421 def self.is_empty(path_and_file) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) Blufin::Files::read_file(path_and_file).each do |line| line.strip! return false if line != '' end true end
Returns TRUE if path_and_file is a file, FALSE if it's a directory. File does not need to exist. @return bool
# File lib/core/files.rb, line 433 def self.is_file(path_and_file) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) path_and_file =~ /\.[a-z0-9]{1,10}$/i ? true : false end
Returns TRUE or FALSE depending whether a path exists. @return void
# File lib/core/files.rb, line 338 def self.path_exists(path) raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String) File.directory?(File.expand_path(path)) end
Get content of a file as an “Array of Lines” @return Array
# File lib/core/files.rb, line 311 def self.read_file(path_and_file, start_line = nil, end_line = nil) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) line_count = 0 path_and_file = File.expand_path(path_and_file) raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file) raise RuntimeError, "start_line (#{start_line}) cannot be bigger than end_line (#{end_line})." if (!start_line.nil? && !end_line.nil?) && (start_line > end_line) file_content = [] file = File.open(path_and_file).read file.gsub!(/\r\n?/, "\n") file.each_line do |line| line_count += 1 next if !start_line.nil? && start_line > line_count next if !end_line.nil? && end_line < line_count file_content << line end file_content end
Removes a line from a file. multiple_occurrences -> If set to TRUE, will remove ALL occurrences from file. @return void
# File lib/core/files.rb, line 284 def self.remove_line_from_file(path_and_file, regex, multiple_occurrences = false) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) path_and_file = File.expand_path(path_and_file) raise RuntimeError, "Expected Regexp to match to line, instead got: #{regex.class}" unless regex.is_a? Regexp raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file) new_lines = [] line_removed = false read_file(path_and_file).each do |line_content| line_content.gsub!(/\n\z/, '') line_content_to_match = line_content.strip if line_content_to_match =~ regex if multiple_occurrences next else unless line_removed line_removed = true next end end end new_lines << line_content end write_file(path_and_file, new_lines) end
Write an “Array of Lines” to a file – overwrites file if exists! @return String
# File lib/core/files.rb, line 186 def self.write_file(path_and_file, array_of_lines, write_empty_trailing_line: false) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) path_and_file = File.expand_path(path_and_file) # If this comes in as a string, convert it to an Array of lines. if array_of_lines.is_a?(String) array_of_lines_new = [] array_of_lines.split("\n").each { |line| array_of_lines_new << line.gsub("\n", '') } array_of_lines = array_of_lines_new end raise RuntimeError, "Expected an array of lines to write to file, instead got: #{array_of_lines.class}" unless array_of_lines.is_a? Array prepare_for_file_write(path_and_file) begin File.open(path_and_file, 'w') { |file| array_of_lines.each_with_index do |line, index| if index == array_of_lines.size - 1 file.write("#{line}") if line.to_s.strip != '' || write_empty_trailing_line else file.write("#{line}\n") end end file.close } rescue Exception => e Blufin::Terminal::print_exception(e) end path_and_file end
Writes a file (but only if content has changed). Returns true if file was overwritten, false if not. @return boolean
# File lib/core/files.rb, line 165 def self.write_file_if_changed(path_and_file, array_of_lines, write_empty_trailing_line: false) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) raise RuntimeError, "Expected Array, instead got: #{array_of_lines.class}" unless array_of_lines.is_a?(Array) # If file does not exist, writes it regardless and returns TRUE. unless Blufin::Files::file_exists(path_and_file) Blufin::Files::write_file(path_and_file, array_of_lines, write_empty_trailing_line: write_empty_trailing_line) return true end tmp_file = "/tmp/#{Blufin::Strings::random_string(2)}.txt" Blufin::Files::write_file(tmp_file, array_of_lines, write_empty_trailing_line: write_empty_trailing_line) target_file_hash = Digest::SHA1.hexdigest Blufin::Arrays::convert_line_array_to_string(Blufin::Files::read_file(path_and_file)).gsub(/\s/, '') tmp_file_hash = Digest::SHA1.hexdigest Blufin::Arrays::convert_line_array_to_string(Blufin::Files::read_file(tmp_file)).gsub(/\s/, '') if target_file_hash != tmp_file_hash FileUtils.mv(tmp_file, path_and_file) return true end false end
Same as write_file
() but for Java files. If arrange_imports = TRUE (default) it will sort the import statements in the same order as IntelliJ would. @return String
# File lib/core/files.rb, line 15 def self.write_file_java(path_and_file, array_of_lines, auto_generated = JAVA_AUTO_GENERATED_EVERY_RUN, test_annotations = true) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) auto_generated_valid = [nil, JAVA_AUTO_GENERATED_EVERY_RUN, JAVA_AUTO_GENERATED_ONCE] raise RuntimeError, "Expected .java file, instead got: #{path_and_file}" unless path_and_file =~ /\.java\z/ raise RuntimeError, "auto_generated must be one of the following: #{auto_generated_valid.join(', ')}" unless auto_generated.nil? || auto_generated_valid.include?(auto_generated) raise RuntimeError, "Expected Boolean, instead got: #{test_annotations.class}" unless !!test_annotations == test_annotations package = nil import_statements_one = [] import_statements_two = [] previous_was_blank = false annotations_one = [] annotations_two = [] contents = [] array_of_lines.each do |line| if contents.any? next if line.strip == '' && previous_was_blank previous_was_blank = false contents << line previous_was_blank = true if line.strip == '' next end if package.nil? && line.strip =~ /^package\s+[A-Za-z0-9\._-]+;(\s*#.*)?$/ # Get package. raise RuntimeError, "Package has a hyphen in it \xe2\x86\x92 \x1B[38;5;184m#{line.strip}\x1B[0m. When this file's contents were generated you forgot a .gsub() statement to replace it." if line.gsub(/(\s*#.*)?$/, '').strip =~ /-/ package = line.strip next elsif line.strip =~ /^import\s+[A-Za-z0-9\.*_-]+;$/ || line.strip =~ /^import\s+static\s+[A-Za-z0-9\.*_-]+;$/ # Get import statements. raise RuntimeError, "Import has a hyphen in it \xe2\x86\x92 \x1B[38;5;184m#{line.strip}\x1B[0m. When this file's contents were generated you forgot a .gsub() statement to replace it." if line.strip =~ /-/ import_statements_one << line.strip next elsif !contents.any? && line.strip =~ /^@(.)+$/ annotations_one << line.strip elsif !contents.any? && line.strip =~ /^(public|private|protected)\s+.*(class|enum)\s+.*\{(\s*\})?$/ contents << line.strip next end end raise RuntimeError, "Couldn't parse content for: #{path_and_file}" unless contents.any? # Add @AutoGenerated + @TestNotRequired stuff. import_statements_one << 'import org.blufin.base.annotations.AutoGenerated;' unless auto_generated.nil? import_statements_one << 'import org.blufin.base.annotations.TestNotRequired;' if test_annotations import_statements_one << 'import org.blufin.base.annotations.helper.ON;' unless auto_generated.nil? annotations_one.each do |annotation| next if %w(@TestNotRequired @AutoGenerated @AutoGenerated(ON.EVERY_RUN) @AutoGenerated(ON.CREATION_ONLY)).include?(annotation) annotations_two << annotation end annotations_two << '@TestNotRequired' if test_annotations annotations_two << ((auto_generated == JAVA_AUTO_GENERATED_EVERY_RUN) ? '@AutoGenerated(ON.EVERY_RUN)' : '@AutoGenerated(ON.CREATION_ONLY)') unless auto_generated.nil? annotations_two.uniq! import_statements_one.uniq! import_statements_one.sort! package_path = package.gsub(/package\s/, '').gsub(/;/, '').strip # Figure out which import statements to "keep" -- IE: Are they being used? import_statements_one.each do |import_statement| import_statement_path = [] import_statement_split = import_statement.gsub(/import\s/, '').gsub(/;/, '').strip.split('.') import_statement_split.each_with_index { |n, idx| import_statement_path << n unless idx == (import_statement_split.length - 1) } # Skip import if we're in the same package. next if import_statement_path.join('.') == package_path found = false is = import_statement.split('.') is = is[is.length - 1].gsub(';', '').strip if is == '*' import_statements_two << import_statement next end annotations_two.each do |annotation| if annotation =~ /@#{is}/ || annotation =~ /[\(\.]#{is}[\)\.]/ found = true break end end unless found contents.each do |content_line| if content_line =~ /[<\(\s{]#{is}[\.<>,\s\(\)]/ || content_line =~ /@#{is}[\(]?/ found = true break end end end import_statements_two << import_statement if found end import_statement_counter = {} import_statement_tracker = {} # Convert multiple imports to .* import_statements_two.each do |import_statement| is = import_statement.split('.') is = is.first(is.length - 1).join('.') import_statement_counter[is] = 0 if import_statement_counter[is].nil? import_statement_counter[is] += 1 import_statement_tracker[is] = [] if import_statement_tracker[is].nil? import_statement_tracker[is] << import_statement end import_statements_one = [] import_statements_two.each do |import_statement| is = import_statement.split('.') is = is.first(is.length - 1).join('.') if import_statement_counter[is] > 5 import_statements_one << "#{is}.*;" else import_statements_one << import_statement end end import_statements_one.uniq! import_statements_one.sort! # Re-assemble the file. final_written_java_non = 0 final_written_java = 0 final_contents = [package, ''] # Write NON-JAVA statements. import_statements_one.each do |import_statement| unless import_statement =~ /^import\s+java/ || import_statement =~ /^import\s+static/ final_contents << import_statement final_written_java_non += 1 end end static_statement_found = false # Write STATIC statements. import_statements_one.each do |import_statement| if import_statement =~ /^import\s+static/ unless static_statement_found final_contents << '' static_statement_found = true end final_contents << import_statement final_written_java += 1 end end final_contents << '' if final_written_java_non > 0 # Write JAVA statements. import_statements_one.each do |import_statement| if import_statement =~ /^import\s+java/ final_contents << import_statement final_written_java += 1 end end final_contents << '' if final_written_java > 0 annotations_two.each { |line| final_contents << line } if annotations_two.any? contents.each { |line| final_contents << line } if contents.any? return self.write_file(path_and_file, final_contents) end
Write a “String” to a file – overwrites file if exists! @return void
# File lib/core/files.rb, line 216 def self.write_file_string(path_and_file, content) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) path_and_file = File.expand_path(path_and_file) raise RuntimeError, "Expected String to write to file, instead got: #{content.class}" unless content.is_a? String prepare_for_file_write(path_and_file) begin File.open(path_and_file, 'w') { |file| file.write("#{content}") file.close } rescue Exception => e Blufin::Terminal::print_exception(e) end end
Writes a line to a file. regex -> If a value exists the program checks for this regex and writes on the line AFTER match(es). if nil (or not found), writes at the end of file. only_if_not_exists -> If TRUE, will add line only if it doesn't already exist. replace -> If TRUE, will replace file rather than writing on next line after regex. @return void
# File lib/core/files.rb, line 236 def self.write_line_to_file(path_and_file, line, regex = nil, only_if_not_exists = true, replace = false) raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String) path_and_file = File.expand_path(path_and_file) raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file) raise RuntimeError, "Expected String to write to file, instead got: #{line.class}" unless line.is_a? String raise RuntimeError, "Expected Regexp to match to line, instead got: #{regex.class}" unless regex.nil? || regex.is_a?(Regexp) raise RuntimeError, 'Cannot set replace to TRUE when regex is nil.' if regex.nil? && replace raise RuntimeError, 'only_if_not_exists must be set to FALSE when replace is TRUE.' if only_if_not_exists && replace new_lines = [] if only_if_not_exists line_found = false read_file(path_and_file).each do |line_content| line_content.gsub!(/\n\z/, '') line_found = true if line_content == line end return if line_found end if !regex.nil? && !replace regex_found = false line_inserted = false read_file(path_and_file).each do |line_content| line_content.gsub!(/\n\z/, '') regex_found = true if line_content =~ regex if regex_found && line_content !~ regex && !line_inserted new_lines << line line_inserted = true end new_lines << line_content end new_lines << line unless line_inserted elsif !regex.nil? && replace regex_found = false read_file(path_and_file).each do |line_content| line_content.gsub!(/\n\z/, '') if !regex_found && line_content =~ regex regex_found = true new_lines << line else new_lines << line_content end end end write_file(path_and_file, new_lines) end
Private Class Methods
Creates path (if not exists) and deletes file (if exists). @return void
# File lib/core/files.rb, line 442 def self.prepare_for_file_write(path_and_file) FileUtils::mkdir_p(File.dirname(path_and_file)) unless path_exists(File.dirname(path_and_file)) File.delete(path_and_file) if file_exists(path_and_file) end