Skip to content

Instantly share code, notes, and snippets.

@RichardFevrier
Last active August 14, 2019 12:04
Show Gist options
  • Save RichardFevrier/bc95c07faf3601bf9ed24ec813d9d53a to your computer and use it in GitHub Desktop.
Save RichardFevrier/bc95c07faf3601bf9ed24ec813d9d53a to your computer and use it in GitHub Desktop.
ObjC cleaning
BasedOnStyle: LLVM
BreakBeforeBraces: Linux
ColumnLimit: 135 # fine with a macbook pro 15" screen
IndentWidth: 4
IndentWrappedFunctionNames: true
MaxEmptyLinesToKeep: 2
ObjCBinPackProtocolList: Always
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
TabWidth: 4
UseTab: Never
#!/bin/bash
folder="$SRCROOT/$TARGET_NAME";
find $folder -path '*.framework' -prune -o -name "*.m" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format -i
#!/usr/bin/ruby
xcworspacePath = ARGV[0]
schemeName = ARGV[1]
workspaceName = ARGV[2]
classesPath = ARGV[3]
if !xcworspacePath
abort("No xcworspacePath supplied")
end
if !schemeName
abort("No schemeName supplied")
end
if !workspaceName
abort("No workspaceName supplied")
end
if !classesPath
abort("No classesPath supplied")
end
######################################################################
def testImports(xcworspacePath, schemeName, workspaceName, classesPath)
total = 0
Dir.glob("#{classesPath}/**/*.{h,m}") do |filepath|
if !filepath.include? ".framework"
text = File.read(filepath, :encoding => 'utf-8')
text.scan(/(\/\/.*#import.*)/).each do |match|
text [match[0]] = ""
File.open(filepath, 'w') do |file|
file.puts text
end
end
text = File.read(filepath, :encoding => 'utf-8')
text.scan(/(^#import.*)/).each do |match|
text [match[0]] = "//#{match[0]}"
File.open(filepath, 'w') do |file|
file.puts text
end
fileName = File.basename(filepath)
if isImportRequired(fileName, match[0], xcworspacePath, schemeName, workspaceName)
text ["//#{match[0]}"] = match[0]
else
text ["//#{match[0]}"] = ""
total += 1
end
File.open(filepath, 'w') do |file|
file.puts text
end
end
end
end
return total
end
def isImportRequired(fileName, import, xcworspacePath, schemeName, workspaceName)
`xcodebuild -scheme #{schemeName} -workspace #{workspaceName} build > /tmp/import_minimizer-build.log 2>&1`
if ($?.exitstatus != 0)
return true
else
puts("#{import} is not required in #{fileName}")
return false
end
end
######################################################################
imports = testImports(xcworspacePath, schemeName, workspaceName, classesPath)
puts(imports.to_s + " imports deleted ! ✌️")
#!/usr/bin/ruby
path = ARGV[0]
if !path
abort("No path supplied")
end
######################################################################
ObjcClass = Struct.new(:name, :path)
######################################################################
def getClasses(path)
classes = []
Dir.glob("#{path}/**/*.{h,m}") do |filepath|
if !filepath.include? ".framework"
text = File.read(filepath, :encoding => 'utf-8')
text.scan(/@(?:interface|implementation)\s*(\w*?)\W/).each do |match|
objcClass = ObjcClass.new(match[0], filepath)
if classes.select{ |item| item[:name] == objcClass.name }.empty?
classes.push(objcClass)
end
end
end
end
return classes
end
def getUnusedClasses(path, classes)
unused = []
for objcClass in classes
if unused.select{ |item| item[:name] == objcClass.name }.empty? && !isClassUsed(path, objcClass)
unused.push(objcClass)
end
end
return unused
end
def isClassUsed(path, objcClass)
Dir.glob("#{path}/**/*.{h,m,xib,storyboard,pch}") do |filepath|
if objcClass.name != File.basename(filepath, ".*")
text = File.read(filepath, :encoding => 'utf-8')
match = /#{Regexp.quote(objcClass.name)}/.match(text)
if match
return true
end
end
end
return false
end
def deleteClasses(classes)
for objcClass in classes
puts("Deleting " + objcClass.path.chop.chop)
begin
File.delete(objcClass.path.chop.concat("h"))
rescue
# puts("unable to delete " + objcClass.name + ".h")
end
begin
File.delete(objcClass.path.chop.concat("m"))
rescue
# puts("unable to delete " + objcClass.name + ".m")
end
begin
File.delete(objcClass.path.chop.concat("xib"))
rescue
# puts("unable to delete " + objcClass.name + ".xib")
end
end
end
def main(path)
puts("Finding classes")
classes = getClasses(path)
puts("Found " + classes.count.to_s + " classes")
unused = getUnusedClasses(path, classes)
puts("Found " + unused.count.to_s + " unused classes")
deleteClasses(unused)
return unused.count
end
######################################################################
total = 0
shouldStop = false
until shouldStop do
unused = main(path)
total += unused
shouldStop = unused == 0
end
puts(total.to_s + " classes deleted ! ✌️")
#!/usr/bin/ruby
path = ARGV[0]
if !path
abort("No path supplied")
end
######################################################################
ObjcClass = Struct.new(:name)
GroupClass = Struct.new(:name, :desc)
######################################################################
def getClasses(path)
classes = []
Dir.glob("#{path}/*.xcodeproj/*.pbxproj") do |filepath|
text = File.read(filepath, :encoding => 'utf-8')
text.scan(/PBXBuildFile section(?:.|[\r\n])*?PBXBuildFile section/).each do |match|
match.scan(/(\S*)\.(h|m)\s/).each do |match2|
objcClass = ObjcClass.new(match2[0])
if classes.select{ |item| item[:name] == objcClass.name }.empty?
classes.push(objcClass)
end
end
end
text.scan(/PBXFileReference section(?:.|[\r\n])*?PBXFileReference section/).each do |match|
match.scan(/(\S*)\.(h|m)\s/).each do |match2|
objcClass = ObjcClass.new(match2[0])
if classes.select{ |item| item[:name] == objcClass.name }.empty?
classes.push(objcClass)
end
end
end
end
return classes
end
def getNotExistingClasses(path, classes)
notExisting = []
for objcClass in classes
if notExisting.select{ |item| item[:name] == objcClass.name }.empty? && !isClassExisting(path, objcClass)
notExisting.push(objcClass)
end
end
return notExisting
end
def isClassExisting(path, objcClass)
Dir.glob("#{path}/**/*.{h,m}") do |filepath|
if !filepath.include? ".framework"
if File.basename(filepath, ".*").casecmp(objcClass.name) == 0
return true
end
end
end
return false
end
def deleteClasses(path, classes)
for objcClass in classes
puts("Deleting " + objcClass.name)
Dir.glob("#{path}/*.xcodeproj/*.pbxproj") do |filepath|
text = File.read(filepath, :encoding => 'utf-8')
text.scan(/(.*#{Regexp.quote(objcClass.name)}\.(h|m|xib).*)/).each do |match|
text [match[0]] = ""
end
File.open(filepath, 'w') do |file|
file.puts text
end
end
end
end
def getGroups(path)
groups = []
Dir.glob("#{path}/*.xcodeproj/*.pbxproj") do |filepath|
text = File.read(filepath, :encoding => 'utf-8')
text.scan(/(\w*\s\/\*\s\w*\s\*\/\s=\s{[\s\S]*?isa\s=\sPBXGroup;[\s\S]*?};)/).each do |match|
if name = match[0].match(/(\w*)/)
groupClass = GroupClass.new(name[0], match[0])
if groups.select{ |item| item[:name] == groupClass.name }.empty?
groups.push(groupClass)
end
end
end
end
return groups
end
def getEmptyGroups(groups)
emptyGroups = []
for groupClass in groups
if emptyGroups.select{ |item| item[:name] == groupClass.name }.empty? && isGroupEmpty(groupClass)
emptyGroups.push(groupClass)
end
end
return emptyGroups
end
def isGroupEmpty(groupClass)
match = /children\W*\);/.match(groupClass.desc)
if match
return true
end
return false
end
def deleteGroups(path, groups)
for groupClass in groups
puts("Deleting " + groupClass.name)
Dir.glob("#{path}/*.xcodeproj/*.pbxproj") do |filepath|
text = File.read(filepath, :encoding => 'utf-8')
text [groupClass.desc] = ""
text.scan(/(.*#{Regexp.quote(groupClass.name)}.*)/).each do |match|
text [match[0]] = ""
end
File.open(filepath, 'w') do |file|
file.puts text
end
end
end
end
def main(path)
puts("Finding Groups")
groups = getGroups(path)
puts("Found " + groups.count.to_s + " groups")
empty = getEmptyGroups(groups)
puts("Found " + empty.count.to_s + " empty groups")
deleteGroups(path, empty)
return empty.count
end
######################################################################
puts("Finding classes")
classes = getClasses(path)
puts("Found " + classes.count.to_s + " classes")
notExisting = getNotExistingClasses(path, classes)
puts("Found " + notExisting.count.to_s + " notExisting classes")
deleteClasses(path, notExisting)
puts(notExisting.count.to_s + " classes deleted ! ✌️")
total = 0
shouldStop = false
until shouldStop do
empty = main(path)
total += empty
shouldStop = empty == 0
end
puts(total.to_s + " groups deleted ! ✌️")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment