We maintain a few different branches of the lldb sources, e.g. to add swift 
support, and the xcode project files have diverged over time from llvm.org to 
our github repositories making git merging a real pain.  The two biggest 
sources of pain are the BuildFiles and FileReferences sections of the project 
file, where we've managed to get the files in completely different orders 
across our different branches.

I threw together a quick script to sort the files in these sections, and to 
segregate the swift etc files that aren't on llvm.org into their own sections 
so they don't cause merge headaches as often.

If anyone is maintaining a fork/branch of lldb where they've added files to the 
xcode project file, this sorting will be need hand cleanup from them too.  I 
suspect that everyone outside apple would be using cmake and ignoring the xcode 
project files -- but if this is a problem, please let me know and I'll delay.

Right now my cleanup script looks like this

#! /usr/bin/ruby
#


## Sort the BuildFile and FileReference sections of an Xcode project file,
## putting Apple/github-local files at the front to avoid merge conflicts.
#
## Run this in a directory with a project.pbxproj file.  The sorted version
## is printed on standard output.
#


# Files with these words in the names will be sorted into a separate section;
# they are only present in some repositories and so having them intermixed 
# can lead to merge failures.
segregated_filenames = ["Swift", "repl", "RPC"]

if !File.exists?("project.pbxproj")
    puts "ERROR: project.pbxproj does not exist."
    exit(1)
end

beginning  = Array.new   # All lines before "PBXBuildFile section"
files      = Array.new   # PBXBuildFile section lines -- sort these
middle     = Array.new   # All lines between PBXBuildFile and PBXFileReference sections
refs       = Array.new   # PBXFileReference section lines -- sort these
ending     = Array.new   # All lines after PBXFileReference section

all_lines = File.readlines 'project.pbxproj'

state = 1 # "begin"
all_lines.each do |l|
    l.chomp
    if state == 1 && l =~ /Begin PBXBuildFile section/
        beginning.push(l)
        state = 2
        next
    end
    if state == 2 && l =~ /End PBXBuildFile section/
        middle.push(l)
        state = 3
        next
    end
    if state == 3 && l =~ /Begin PBXFileReference section/
        middle.push(l)
        state = 4
        next
    end
    if state == 4 && l =~ /End PBXFileReference section/
        ending.push(l)
        state = 5
        next
    end

    if state == 1
        beginning.push(l)
    elsif state == 2
        files.push(l)
    elsif state == 3
        middle.push(l)
    elsif state == 4
        refs.push(l)
    else
        ending.push(l)
    end
end

######### Sort FILES by the filename, putting swift etc in front

# key is filename
# value is array of text lines for that filename in the FILES text
# (libraries like libz.dylib seem to occur multiple times, probably
# once each for different targets).

files_by_filename = Hash.new { |k, v| k[v] = Array.new }

files.each do |l|
    # 2669421A1A6DC2AC0063BE93 /* MICmdCmdTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266941941A6DC2AC0063BE93 /* MICmdCmdTarget.cpp */; };

    if l =~ /^\s+([A-F0-9]{24})\s+\/\*\s+(.*?)\sin.*?\*\/.*?fileRef = ([A-F0-9]{24})\s.*$/
        uuid = $1
        filename = $2
        fileref = $3
        files_by_filename[filename].push(l)
    end
end

# clear the FILES array

files = Array.new

# add the lines in sorted order.  First swift/etc, then everything else.

segregated_filenames.each do |keyword|
    filenames = files_by_filename.keys
    filenames.select {|l| l.include?(keyword) }.sort.each do |fn|
        # re-add all the lines for the filename FN to our FILES array that we'll
        # be outputting.
        files_by_filename[fn].sort.each do |l|
            files.push(l)
        end
        files_by_filename.delete(fn)
    end
end

# All segregated filenames have been added to the FILES output array.
# Now add all the other lines, sorted by filename.

files_by_filename.keys.sort.each do |fn|
    files_by_filename[fn].sort.each do |l|
        files.push(l)
    end
end

######### Sort REFS by the filename, putting swift etc in front

refs_by_filename = Hash.new { |k, v| k[v] = Array.new }
refs.each do |l|
    # 2611FF12142D83060017FEA3 /* SBValue.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBValue.i; sourceTree = "<group>"; };

    if l =~ /^\s+([A-F0-9]{24})\s+\/\*\s+(.*?)\s\*\/.*$/
        uuid = $1
        filename = $2
        refs_by_filename[filename].push(l)
    end
end

# clear the refs array

refs = Array.new

# add the lines in sorted order.  First swift/etc, then everything else.


segregated_filenames.each do |keyword|
    filenames = refs_by_filename.keys
    filenames.select {|l| l.include?(keyword) }.sort.each do |fn|
        # re-add all the lines for the filename FN to our refs array that we'll
        # be outputting.
        refs_by_filename[fn].sort.each do |l|
            refs.push(l)
        end
        refs_by_filename.delete(fn)
    end
end

# All segregated filenames have been added to the refs output array.
# Now add all the other lines, sorted by filename.

refs_by_filename.keys.sort.each do |fn|
    refs_by_filename[fn].sort.each do |l|
        refs.push(l)
    end
end



####### output the sorted pbxproj

[ beginning, files, middle, refs, ending ].each do |arr|
    arr.each {|l| puts l}
end


I'll probably add something to fix up file UUIDs that have drifted over time 
across the repositories (using the llvm.org project.pbxproj as the definitive 
source) before I commit.  But this is the general idea.


Jason
_______________________________________________
lldb-dev mailing list
lldb-dev@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev

Reply via email to