=begin This program removes file/folder(s) from Visual Studio Deployment Project File. =end require 'fileutils' module VdProject class Through def initialize(a, line) @proj = a @line = line end def read(x) nil end def save(f) f.puts @line end end class Entry def initialize(a, line) @proj = a @key = nil @MsmKey = nil @OwnerKey = nil @MsmSig = nil end def read(x) if x.strip == '}' return nil elsif x =~ /MsmKey.+:([_0-9A-F]+)"/ @MsmKey = x @key = $1 elsif x =~ /OwnerKey/ @OwnerKey = x elsif x =~ /MsmSig/ @MsmSig = x end self end def save(f) if @proj.key?(@key) f.puts ' "Entry"' f.puts ' {' f.puts @MsmKey f.puts @OwnerKey f.puts @MsmSig f.puts ' }' end end end class Hierarchy def initialize(a, line) @proj = a @entries = [] @state = nil end def read(x) unless @state if x =~ /\A\s*"Entry"\s*\Z/ @entries << @state = Entry.new(@proj, x) elsif x.strip == '}' return nil end else @state = @state.read(x) end self end def save(f) f.puts ' "Hierarchy"' f.puts ' {' @entries.each do |e| e.save(f) end f.puts ' }' end end module ItemEntry def contains?(fn) if String === fn || Symbol === fn fn = [fn.to_s] end fn.each do |f| if @name =~ /#{f}/ STDOUT.puts "remove #{@name}" return true end end nil end end class FileEntry include ItemEntry def initialize(a, line, key) @key = key @proj = a a.add_file(key, self) @lines = [line] @name = nil @removed = false @nest = 0 end attr_accessor :removed def read(x) @lines << x @nest += 1 if x.strip == '{' if x =~ /\A\s*"SourcePath".+?"8:(.+?)"\Z/ @name = $1.gsub(/\\\\/, '/') elsif x.strip == '}' @nest -= 1 return nil if @nest == 0 end self end def save(f) unless @removed @lines.each do |x| f.puts x end end end end class FileSection def initialize(a, line) @proj = a @entries = [] @state = nil end def create_entry(line, key) FileEntry.new(@proj, line, key) end def read(x) unless @state if x =~ /\A\s*"\{[-0-9A-F]+\}:([_0-9A-F]+)"\s*\Z/ @entries << @state = create_entry(x, $1) elsif x.strip == '}' return nil end else @state = nil unless @state.read(x) end self end def save(f) f.puts ' "File"' f.puts ' {' @entries.each do |x| x.save(f) end f.puts ' }' end end class MergeModule < FileSection def initialize(a, line) super(a, line) end def save(f) f.puts ' "MergeModule"' f.puts ' {' @entries.each do |x| x.save(f) end f.puts ' }' end end class FolderEntry include ItemEntry def initialize(a, line, key) @proj = a a.add_folder self @lines = [Through.new(a, line)] @removed = false @state = nil @name = '' end attr_accessor :removed, :name def read(x) unless @state if x =~ /\A\s*"Folders"\Z/ @lines << @state = FoldersSection.new(@proj, x, @name) else @lines << Through.new(@proj, x) if x.strip == '}' return nil elsif x =~ /\A\s*"Name".+?"8:(.+?)"\Z/ @name = "#{@name}/#{$1}" end end else @state = nil unless @state.read(x) end self end def save(f) unless @removed @lines.each do |line| line.save(f) end end end end class FolderSection < FileSection def initialize(a, line) super(a, line) end def name '' end def create_entry(line, key) ent = FolderEntry.new(@proj, line, key) ent.name = name ent end def save(f) f.puts ' "Folder"' f.puts ' {' @entries.each do |x| x.save(f) end f.puts ' }' end end class FoldersSection < FolderSection def initialize(a, line, name) super(a, line) @name = name end attr_reader :name def save(f) f.puts ' "Folders"' f.puts ' {' @entries.each do |x| x.save(f) end f.puts ' }' end end class VdProj def initialize(fn = nil) @lines = [] @files = {} @folders = [] @state = nil read(fn) if fn end def read(fn) File.open(fn).each_line do |line| line.rstrip! if @state @state = @state.read(line) else if line =~ /\A\s*"Hierarchy"\Z/ @lines << @state = Hierarchy.new(self, line) elsif line =~ /\A\s*"File"\Z/ @lines << @state = FileSection.new(self, line) elsif line =~ /\A\s*"MergeModule"\Z/ @lines << @state = MergeModule.new(self, line) elsif line =~ /\A\s*"Folder"\Z/ @lines << @state = FolderSection.new(self, line) else @lines << Through.new(self, line) end end end.close end def save(fn) File.open(fn, 'w') do |f| @lines.each do |line| line.save(f) end end end def add(x) @lines << x end def key?(key) @files[key] end def add_file(k, v) @files[k] = v end def add_folder(f) @folders << f end def remove(files) @files.each do |k, v| next unless v if v.contains?(files) v.removed = true @files[k] = nil end end @folders.each do |f| if f.contains?(files) f.removed = true end end self end end end if __FILE__ == $0 if ARGV.size == 0 STDERR.puts 'usage: ruby delnode.rb vdproj node-name(use x/y/z format) [node-name ...]' exit end fn = ARGV.shift FileUtils.cp fn, "#{fn}.back" VdProject::VdProj.new(fn).remove(ARGV).save("#{fn}.new") end