From ac4d99b0300b271da0589f26aa94e4b45588c4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konrad=20Ko=C5=82akowski?= Date: Wed, 19 Oct 2022 10:37:52 +0200 Subject: [PATCH] Model: Added cleaning documentation cache --- DevCleaner.xcodeproj/project.pbxproj | 4 ++ .../Entries/DocumentationCacheFileEntry.swift | 37 +++++++++++++++ DevCleaner/Model/XcodeFiles.swift | 47 ++++++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 DevCleaner/Model/Entries/DocumentationCacheFileEntry.swift diff --git a/DevCleaner.xcodeproj/project.pbxproj b/DevCleaner.xcodeproj/project.pbxproj index fce6629..57de7a4 100644 --- a/DevCleaner.xcodeproj/project.pbxproj +++ b/DevCleaner.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 7164260C20B8903000D47EF2 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7164260B20B8903000D47EF2 /* StoreKit.framework */; }; 716667D0221A26BA004D4FC4 /* FileManager+HomeFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716667CF221A26BA004D4FC4 /* FileManager+HomeFolder.swift */; }; 7169D2B027B32A8E00882E03 /* Digest+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7169D2AF27B32A8E00882E03 /* Digest+Helpers.swift */; }; + 717A3EC928FC3DDC002A0C8F /* DocumentationCacheFileEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717A3EC828FC3DDC002A0C8F /* DocumentationCacheFileEntry.swift */; }; 717A9F1B22DBAF9300682A0A /* OldDocumentationFileEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717A9F1A22DBAF9300682A0A /* OldDocumentationFileEntry.swift */; }; 717AB6B620C71F4D0096743C /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 717AB6B520C71F4D0096743C /* LoadingView.swift */; }; 7185E5D320D0775200C1C918 /* DonationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7185E5D220D0775200C1C918 /* DonationViewController.swift */; }; @@ -88,6 +89,7 @@ 7164260B20B8903000D47EF2 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; 716667CF221A26BA004D4FC4 /* FileManager+HomeFolder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+HomeFolder.swift"; sourceTree = ""; }; 7169D2AF27B32A8E00882E03 /* Digest+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Digest+Helpers.swift"; sourceTree = ""; }; + 717A3EC828FC3DDC002A0C8F /* DocumentationCacheFileEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentationCacheFileEntry.swift; sourceTree = ""; }; 717A9F1A22DBAF9300682A0A /* OldDocumentationFileEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OldDocumentationFileEntry.swift; sourceTree = ""; }; 717AB6B520C71F4D0096743C /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = ""; }; 7185E5D220D0775200C1C918 /* DonationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DonationViewController.swift; sourceTree = ""; }; @@ -315,6 +317,7 @@ 71FD37D6206AD6BE0042812D /* ArchiveFileEntry.swift */, 71FD37D8206AD72C0042812D /* DeviceSupportFileEntry.swift */, 71FD37DC206AD76D0042812D /* DerivedDataFileEntry.swift */, + 717A3EC828FC3DDC002A0C8F /* DocumentationCacheFileEntry.swift */, 714AB65E22DA87FA00A7FBB7 /* DeviceLogsFileEntry.swift */, 717A9F1A22DBAF9300682A0A /* OldDocumentationFileEntry.swift */, ); @@ -440,6 +443,7 @@ 719B25D9205ECA53007560C0 /* Version.swift in Sources */, 71B01E8E20824F2A00940041 /* XcodeEntryCellView.swift in Sources */, 715E8C3D216566FD0059A2E5 /* Weak.swift in Sources */, + 717A3EC928FC3DDC002A0C8F /* DocumentationCacheFileEntry.swift in Sources */, 717A9F1B22DBAF9300682A0A /* OldDocumentationFileEntry.swift in Sources */, 71FD37DD206AD76D0042812D /* DerivedDataFileEntry.swift in Sources */, 71A2C1202668FB1200F502A0 /* FeedbackMailer.swift in Sources */, diff --git a/DevCleaner/Model/Entries/DocumentationCacheFileEntry.swift b/DevCleaner/Model/Entries/DocumentationCacheFileEntry.swift new file mode 100644 index 0000000..bb4ba8d --- /dev/null +++ b/DevCleaner/Model/Entries/DocumentationCacheFileEntry.swift @@ -0,0 +1,37 @@ +// +// DocumentationCacheFileEntry.swift +// DevCleaner +// +// Created by Konrad Kołakowski on 16/10/2022. +// Copyright © 2022 One Minute Games. All rights reserved. +// +// DevCleaner is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// DevCleaner is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with DevCleaner. If not, see . + +import Foundation +import AppKit + +public final class DocumentationCacheFileEntry: XcodeFileEntry { + // MARK: Properties + public let version: Version + + public init(version: Version, selected: Bool) { + self.version = version + + super.init(label: "Cache from Xcode \(version)", + tooltipText: "Documentation cache files from Xcode \(version)", + icon: .system(name: NSImage.multipleDocumentsName), + tooltip: true, + selected: selected) + } +} diff --git a/DevCleaner/Model/XcodeFiles.swift b/DevCleaner/Model/XcodeFiles.swift index 6590937..5309cca 100644 --- a/DevCleaner/Model/XcodeFiles.swift +++ b/DevCleaner/Model/XcodeFiles.swift @@ -39,7 +39,7 @@ public protocol XcodeFilesDeleteDelegate: AnyObject { final public class XcodeFiles { // MARK: Types public enum Location: Int, CaseIterable { - case deviceSupport, archives, derivedData, logs, oldDocumentation + case deviceSupport, archives, derivedData, documentationCache, logs, oldDocumentation } // MARK: Constants @@ -89,6 +89,7 @@ final public class XcodeFiles { .deviceSupport: XcodeFileEntry(label: "Device Support", tooltipText: "Systems debug symbols that are retained every version, usually you need only the newer ones", tooltip: true, selected: true), .archives: XcodeFileEntry(label: "Archives", tooltipText: "Archived apps, delete only if you sure you don't need them", tooltip: true, selected: false), .derivedData: XcodeFileEntry(label: "Derived Data", tooltipText: "Cached projects data & symbol index", tooltip: true, selected: false), + .documentationCache: XcodeFileEntry(label: "Documentation Cache", tooltipText: "Documentation cache for each Xcode version", tooltip: true, selected: true), .logs: XcodeFileEntry(label: "Old Simulator & Device Logs", tooltipText: "Old device logs & crashes databases, only most recent ones are usually needed as they are copies of previous ones.", tooltip: true, selected: true), .oldDocumentation: OldDocumentationFileEntry(selected: false) ] @@ -428,6 +429,9 @@ final public class XcodeFiles { case .derivedData: entry.addChildren(items: self.scanDerivedDataLocations()) + + case .documentationCache: + entry.addChildren(items: self.scanDocumentationCacheLocations()) case .logs: entry.addChildren(items: self.scanLogsLocations()) @@ -620,6 +624,47 @@ final public class XcodeFiles { return results } + private func scanDocumentationCacheLocations() -> [XcodeFileEntry] { + let docsCacheLocation = self.userDeveloperFolderUrl.appendingPathComponent("Xcode/DocumentationCache") + + var entries = [DocumentationCacheFileEntry]() + + // get documentation cache locations + if let cacheFolders = try? FileManager.default.contentsOfDirectory(at: docsCacheLocation, includingPropertiesForKeys: nil, options: Self.scanFileEnumerationOptions) { + for cacheFolder in cacheFolders { + if let xcodeDocsCaches = try? FileManager.default.contentsOfDirectory(at: cacheFolder, includingPropertiesForKeys: nil, options: Self.scanFileEnumerationOptions) { + for xcodeDocsCache in xcodeDocsCaches { + if let xcodeVersion = Version(describing: xcodeDocsCache.lastPathComponent) { + // check if we already have entry for this Xcode version, and create it if not + if let oldXcodeEntryIndex = entries.firstIndex(where: { $0.version == xcodeVersion }) { + entries[oldXcodeEntryIndex].addPath(path: xcodeDocsCache) + } else { + let newEntry = DocumentationCacheFileEntry(version: xcodeVersion, selected: true) + newEntry.addPath(path: xcodeDocsCache) + + entries.append(newEntry) + } + } else { + log.warning("XcodeFiles: Invalid Xcode version while searching for documentation caches: \(xcodeDocsCache.lastPathComponent)") + } + } + } + } + } + + // sort + entries.sort { lhs, rhs in + return lhs.version > rhs.version + } + + // deselect first one + if let firstEntry = entries.first { + firstEntry.deselectWithChildItems() + } + + return entries + } + private func scanLogsLocations() -> [XcodeFileEntry] { struct LogEntry { let path: URL