# p4unknown.rb # Task: determine which files need to be "p4 add'ed." and offer options to do so. # # Expects parameters: # -p $p -c $c -u $u -a "%D" # Note that %D is depot syntax for current selected file or directory. # # num of calls to 'p4': 3 # status: tested on Darwin Mac OS X using P4Ruby API # R Cowham - converted to work fine on Windows # # Based on the original by Jeff Bowles which was: # Copyright 2004 Perforce Corporation, Inc. All rights reserved. # Changes Copyright 2005 Robert Cowham, MIT License require "P4" require 'getoptlong' require "find" require 'fox14' include Fox def convert_paths(arr) if RUBY_PLATFORM.match("win32") arr.collect! {|e| e.tr('/', '\\')} else arr.collect! {|e| e.tr('\\', '/')} end end verboseOption = false defaultPort = nil defaultUser = nil defaultClient = nil addToP4 = false options = GetoptLong.new( [ '--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT], [ '--add', '-a', GetoptLong::NO_ARGUMENT], [ '--user', '-u', GetoptLong::REQUIRED_ARGUMENT], [ '--port', '-p', GetoptLong::REQUIRED_ARGUMENT], [ '--client', '-c', GetoptLong::REQUIRED_ARGUMENT], [ '--help', '-h', GetoptLong::REQUIRED_ARGUMENT], [ '--quiet', '-q', GetoptLong::REQUIRED_ARGUMENT] ) options.each do |opt, arg| case opt when "--verbose" verboseOption = true when "--add" addToP4 = true when "--user" defaultUser = arg when "--client" defaultClient = arg when "--port" defaultPort = arg when "--quiet" puts "'--quiet' not implemented yet." when "--help" puts options.Usage end end file_args = ARGV p4 = P4.new p4.port = defaultPort if defaultPort != nil p4.user = defaultUser if defaultUser != nil p4.client = defaultClient if defaultClient != nil p4.tagged p4.parse_forms p4.exception_level = 1 p4.connect class FileMainWindow < FXMainWindow def initialize(anApp, p4, search_root, files) # Initialize base class first super(anApp, "Files Present in Client Workspace directories", nil, nil, DECOR_ALL, 0, 0, 400, 300) buttons = FXHorizontalFrame.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH) # Place the list in a sunken frame sunkenFrame = FXVerticalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, 0, 0, 0, 0, 0, 0, 0, 0) fileList = FXList.new(sunkenFrame, nil, 0, LIST_EXTENDEDSELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y) addBtn = FXButton.new(buttons, "Add to Perforce") cancelBtn = FXButton.new(buttons, "Close") addBtn.connect(SEL_COMMAND) do |sender, selector, data| files = Array.new fileList.each { |item| files << item.getText() if item.isSelected() } p4.run_add(files) exit end cancelBtn.connect(SEL_COMMAND) {exit} fileList.appendItem("Search root: #{search_root}") fileList.appendItem("List of files present in workspace, but unknown to Perforce:") files.each do |file| fileList.appendItem(file) end fileList.appendItem("Total files: #{files.size}") end def create super show(PLACEMENT_SCREEN) end end begin #----------------------------------------------------------- # first call to P4: 'p4 client -o' #----------------------------------------------------------- cl_spec = p4.fetch_client cl_name = cl_spec['Client'] cl_root = cl_spec['Root'] search_root = cl_root if file_args # print "File args: '#{file_args}'\n" where = p4.run_where(file_args)[0] # print "Where #{where}\n" search_root = where['path'].strip # print "Search root: '#{search_root}'\n" if search_root =~ /\\\.\.\.$/ search_root = search_root[0..search_root.size - 5] end print "Search root: '#{search_root}'\n" end #----------------------------------------------------------- # second call to P4: 'p4 fstat //myclient/...' #----------------------------------------------------------- ret = p4.run_fstat("//#{cl_name}/...").delete_if { |r| r['headAction'] == 'delete' } # # at this point, we create two arrays to hold # the filenames: # allFilesPerforce - from "p4 fstat //myclient/..." # allFilesPresent - from "Find.find(cl_root)" # we can use set operations for the tricky stuff, and # it's a great advert for Ruby. # allFilesPerforce = ret.collect { |r| r['clientFile'] } allFilesPresent = [] Find.find(search_root) do |f| Find.prune if f == "." || f == ".." allFilesPresent << f if File.stat(f).file? end convert_paths(allFilesPresent) convert_paths(allFilesPerforce) newFiles = (allFilesPresent - allFilesPerforce) if addToP4 ret = p4.run_add(newFiles) else FXApp.new("P4Unknown", "FXRuby") do |theApp| FileMainWindow.new(theApp, p4, search_root, newFiles) theApp.create theApp.run end end # puts "List of files known to Perforce, but not (yet) synced to workspace:" # puts (allFilesPerforce - allFilesPresent) rescue P4Exception p4.errors.each { |e| $stderr.puts( e ) } raise end p4.disconnect