require 'rubygems' require 'progressbar' require 'thread' # Parses a checkpoint with {#read_in} then creates a directory tree, depot list and protections table class Parse attr_accessor :checkpoint, :filetree, :filesize def initialize(checkpoint, filetree, protections_table) # @return [Dir_Tree] @filetree A representation of the Perforce instances file tree # @filetree.root is the root of the tree ('//') @filetree = filetree # @return [File] @checkpoint The checkpoint to be parsed @checkpoint = File.open(checkpoint) # @return [Protections_Table] @protections_table the list of all current protections entries @protections_table = protections_table # @return [Integer] @filesize The filesize of @checkpoint, for calculating percentage read @filesize = File.size(checkpoint) end # Read in the checkpoint line by line # The method has two threads which share a queue # read_thread reads in each line of @checkpoint, and adds it to the queue if =~ /@pv@/ # proc_thread deals with processing the queue def read_in queue = Queue.new mutex = Mutex.new cond = ConditionVariable.new pbar = ProgressBar.new("% read", 100) pbar2 = ProgressBar.new("% processed", 100) read_thread = Thread.new do position = 0 next_line = @checkpoint.gets curr = next_line.size while next_line curr += next_line.size percentage = (curr/@filesize.to_f)*100.0 if percentage <= 100.0 pbar.set(percentage) end position += 1 if next_line =~ /^@pv@/ mutex.synchronize do queue.push(next_line) cond.signal end end next_line = @checkpoint.gets end pbar.finish p 'waiting for processing of the file to finish' q_size = queue.size pbar2.set((q_size/position)*100.0) until queue.empty? cond.signal pbar2.set((queue.size/q_size)*100.0) end end proc_thread = Thread.new do while true mutex.synchronize do cond.wait(mutex) next_record = queue.shift put_record(next_record) end end end read_thread.join end # If find_nonwc_paths returns with an array of paths, put record adds them to @filetree # @param [String] record is a single line of the checkpoint passed from {#read_in} proc_thread def put_record(record) paths = find_nonwc_paths(record) unless paths.empty? paths.each { |path| @filetree.add_path(path) } end end # Find non-wildcard paths if record contains "db.rev*" and add them to the file tree # Find depot names if record contains "db.depot" and add them to the file tree's depot list' # Find protections if record contains "db.protect" and add them to @protections_table.table # # @note all paths will be non-wildcard, since the search has been narrowed to just "db.rev*" paths # # @param [String] record is a single line of the checkpoint passed {#put_record} # # @return [Array] if record contains 'db.rev*' return all paths from the record as an array def find_nonwc_paths(record) #array is required for the return as some records such as db.integ have 2+ paths ret = [] split_rec = record.split("@") if split_rec.include?("db.depot") @filetree.add_depot(split_rec[5]) elsif split_rec.include?("db.protect") @protections_table.add_protection_record(split_rec) elsif split_rec.include?("db.group") @protections_table.groups[:split_recs] << split_rec end unless split_rec.grep(/db\.rev/).empty? split_rec.each { |part| if part =~ /^\/\// ret << part end } end return ret end end