#!/usr/bin/env ruby # # $Id: //guest/robert_cowham/perforce/utils/vss_rev_date_problems.rb#5 $ # # Author: Robert Cowham # Copyright (c) 2005 Robert Cowham # # =DESCRIPTION # Script to check for files in VSS where an earlier revision has a later date/time on it. # # Uses VSS OLE Automation # Documentation on VSS Object Model can be found at: # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvss/html/msdn_vssole.asp # # Usual disclaimers apply! require 'win32ole' require 'getoptlong' # Module for constants to be loaded into module VSS_CONST end @@verbose = nil class CheckFiles attr_reader :count, :rev_count, :err_count def initialize(vssdb) @vssdb = vssdb @count = 0 @rev_count = 0 @err_count = 0 end # Recurse down the list of VSS directories looking for files def vss_dir_tree(dir) begin root = @vssdb.VSSItem(dir, 1) @deleted_dirs_count += 1 # print "\'#{dir}\'\n" rescue begin root = @vssdb.VSSItem(dir, 0) rescue print "Problem with '#{dir}'\n" return end end items = root.Items(1) items.each{|item| if (item.Type == VSS_CONST::VSSITEM_PROJECT) subdir = item.Name vss_dir_tree("#{dir}/#{subdir}") else check_rev(dir, "#{dir}/#{item.Name}") end } end def get_rev(file) begin @vssdb.VSSItem(file, 1) rescue @vssdb.VSSItem(file, 0) end end def get_date(dt) # 2001/06/25 19:07:12 (date, time) = dt.split arr = date.split("/").map{|e| e.to_i} arr += time.split(":").map{|e| e.to_i} return Time.utc(*arr) end def check_rev(dir, file) @count += 1 item = get_rev(file) versions = item.Versions rev_hist = Hash.new versions.each{|ver| if ver.Action !~ /^Labeled/ rev_hist[ver.VersionNumber.to_i] = ver.Date end print "#{file} #{ver.VersionNumber} #{ver.Date} #{ver.Action}\n" if @@verbose } revs = rev_hist.keys.sort @rev_count += revs.size for i in 1..revs.size-1 if revs[i] != revs[i-1] + 1 @err_count += 1 print "Seq error: #{file} #{revs[i]} #{revs[i-1]}\n" end if get_date(rev_hist[revs[i]]) < get_date(rev_hist[revs[i-1]]) @err_count += 1 print "Date Seq error: #{file} #{revs[i]} #{rev_hist[revs[i]]} #{revs[i-1]} #{rev_hist[revs[i-1]]}\n" end end end end # # Main application class # class App VERSION = "$Revision: #5 $" REVISION_DATE = "$Date: 2005/10/31 $" AUTHOR = "Robert Cowham" # # Returns a version string similar to: # : Version: 1.2 Created on: 2002/05/08 by Jim Freeze # The version number is maintained by CVS. # The date is the last checkin date of this file. # def version "Version: #{VERSION.split[1]} Created on: " + "#{REVISION_DATE.split[1]} by #{AUTHOR}" end def initialize @debug = false # @verbose = false @user = nil @password = nil @srcsafeini = nil if 0 == ARGV.size STDERR.puts usage exit 1 end get_options rescue => err STDERR.puts err STDERR.puts usage exit 1 end # # Returns usage string # def usage <<-USAGE Usage: #{File.basename $0} -u -p -s [-v] file_or_dir -v|--verbose print intermediate steps to STDERR -u|--user SourceSafe user -p|--password SourceSafe password -s|--srcsafeini Full path to srcsafe.ini file USAGE end # # Processes command line arguments # def get_options opts = GetoptLong.new( [ '--verbose', '-v', GetoptLong::OPTIONAL_ARGUMENT], [ '--user', '-u', GetoptLong::REQUIRED_ARGUMENT], [ '--password', '-p', GetoptLong::REQUIRED_ARGUMENT], [ '--srcsafeini', '-s', GetoptLong::REQUIRED_ARGUMENT], [ '--help', '-h', GetoptLong::REQUIRED_ARGUMENT] ) opts.each do |opt, arg| case opt when "--verbose" @@verbose = true when "--user" @user = arg when "--password" @password = arg when "--srcsafeini" @srcsafeini = arg when "--help" puts usage else raise "Invalid option '#{opt}'." end end if ARGV.size != 1 puts usage raise "VSS Path argument required: [vssdir]\ne.g.\n \"\$/Project 1/subdir\"\n" end @root = ARGV[0] rescue NameError => err STDERR.puts "ERROR: #{err}" exit 1 rescue => err STDERR.puts "ERROR: #{err}" exit 1 end # # Launches the application # App.new.run # def run # Load up VSS Ole Automation vssdb = WIN32OLE.new('SourceSafe') WIN32OLE.const_load(vssdb, VSS_CONST) vssdb.Open(@srcsafeini, @user, @password) print "Checked revisions for VSS files in '#{@root}':\n" cf = CheckFiles.new(vssdb) cf.vss_dir_tree(@root) print "\n#{cf.err_count} file/rev errors out of #{cf.count} files, #{cf.rev_count} revs in total.\n" end#run end#App app = App.new.run