Skip to content

Instantly share code, notes, and snippets.

@TellowKrinkle
Last active May 10, 2021 02:36
Show Gist options
  • Save TellowKrinkle/e00ddfb0c64a6012f57609a10452813b to your computer and use it in GitHub Desktop.
Save TellowKrinkle/e00ddfb0c64a6012f57609a10452813b to your computer and use it in GitHub Desktop.
Script for PCSX2 to rename files to match a `.vcxproj.filters` file and update includes
#!/usr/bin/env ruby
require "fileutils"
require "nokogiri"
require "optparse"
require "pathname"
$absolutes = []
parser = OptionParser.new do |opts|
opts.banner = "Usage: #{$PROGRAM_NAME} file.vcxproj.filters [options]"
opts.on("--absolute INCLUDE", "Force an include to always use absolute paths") do |absolute|
$absolutes << absolute
end
end
parser.parse!
if ARGV.count == 1 then
$filename = Pathname::new(ARGV[0]).expand_path
else
abort(parser.help)
end
$cwd = Pathname::new(".").expand_path
$absolutes = $absolutes.map { |file| Pathname::new(file).expand_path($cwd).relative_path_from($cwd) }
xml = File.open($filename) { |f| Nokogiri::XML(f) }
Filter = Struct::new(:file, :loc)
def find_filters(node, filters=[])
file = node.attribute "Include"
filter = node.element_children.find { |child| child.name == "Filter" }
if !file.nil? && !filter.nil? then
filters << Filter::new(file, filter.child)
else
node.element_children.each { |child| find_filters(child, filters) }
end
return filters
end
class RenameList
def initialize(filters)
@renames = {}
filters.each do |filter|
old = Pathname::new(filter.file.value.gsub("\\", "/")).expand_path($filename.parent).relative_path_from($cwd)
new = Pathname::new(filter.loc.to_s.gsub("\\", "/")).join(old.basename)
@renames[old] = new
end
end
def new_name(file)
if @renames.has_key? file then
return @renames[file]
else
return file
end
end
def fixup_includes(file)
file = Pathname::new(file).expand_path($cwd).relative_path_from($cwd)
new_file = new_name(file)
content = File.read(file, :encoding => 'iso-8859-1')
begin
newcontent = content.gsub(/#include "([^"]+)"/) do |full_include|
old_include = Pathname::new($1).expand_path(file.parent).relative_path_from($cwd)
[".", "gui", "x86"].each do |dir|
if !old_include.exist? then
old_include = Pathname::new($1).expand_path(Pathname::new(dir).expand_path).relative_path_from($cwd)
end
end
if !old_include.exist? then
next full_include
end
new_include = new_name(old_include)
relative = new_include.relative_path_from(new_file.parent)
absolute = new_include.relative_path_from(".")
if $absolutes.include? old_include then
# puts "Forcing absolute for #{new_include}"
choice = absolute
elsif relative.to_s.count("/") <= absolute.to_s.count("/") then
choice = relative
else
choice = absolute
end
next "\#include \"#{choice}\""
end
if content != newcontent then
File.write(file, newcontent, :encoding => 'iso-8859-1')
end
rescue ArgumentError => err
STDERR.puts "Unable to update #{file}: #{err}"
end
end
def fixup_cmake(file)
content = File.read(file)
content.gsub!(/[^\s\(\)]+/) do |word|
if @renames.has_key? Pathname::new(word) then
next @renames[Pathname::new(word)]
else
next word
end
end
File.write(file, content)
end
def to_s
@renames.map { |from, to| "#{from} => #{to}" }.join "\n"
end
end
filters = find_filters xml.root
renames = RenameList::new(filters)
Dir.glob("**/*.cpp") { |file| renames.fixup_includes file }
Dir.glob("**/*.h") { |file| renames.fixup_includes file }
Dir.glob("**/*.inl") { |file| renames.fixup_includes file }
renames.fixup_cmake "CMakeLists.txt"
filters.each do |filter|
file = Pathname::new(filter.file.value.gsub("\\", "/")).expand_path($filename.parent).relative_path_from($cwd)
new_file = renames.new_name file
filter.file.value = new_file.expand_path($cwd).relative_path_from($filename.parent).to_s.gsub("/", "\\")
begin
FileUtils.mkdir_p(new_file.parent)
File.rename(file, new_file)
rescue
STDERR.puts "Failed to rename #{file} to #{new_file}"
end
end
File.write($filename, xml.to_s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment