################################################################## # Licensing Information # # # # The following code is licensed, as standalone code, under # # the Ruby License, unless otherwise directed within the code. # # # # For information on the license of this code when distributed # # with and used in conjunction with the other modules in the # # Amp project, please see the root-level LICENSE file. # # # # © Michael J. Edgar and Ari Brown, 2009-2010 # # # ################################################################## module Amp module Core module Support # This creates an opener that prepends a directory to all # File opening, allowing repository formats to worry only # about file paths relative to the repository root. class RootedOpener attr_reader :root attr_accessor :create_mode attr_accessor :default alias_method :base, :root ## # Creates a new opener with a root of +base+, and also set to open files in # the .hg subdirectory. If you set .default = :open_file, it will no longer # open files in the .hg subdir. # # @param [String] base the root directory of the repository this opener will be # used on def initialize(base) @root = File.expand_path base @create_mode = nil @default = :open_hg end ## # Returns the path to the opener's root. # # @return path to the opener's root, as an absolute path. def path case @default when :open_file "#{root}/" when :open_hg "#{root}/.hg/" when :open_git "#{root}/.git" else raise abort "Unknown opener format #{@default.inspect}" end end ## # Read the file passed in with mode 'r'. # Synonymous with File.open(+file+, 'r') {|f| f.read } and # File.read(+file+) # # @param [String] file the relative path to the file we're opening # @return [String] the contents of the file def read(file) res = nil open(file, 'r') {|f| res = f.read } res end alias_method :contents, :read ## # Opens up the given file, exactly like you would do with File.open. # The parameters are the same. Defaults to opening a file in the .hg/ # folder, but if @default == :open_file, will open it from the working # directory. # # If the mode includes write privileges, then the write will use an # atomic temporary file. # # @param [String] file the path to the file to open # @param [String] mode the read/write mode to open with (standard # C choices here) # @yield Can yield the opened file if the block form is used def open(file, mode='r', &block) if @default == :open_file open_file file, mode, &block else open_hg file, mode, &block end end def join(file) File.join(root, file) end ## # Opens a file in the .hg repository using +@root+. This method # operates atomically, and ensures that the file is always closed # after use. The temporary files (while being atomically written) # are stored in "#{@root}/.hg", and are deleted after use. If only # a read is being done, it instead uses Kernel::open instead of # File::amp_atomic_write. # # @param [String] file the file to open # @param [String] mode the mode with which to open the file ("w", "r", "a", ...) # @yield [file] code to run on the file # @yieldparam [File] file the opened file def open_hg(file, mode='w', &block) open_up_file File.join(root, ".hg"), file, mode, &block end ## # Opens a file in the repository (not in .hg). # Writes are done atomically, and reads are efficiently # done with Kernel::open. THIS IS NOT +open_up_file+!!! # # @param [String] file the file to open # @param [String] mode the mode with which to open the file ("w", "r", "a", ...) # @yield [file] code to run on the file # @yieldparam [File] file the opened file def open_file(file, mode='w', &block) open_up_file root, file, mode, &block end ## # This does the actual opening of a file. # # @param [String] dir This dir is where the temp file is made, but ALSO # the parent dir of +file+ # @param [String] file Just the file name. It must exist at "#{dir}/#{file}" def open_up_file(dir, file, mode, &block) path = File.join dir, file if mode == 'r' # if we're doing a read, make this super snappy Kernel::open path, mode, &block else # we're doing a write File::amp_atomic_write path, mode, @create_mode, dir, &block end end end end end end