# # File:: %RS_TOOLSLIB%/util/findMakefiles.rb # Description:: ironruby script that recursively scans for projgen.config files and all recognised makefiles # it then produces a series of local *.makefiles files. # - each file contains the correct build directive to build the makefiles with the appropriate settings # # Author:: Derek Ward # Date:: 04th October 2012 # #----------------------------------------------------------------------------- # Uses #----------------------------------------------------------------------------- require 'RSG.Base.dll' require 'mscorlib' require 'System.Core' require 'pathname' require 'RSG.Pipeline.Core.dll' require 'RSG.Base.Configuration.dll' require 'RSG.Base.Windows.dll' require 'RSG.SourceControl.Perforce.dll' include System::IO include RSG::Base::Logging include RSG::Base::Logging::Universal include RSG::Base::OS include RSG::Base::Configuration include RSG::Base::Windows include RSG::Pipeline::Core include RSG::SourceControl::Perforce require 'pipeline/os/options' include Pipeline using_clr_extensions RSG::Base::Extensions using_clr_extensions System::Linq module FindMakeFiles #----------------------------------------------------------------------------- # Constants #----------------------------------------------------------------------------- # Order matters, slndefs should be converted after makefiles. MAKEFILE_SEARCHES = [ "*.makefile", "makefile.txt", "*.slndef" ] BUILDFILE_SEARCHES = [ "projgen.config" ] AUTHOR = 'RSGEDI Tools' EMAIL = 'RSGEDI Tools <*tools@rockstarnorth.com>' OPTIONS = [ LongOption::new( 'nonrecursive', LongOption::ArgType.None, '1', 'Do not recurse.' ), LongOption::new( 'exclude', LongOption::ArgType.Required, 'x', 'Exclusion Regex' ) ] class Utility #------------------------------------------------------------------ # search routine def Utility::search_files( searches, list, searchOptions, exclusionRegex, log ) searches.each do |search| files = Directory::GetFiles(Dir.pwd, search, searchOptions ) files = files.collect { |f| File.expand_path(f) } excluded = 0 if exclusionRegex # delete_if doesnt work!!!! newfiles = [] files.each do |f| if (f=~exclusionRegex) excluded += 1 log.Message " excluding #{f}" else newfiles << f end end files = newfiles end list.concat files log.Message "- Discovered #{files.length} x #{search} : #{excluded} excluded" if (files.length>0) end end end #----------------------------------------------------------------------------- # Implementation #----------------------------------------------------------------------------- if ( __FILE__ == $0 ) then # Initialise log and console output. puts "a" LogFactory.Initialize() puts "b" g_Log = LogFactory.method(:CreateUniversalLog).call( 'findMakefiles' ) puts "c" LogFactory.CreateApplicationConsoleLogTarget( ) puts "d" g_Options = OS::Options::new( OPTIONS ) puts "e" begin if ( g_Options.is_enabled?( 'help' ) ) g_Log.Message "#{__FILE__}" g_Log.Message "Usage:" g_Log.Message g_Options.usage() exit( 1 ) end g_Recurse = g_Options.get( 'nonrecursive' ) ? false : true searchOptions = g_Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly g_ExclusionRegex = nil if g_Options.has_option?( 'exclude' ) regex = g_Options.get( 'exclude' ) g_ExclusionRegex = Regexp.new( regex, 'i') g_Log.Message " " g_Log.Message "Excluding #{regex}" g_Log.Message " " end makefiles = [] buildfiles = [] # # Search recursively for specific files. # g_Log.Message " " g_Log.Message "--------------------- Recursive Directory Search --------------------" if g_Recurse g_Log.Message "------------------- Non Recursive Directory Search ------------------" unless g_Recurse g_Log.Message " Searching within #{Dir.pwd}..." Utility::search_files(MAKEFILE_SEARCHES, makefiles, searchOptions, g_ExclusionRegex, g_Log) Utility::search_files(BUILDFILE_SEARCHES, buildfiles,searchOptions, g_ExclusionRegex, g_Log) g_Log.Message " " g_Log.Message " Searching (walking up) #{Dir.pwd}..." # these buildfiles can be in a folder above! BUILDFILE_SEARCHES.each do |search| path_name = Pathname.new(Dir.pwd) begin path_name = path_name.parent if (path_name!=nil) files = Directory::GetFiles(path_name.to_s, search, SearchOption.TopDirectoryOnly) files = files.collect { |f| File.expand_path(f) } excluded = 0 if g_ExclusionRegex newfiles = [] files.each do |f| if (f=~g_ExclusionRegex) excluded += 1 #g_Log.Message " excluding #{f}" else newfiles << f end end files = newfiles end g_Log.Message "- Discovered #{files.length} x #{search} : #{excluded} excluded" if (files.length>0) buildfiles.concat files end end while (path_name!=nil && !path_name.root?) end g_Log.Message "---------------------------------------------------------------------" # # Get all the build files. # # - DW: TODO will conversion order become a concern? # Actually I don't think I can practically guarantee any order by virtue of the batching I do.... bah buildfiles = buildfiles.sort{|x, y| File.dirname(y).length <=> File.dirname(x).length} buildfile_hash = {} buildfiles.each do |build_file| f = File.open(build_file) lines = f.readlines fileScope = nil tmpFile = nil squiggle_depth = 0 lines.each do |line| #g_Log.Message ">>>#{line}" if (/\s*#(.*)/.match(line)) # ignore comments # deliberately left empty elsif fileScope != nil squiggle_depth += 1 if line.trim.ends_with("{") squiggle_depth -= 1 if line.trim.ends_with("}") if squiggle_depth<=0 fileScope = nil tmpFile = nil else g_Log.Message "Writing #{fileScope} : #{line}" tmpFile.write(line) end elsif (/(.*)\s*\{/.match(line)) filename = $1 g_Log.Message "Matched filename #{filename}" fileScope = Environment.ExpandEnvironmentVariables(filename) g_Log.Message "Creating #{fileScope}" tmpFile = File.open(fileScope) squiggle_depth += 1 elsif (/\s*(.+)\s*/.match(line)) # this is what we are looking for. setup_file = $1 # TODO : figure out why this aint workin #setup_file = System::Object::Environment::ExpandEnvironmentVariables(setup_file) #setup_file = File.expand_path(setup_file) #g_Log.Message setup_file buildfile_hash[setup_file] = build_file end end end # # Order hash - we have to match with the deepest project.config # all_makefiles = {} buildfile_hash.each_key do |key| all_makefiles[key] = [] end # I know hashes are unordered - this is ruby magic. buildfile_sorted = buildfile_hash.sort_by { |key, val| File.dirname(val).length }.reverse g_Log.Message " " g_Log.Message "-------------------------- ProjGen.Configs --------------------------" buildfile_sorted.each do |h| g_Log.Message "#{h[1]}:" g_Log.Message "\t( #{h[0]} )" end g_Log.Message "---------------------------------------------------------------------" g_Log.Message " " # # Construct a hash keyed by setup file and the makefiles beneath to process, # makefiles.each do |makefile| found = false # this deepest buildfile needs to match first buildfile_sorted.each do |a| setup_file = a[0] buildfile = a[1] #g_Log.Message "matching #{buildfile} for #{makefile}" dir = File.dirname(buildfile) if (makefile.include?(dir)) #g_Log.Message "#{f} chooses build setup file #{setup_file}" all_makefiles[setup_file] << makefile found = true break end end if (!found) g_Log.Error( "Makefile can't find a projgen.config in its source tree and above #{makefile}" ) end end # # each key is serialised to a ,makefiles file so that it can be converted externally # DW: - if I had designed the project generator to be a dll ( but I didn't ) I could have run it directly in here # i = 0 all_makefiles.each_pair do |build_file, makefiles| if (makefiles.length>0) File.open("#{i}.makefiles", 'w') do |f| f.puts("build #{build_file}\n") makefiles.each do |makefile| f.puts("#{makefile}\n") end end i+=1 end end rescue SystemExit => ex exit( ex.status ) rescue Exception => ex ConsoleLog::new( ) Log::Log__Error( "Unhandled error in findMakefiles.rb" ) Log::Log__Error( ex.backtrace.join("\n" ) + "\n" + ex.Message ) end end end # module findMakeFiles