Skip to content

Instantly share code, notes, and snippets.

@konifar
Created April 20, 2018 04:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save konifar/d0328007d556e629b8fbc237481c13ac to your computer and use it in GitHub Desktop.
Save konifar/d0328007d556e629b8fbc237481c13ac to your computer and use it in GitHub Desktop.
android_unused_resource_remover.py
# -*- coding: utf-8 -*-
import commands
import glob
import os
import xml.etree.ElementTree as ElementTree
# http://stackoverflow.com/questions/33573807/faithfully-preserve-comments-in-parsed-xml-python-2-7
class CommentedTreeBuilder(ElementTree.TreeBuilder):
def __init__(self, *args, **kwargs):
super(CommentedTreeBuilder, self).__init__(*args, **kwargs)
def comment(self, data):
self.start(ElementTree.Comment, {})
self.data(data)
self.end(ElementTree.Comment)
def to_camel_case(snake_str):
components = snake_str.split('_')
# We capitalize the first letter of each component
# except the first one with the 'title' method and join them together.
return components[0].title() + ''.join(x.title() for x in components[1:])
def remove_file(prefix):
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + "/app/src"
files = glob.glob(path + "/main/res/" + prefix + "/*")
changed = False
for f in files:
base_name = os.path.basename(f)
file_name = os.path.splitext(base_name)[0]
if prefix.startswith("drawable"):
file_name = file_name.strip('.9') # Considered 9patch
command = "find " + path + " \( -name '*.xml' -o -name '*.kt' -o -name '*.java' \) -type f -print " \
"| xargs grep" \
" -e '" + prefix + "/" + file_name + "' -e 'R." + prefix + "." + file_name + "'"
if prefix == "layout":
command += " -e '" + to_camel_case(file_name) + "Binding'"
grep_result = commands.getoutput(command)
if len(grep_result) <= 0:
print "Delete " + base_name + " / " + prefix
os.remove(f)
changed = True
if changed:
print "Complete to delete: " + prefix
else:
print "No unused file about " + prefix
def remove_tag(prefix):
path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + "/app/src"
files = glob.glob(path + "/main/res/values*/" + prefix + "*")
for f in files:
base_name = os.path.basename(f)
doc = ElementTree.parse(f, parser=ElementTree.XMLParser(target=CommentedTreeBuilder()))
root = doc.getroot()
changed = False
for tag in root.findall(prefix):
attr_name = tag.attrib["name"]
command = "find " + path + " \( -name '*.xml' -o -name '*.kt' -o -name '*.java' \) -type f -print " \
"| xargs grep" \
" -e '" + prefix + "/" + attr_name + "' -e 'R." + prefix + "." + attr_name + "'"
if prefix == "style":
command += " -e '" + attr_name + "\.' -e 'parent=\"" + attr_name + "\"'"
grep_result = commands.getoutput(command)
if len(grep_result) <= 0:
print "Delete " + attr_name + " in " + base_name + " / " + prefix
root.remove(tag)
changed = True
if changed:
doc.write(f, encoding="UTF-8", xml_declaration=True)
else:
print "No unused tag in " + base_name
# Remove file if it has no tag
if len(root.findall(prefix)) == 0:
os.remove(f)
remove_file("layout")
remove_file("drawable*")
remove_file("mipmap*")
remove_file("anim")
remove_file("animator")
remove_file("color")
remove_file("menu")
remove_tag("style")
remove_tag("string")
remove_tag("dimen")
# TODO Support theme
# TODO Support attr
# TODO Support multi module
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment