Last active
August 14, 2019 12:04
-
-
Save RichardFevrier/bc95c07faf3601bf9ed24ec813d9d53a to your computer and use it in GitHub Desktop.
ObjC cleaning
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
folder="$SRCROOT/$TARGET_NAME"; | |
find $folder -path '*.framework' -prune -o -name "*.m" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format -i |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 ! ✌️") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 ! ✌️") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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