Last active
May 9, 2024 05:44
-
-
Save Daemon-Devarshi/05f6142267fc402f10b50360dfc7aaa6 to your computer and use it in GitHub Desktop.
Python script to identify unused images in the Xcode - Swift project
This file contains hidden or 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
# Usage e.g.: python3 unused_assets.py '/Users/DevK/MyProject' '/Users/DevK/MyProject/MyProject/Assets/Assets.xcassets' | |
# It is important to pass project folder path as first argument, assets folder path as second argument | |
# It is assumed that all the images are maintained within Assets.xcassets folder and are used either within swift files or within storyboards | |
""" | |
@author = "Devarshi Kulshreshtha" | |
@copyright = "Copyright 2020, Devarshi Kulshreshtha" | |
@license = "GPL" | |
@version = "1.0.2" | |
@contact = "[email protected]" | |
""" | |
import sys | |
import glob | |
from pathlib import Path | |
import mmap | |
import time | |
# obtain start time | |
start = time.time() | |
arguments = sys.argv | |
# pass project folder path as argument 1 | |
projectFolderPath = arguments[1].replace("\\", "") # replacing backslash with space | |
# pass assets folder path as argument 2 | |
assetsPath = arguments[2].replace("\\", "") # replacing backslash with space | |
print(f"assetsPath: {assetsPath}") | |
print(f"projectFolderPath: {projectFolderPath}") | |
# obtain all assets / images | |
# obtain paths for all assets | |
assetsSearchablePath = assetsPath + '/**/*.imageset' #alternate way to append: fr"{assetsPath}/**/*.imageset" | |
print(f"assetsSearchablePath: {assetsSearchablePath}") | |
imagesNameCountDict = {} # empty dict to store image name as key and occurrence count | |
for imagesetPath in glob.glob(assetsSearchablePath, recursive=True): | |
# storing the image name as encoded so that we save some time later during string search in file | |
encodedImageName = str.encode(Path(imagesetPath).stem) | |
# initializing occurrence count as 0 | |
imagesNameCountDict[encodedImageName] = 0 | |
print("Names of all assets obtained") | |
# search images in swift files | |
# obtain paths for all swift files | |
swiftFilesSearchablePath = projectFolderPath + '/**/*.swift' #alternate way to append: fr"{projectFolderPath}/**/*.swift" | |
print(f"swiftFilesSearchablePath: {swiftFilesSearchablePath}") | |
for swiftFilePath in glob.glob(swiftFilesSearchablePath, recursive=True): | |
with open(swiftFilePath, 'rb', 0) as file, \ | |
mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as s: | |
# search all the assests within the swift file | |
for encodedImageName in imagesNameCountDict: | |
# file search | |
if s.find(encodedImageName) != -1: | |
# updating occurrence count, if found | |
imagesNameCountDict[encodedImageName] += 1 | |
print("Images searched in all swift files!") | |
# search images in storyboards | |
# obtain path for all storyboards | |
storyboardsSearchablePath = projectFolderPath + '/**/*.storyboard' #alternate way to append: fr"{projectFolderPath}/**/*.storyboard" | |
print(f"storyboardsSearchablePath: {storyboardsSearchablePath}") | |
for storyboardPath in glob.glob(storyboardsSearchablePath, recursive=True): | |
with open(storyboardPath, 'rb', 0) as file, \ | |
mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as s: | |
# search all the assests within the storyboard file | |
for encodedImageName in imagesNameCountDict: | |
# file search | |
if s.find(encodedImageName) != -1: | |
# updating occurrence count, if found | |
imagesNameCountDict[encodedImageName] += 1 | |
print("Images searched in all storyboard files!") | |
print("Here is the list of unused assets:") | |
# printing all image names, for which occurrence count is 0 | |
print('\n'.join({encodedImageName.decode("utf-8", "strict") for encodedImageName, occurrenceCount in imagesNameCountDict.items() if occurrenceCount == 0})) | |
print(f"Done in {time.time() - start} seconds!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment