Last active
March 30, 2022 08:05
-
-
Save kientux/0029c7f8483fd280f9f994e8278fa8b9 to your computer and use it in GitHub Desktop.
Remove old Xcode archives. Can be set up to run every day to free up CI machine disk. Default will remove all development/staging archives.
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
import Foundation | |
extension FileManager { | |
typealias FileExistResult = (exist: Bool, isDirectory: Bool) | |
func checkExists(at path: String) -> FileExistResult { | |
var fileIsDirectory: ObjCBool = false | |
let exist = fileExists(atPath: path, isDirectory: &fileIsDirectory) | |
return (exist, fileIsDirectory.boolValue) | |
} | |
func isDirectoryExists(at path: String) -> Bool { | |
let result = checkExists(at: path) | |
return result.exist && result.isDirectory | |
} | |
} | |
struct XCArchive: Codable { | |
var appName: String | |
var date: Date | |
var path: URL | |
} | |
func removeOldArchives() { | |
let fm = FileManager.default | |
let xcodeArchivePath = "Library/Developer/Xcode/Archives" | |
let archivesPath = URL(string: fm.homeDirectoryForCurrentUser.appendingPathComponent(xcodeArchivePath).path)! | |
let dateFormatter = DateFormatter() | |
dateFormatter.dateFormat = "yyyy-MM-dd HH.mm.ss" | |
do { | |
let contents = try fm.contentsOfDirectory(at: archivesPath, includingPropertiesForKeys: nil) | |
var archives: [XCArchive] = [] | |
for path in contents where fm.isDirectoryExists(at: path.path) { | |
let subcontents = try fm.contentsOfDirectory(at: path, includingPropertiesForKeys: nil) | |
for subpath in subcontents where fm.isDirectoryExists(at: subpath.path) { | |
if subpath.pathExtension != "xcarchive" { | |
continue | |
} | |
let name = subpath.lastPathComponent | |
let regex = try NSRegularExpression(pattern: "(.+) ([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}\\.[0-9]{2}\\.[0-9]{2})\\.xcarchive") | |
let matches = regex.matches(in: name, options: [], range: NSRange(location: 0, length: name.count)) | |
guard let match = matches.first else { | |
continue | |
} | |
var appName: String? | |
var date: Date? | |
for i in 1..<match.numberOfRanges { | |
let range = match.range(at: i) | |
let s = (name as NSString).substring(with: range) | |
switch i { | |
case 1: | |
appName = s | |
case 2: | |
date = dateFormatter.date(from: s) | |
default: | |
break | |
} | |
if let appName = appName, let date = date { | |
archives.append(XCArchive(appName: appName, date: date, path: subpath)) | |
} | |
} | |
} | |
} | |
var groupedArchives: [String: [XCArchive]] = [:] | |
for archive in archives { | |
if groupedArchives[archive.appName] == nil { | |
groupedArchives[archive.appName] = [] | |
} | |
groupedArchives[archive.appName]?.append(archive) | |
} | |
for (name, archives) in groupedArchives { | |
if name.lowercased().contains("dev") | |
|| name.lowercased().contains("stage") | |
|| name.lowercased().contains("staging") { | |
for archive in archives { | |
print("Remove dev/staging archive:", archive.path.path) | |
try fm.removeItem(at: archive.path) | |
} | |
continue | |
} | |
if archives.isEmpty || archives.count == 1 { | |
continue | |
} | |
var sorted = archives.sorted(by: { $0.date.timeIntervalSince1970 > $1.date.timeIntervalSince1970 }) | |
sorted.removeFirst() | |
for archive in sorted { | |
print("Remove old release archive:", archive.path.path) | |
try fm.removeItem(at: archive.path) | |
} | |
} | |
} catch { | |
print(error) | |
} | |
} | |
removeOldArchives() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment