From c2e1379df0c00d20a38695c75d4862fe3fb264bc Mon Sep 17 00:00:00 2001 From: Aleksei Minaev Date: Thu, 29 Aug 2019 12:11:45 +0200 Subject: [PATCH 1/2] Update AssetChecker.podspec --- AssetChecker.podspec | 1 + 1 file changed, 1 insertion(+) diff --git a/AssetChecker.podspec b/AssetChecker.podspec index ec7af47..9e9cad2 100644 --- a/AssetChecker.podspec +++ b/AssetChecker.podspec @@ -12,4 +12,5 @@ Pod::Spec.new do |s| s.ios.deployment_target = '8.0' s.source_files = "Classes/*.swift" s.preserve_paths = [ 'run' ] + s.swift_version = '4.0' end From a63b8605b7859771754d90b3f4b26e6d472c9c26 Mon Sep 17 00:00:00 2001 From: Aleksei Minaev Date: Thu, 29 Aug 2019 17:47:16 +0200 Subject: [PATCH 2/2] Update project to support CSV for checking multiple asset directories as input parameter --- Classes/main.swift | 34 ++++++++++++++----- .../AssetChecker.xcodeproj/project.pbxproj | 7 +++- .../Contents.json | 6 ++++ .../Contents.json | 20 +++++++++++ .../Contents.json | 20 +++++++++++ .../Images.xcassets/Contents.json | 6 ++++ .../NotUsedImage.imageset/Contents.json | 20 +++++++++++ Example/AssetChecker/ViewController.swift | 3 ++ 8 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 Example/AssetChecker/AnotherAssetCatalog.xcassets/Contents.json create mode 100644 Example/AssetChecker/AnotherAssetCatalog.xcassets/NotUsedImageInAnotherAssetCatalog.imageset/Contents.json create mode 100644 Example/AssetChecker/AnotherAssetCatalog.xcassets/UsedImageInAnotherAssetCatalog.imageset/Contents.json create mode 100644 Example/AssetChecker/Images.xcassets/Contents.json create mode 100644 Example/AssetChecker/Images.xcassets/NotUsedImage.imageset/Contents.json diff --git a/Classes/main.swift b/Classes/main.swift index c9cda15..502dc7e 100755 --- a/Classes/main.swift +++ b/Classes/main.swift @@ -4,7 +4,7 @@ import Foundation // Configure me \o/ var sourcePathOption:String? = nil -var assetCatalogPathOption:String? = nil +var assetCatalogPathOptions:[String]? = nil let ignoredUnusedNames = [String]() for (index, arg) in CommandLine.arguments.enumerated() { @@ -12,7 +12,7 @@ for (index, arg) in CommandLine.arguments.enumerated() { case 1: sourcePathOption = arg case 2: - assetCatalogPathOption = arg + assetCatalogPathOptions = arg.components(separatedBy: ",") default: break } @@ -23,12 +23,12 @@ guard let sourcePath = sourcePathOption else { exit(0) } -guard let assetCatalogAbsolutePath = assetCatalogPathOption else { +guard let assetCatalogAbsolutePaths = assetCatalogPathOptions else { print("AssetChecker:: error: Asset Catalog path was missing!") exit(0) } -print("Searching sources in \(sourcePath) for assets in \(assetCatalogAbsolutePath)") +print("Searching sources in \(sourcePath) for assets in \(assetCatalogAbsolutePaths)") /* Put here the asset generating false positives, For instance whne you build asset names at runtime @@ -55,7 +55,7 @@ func elementsInEnumerator(_ enumerator: FileManager.DirectoryEnumerator?) -> [St // MARK: - List Assets -func listAssets() -> [String] { +func listAssets(assetCatalogAbsolutePath: String) -> [String] { let extensionName = "imageset" let enumerator = FileManager.default.enumerator(atPath: assetCatalogAbsolutePath) return elementsInEnumerator(enumerator) @@ -64,6 +64,19 @@ func listAssets() -> [String] { .map { $0.components(separatedBy: "/").last ?? $0 } // Remove folder path } +// MARK: Dictionary with Asset as a key with a Path for it as a value +func readAssetsMap() -> [String: String] { + var dictionary: [String: String] = [:] + + assetCatalogAbsolutePaths.forEach { (path) in + listAssets(assetCatalogAbsolutePath: path).forEach({ (asset) in + dictionary[asset] = path + }) + } + + return dictionary +} + // MARK: - List Used Assets in the codebase @@ -117,18 +130,23 @@ func listUsedAssetLiterals() -> [String] { // MARK: - Begining of script -let assets = Set(listAssets()) + let used = Set(listUsedAssetLiterals() + ignoredUnusedNames) +let assetsMap = readAssetsMap() +let allAssets = assetsMap.keys + +let assets = Set(allAssets) // Generate Warnings for Unused Assets let unused = assets.subtracting(used) -unused.forEach { print("\(assetCatalogAbsolutePath):: warning: [Asset Unused] \($0)") } +print(assetsMap) +unused.forEach { print("\(assetsMap[$0]!):: warning: [Asset Unused] \($0)") } // Generate Error for broken Assets let broken = used.subtracting(assets) -broken.forEach { print("\(assetCatalogAbsolutePath):: error: [Asset Missing] \($0)") } +broken.forEach { print("error: [Asset Missing] \($0)") } if broken.count > 0 { exit(1) diff --git a/Example/AssetChecker.xcodeproj/project.pbxproj b/Example/AssetChecker.xcodeproj/project.pbxproj index e323d60..676e6a9 100644 --- a/Example/AssetChecker.xcodeproj/project.pbxproj +++ b/Example/AssetChecker.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; }; + 6A0B84EC2318211200B253A0 /* AnotherAssetCatalog.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6A0B84EB2318211200B253A0 /* AnotherAssetCatalog.xcassets */; }; BA341A14EF45F09231AACBFE /* Pods_AssetChecker_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2F82D1638FD77B9042FE9A6 /* Pods_AssetChecker_Example.framework */; }; /* End PBXBuildFile section */ @@ -47,6 +48,7 @@ 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; }; 63C1D8F311B1C327036F7550 /* AssetChecker.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = AssetChecker.podspec; path = ../AssetChecker.podspec; sourceTree = ""; }; + 6A0B84EB2318211200B253A0 /* AnotherAssetCatalog.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = AnotherAssetCatalog.xcassets; sourceTree = ""; }; B2F82D1638FD77B9042FE9A6 /* Pods_AssetChecker_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AssetChecker_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C2AB56DA4BC27DE54F97B2E5 /* Pods-AssetChecker_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AssetChecker_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-AssetChecker_Example/Pods-AssetChecker_Example.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -100,6 +102,7 @@ 607FACD91AFB9204008FA782 /* Main.storyboard */, 607FACDC1AFB9204008FA782 /* Images.xcassets */, 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, + 6A0B84EB2318211200B253A0 /* AnotherAssetCatalog.xcassets */, 607FACD31AFB9204008FA782 /* Supporting Files */, ); name = "Example for AssetChecker"; @@ -233,6 +236,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -253,6 +257,7 @@ buildActionMask = 2147483647; files = ( 5D8C437E1FC6CB2100DDF7D0 /* run in Resources */, + 6A0B84EC2318211200B253A0 /* AnotherAssetCatalog.xcassets in Resources */, 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, @@ -362,7 +367,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "${PODS_ROOT}/AssetChecker/run --catalog ${SRCROOT}/Resource/Images.xcassets"; + shellScript = "${PODS_ROOT}/AssetChecker/run --catalog ${SRCROOT}/AssetChecker/Images.xcassets,${SRCROOT}/AssetChecker/AnotherAssetCatalog.xcassets\n"; }; CD3F94CDB64297E52FBE5D36 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; diff --git a/Example/AssetChecker/AnotherAssetCatalog.xcassets/Contents.json b/Example/AssetChecker/AnotherAssetCatalog.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/AssetChecker/AnotherAssetCatalog.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/AssetChecker/AnotherAssetCatalog.xcassets/NotUsedImageInAnotherAssetCatalog.imageset/Contents.json b/Example/AssetChecker/AnotherAssetCatalog.xcassets/NotUsedImageInAnotherAssetCatalog.imageset/Contents.json new file mode 100644 index 0000000..f8f827e --- /dev/null +++ b/Example/AssetChecker/AnotherAssetCatalog.xcassets/NotUsedImageInAnotherAssetCatalog.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/AssetChecker/AnotherAssetCatalog.xcassets/UsedImageInAnotherAssetCatalog.imageset/Contents.json b/Example/AssetChecker/AnotherAssetCatalog.xcassets/UsedImageInAnotherAssetCatalog.imageset/Contents.json new file mode 100644 index 0000000..f8f827e --- /dev/null +++ b/Example/AssetChecker/AnotherAssetCatalog.xcassets/UsedImageInAnotherAssetCatalog.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/AssetChecker/Images.xcassets/Contents.json b/Example/AssetChecker/Images.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/AssetChecker/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/AssetChecker/Images.xcassets/NotUsedImage.imageset/Contents.json b/Example/AssetChecker/Images.xcassets/NotUsedImage.imageset/Contents.json new file mode 100644 index 0000000..f8f827e --- /dev/null +++ b/Example/AssetChecker/Images.xcassets/NotUsedImage.imageset/Contents.json @@ -0,0 +1,20 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/AssetChecker/ViewController.swift b/Example/AssetChecker/ViewController.swift index e92141b..ac33f70 100644 --- a/Example/AssetChecker/ViewController.swift +++ b/Example/AssetChecker/ViewController.swift @@ -17,6 +17,9 @@ class ViewController: UIViewController { override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() + UIImage(named: "NotExistingImage") + UIImage(named: "NotExistingImageInAnotherAssetCatalog") + UIImage(named: "UsedImageInAnotherAssetCatalog") // Dispose of any resources that can be recreated. }