Files
2026-09-01 12:44:10 +08:00

343 lines
11 KiB
Python

#!/usr/bin python3
# library update helper
import subprocess
import shutil
import stat
import os
import glob
from typing import Tuple
import zipfile
import showjar
import urllib.request
import ssl
import json
import re
from datetime import datetime, timedelta
_ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
_SOURCE_DIR = os.path.join(_ROOT_PATH, 'sources')
_last_update_time = datetime.now()
def sh(command, print_msg=True):
p = subprocess.Popen(
command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
bytes_result = p.stdout.read()
try:
result = bytes_result.decode('utf-8')
except Exception:
# fix some window system error
result = bytes_result.decode('gbk')
if print_msg:
print(result)
return result
def run(command):
print(command + '...')
subprocess.call(command, shell=True)
def ensure_dir(dirpath):
if not os.path.exists(dirpath):
os.makedirs(dirpath)
def readonly_handler(func, path, execinfo):
# or os.chmod(path, stat.S_IWRITE) from "stat" module
os.chmod(path, stat.S_IWRITE)
func(path)
def rmtree(path):
if os.path.exists(path):
if os.path.isdir(path):
shutil.rmtree(path, onerror=readonly_handler)
else:
os.remove(path)
def copy_git_repo(src, dest):
app_ignore = shutil.ignore_patterns('build', '.git', '.gradle', '.idea', '*.idea')
overwrite_tree(src, dest, ignore=app_ignore)
def lastest_tag():
return sh("git describe --tags --abbrev=0")
def gradle_path():
return 'gradlew' if os.name == 'nt' else './gradlew'
def ensure_repo(origin_url, dirname):
if os.path.exists(dirname):
os.chdir(os.path.join(_SOURCE_DIR, dirname))
print("changed dir to %s"%(os.getcwd()))
run('git reset --hard HEAD')
run('git pull --rebase')
else:
run("git clone --depth=1 %s"%(origin_url))
os.chdir(os.path.join(_SOURCE_DIR, dirname))
print("changed dir to %s"%(os.getcwd()))
def overwrite_tree(src, dest, ignore=None):
if os.path.isdir(src):
if not os.path.isdir(dest):
os.makedirs(dest)
files = os.listdir(src)
if ignore is not None:
ignored = ignore(src, files)
else:
ignored = set()
for f in files:
if f not in ignored:
overwrite_tree(os.path.join(src, f),
os.path.join(dest, f),
ignore)
else:
shutil.copyfile(src, dest)
def download_file(url, store_path):
print("found download url: %s, download file to: %s"%(url, store_path))
def reporthook(a, b, c):
print("\rdownloading: %5.1f%%" % (a * b * 100.0 / c), end="")
try:
if url.lower().startswith('http'):
req = urllib.request.Request(url)
else:
raise ValueError from None
urllib.request.urlretrieve(req.get_full_url(), store_path, reporthook=reporthook)
if not os.path.exists(store_path):
print("download file failed: %s"%(store_path))
return False
except Exception as e:
print("download file error:")
print(e)
return True
def download_release(repo_owner, repo_name, last_update_time, refile, destpath):
"""download lastest release file from github"""
url = "https://api.github.com/repos/%s/%s/releases/latest"%(repo_owner, repo_name)
try:
print("download_release: %s/%s, min_publish_time: %s, destpath: %s"
% (repo_owner, repo_name, last_update_time, destpath))
response = ''
if url.lower().startswith('http'):
req = urllib.request.Request(url)
else:
raise ValueError from None
with urllib.request.urlopen(req.get_full_url()) as f:
response = json.loads(f.read().decode('utf-8'))
publish_time = datetime.strptime(response['published_at'], '%Y-%m-%dT%H:%M:%SZ')
# debug
# publish_time = datetime.strptime('2023-02-20T11:33:37Z', '%Y-%m-%dT%H:%M:%SZ')
print("min_publish_time: %s, repo publish time: %s"%(str(last_update_time), str(publish_time)))
if publish_time.timetuple() <= last_update_time.timetuple():
print("ignore update '%s/%s'"%(repo_owner, repo_name))
return
browser_download_url = ''
for asset in response['assets']:
browser_download_url = asset['browser_download_url']
if re.search(refile, browser_download_url):
break
if not browser_download_url:
print("can not find download url %s/%s"%(repo_owner, repo_name))
return
store_path = os.path.join(_SOURCE_DIR, os.path.basename(browser_download_url))
if not download_file(browser_download_url, store_path):
return
# # unzip file
rmtree(showjar.CACHE_DIR)
if store_path.endswith('.zip'):
with zipfile.ZipFile(store_path, 'r') as z:
z.extractall(showjar.CACHE_DIR)
overwrite_tree(showjar.CACHE_DIR, destpath)
else:
destpath2 = destpath
if os.path.isdir(destpath):
destpath2 = os.path.join(destpath, os.path.basename(store_path))
shutil.copyfile(store_path, destpath2)
except Exception as e:
print("download release error:")
print(e)
def dex2jar_updater():
print("---------------------------dex2jar_updater start---------------------------")
rawdir = os.getcwd()
os.chdir(_SOURCE_DIR)
ensure_repo('https://github.com/pxb1988/dex2jar.git', 'dex2jar')
os.chdir(os.path.join(_SOURCE_DIR, 'dex2jar'))
run("git checkout 2.x")
run("%s clean distZip"%(gradle_path()))
distzipdir = os.path.join('dex-tools', 'build', 'distributions')
distzips = glob.glob("%s/dex-tools*.zip"%(distzipdir))
if distzips:
rmtree(showjar.CACHE_DIR)
with zipfile.ZipFile(distzips[0], 'r') as z:
z.extractall(showjar.CACHE_DIR)
src = os.path.join(showjar.CACHE_DIR, os.listdir(showjar.CACHE_DIR)[0])
overwrite_tree(src, showjar.DEX2JAR)
os.chdir(rawdir)
def enjarify_updater():
print("---------------------------enjarify_updater start---------------------------")
rawdir = os.getcwd()
os.chdir(_SOURCE_DIR)
ensure_repo('https://github.com/Storyyeller/enjarify.git', 'enjarify')
os.chdir(os.path.join(_SOURCE_DIR, 'enjarify'))
src = os.path.join(_SOURCE_DIR, 'enjarify')
copy_git_repo(src, showjar.ENJARIFY)
# delete tests/
rmtree(os.path.join(showjar.ENJARIFY, 'tests'))
# 升级enjarify.bat中python3为python
batpath = os.path.join(showjar.ENJARIFY, 'enjarify.bat')
content = ''
with open(batpath, 'r', encoding='utf-8') as f:
content = f.read()
with open(batpath, 'w', encoding='utf-8') as f:
content = content.replace('python3 ', 'python ')
content = content.replace('py -3 ', 'python ')
f.write(content)
os.chdir(rawdir)
def jadx_updater():
print("---------------------------jadx_updater start---------------------------")
# webbrowser.open_new_tab("https://github.com/skylot/jadx/releases")
download_release('skylot', 'jadx', _last_update_time, r'jadx-\d.+\.zip', showjar.JADX)
rawdir = os.getcwd()
os.chdir(showjar.JADX)
# remove unused files
rmtree('README.md')
rmtree('NOTICE')
rmtree('LICENSE')
print("\n")
# update jadx script config, fix issues #7.
def update_jvm_opts(script_path):
script_path = os.path.abspath(script_path)
if not script_path.startswith(showjar.JADX):
return
print("update_jvm_opts: %s"%(script_path))
content = ''
with open(script_path, 'r', encoding='utf-8') as f:
content = f.read()
content = content.replace('"-XX:MaxRAMPercentage=70.0"', '')
with open(script_path, 'w', encoding='utf-8') as f:
f.write(content)
update_jvm_opts('bin/jadx')
update_jvm_opts('bin/jadx-gui')
update_jvm_opts('bin/jadx-gui.bat')
update_jvm_opts('bin/jadx.bat')
os.chdir(rawdir)
def apktool_updater():
print("---------------------------apktool_updater start---------------------------")
# webbrowser.open_new_tab("https://ibotpeaches.github.io/Apktool/")
download_release('iBotPeaches', 'Apktool', _last_update_time, r'apktool-\d.+\.jar', showjar.APKTOOL)
def fernflower_updater():
print("---------------------------fernflower_updater start---------------------------")
rawdir = os.getcwd()
os.chdir(_SOURCE_DIR)
maven_version = sh("mvn -v")
if "not found" in maven_version or "无法将" in maven_version:
print("please configure maven first!")
return
ensure_dir(os.path.join(_SOURCE_DIR, 'fernflower'))
os.chdir(os.path.join(_SOURCE_DIR, 'fernflower'))
# Try to resolve a concrete latest version from JetBrains metadata instead of using LATEST
version = 'LATEST'
try:
metadata_url_https = (
"https://www.jetbrains.com/intellij-repository/releases/"
"com/jetbrains/intellij/java/java-decompiler-engine/maven-metadata.xml"
)
metadata_url_http = metadata_url_https.replace("https://", "http://")
try:
meta = urllib.request.urlopen(metadata_url_https, context=ssl._create_unverified_context()).read().decode('utf-8')
except Exception:
meta = urllib.request.urlopen(metadata_url_http).read().decode('utf-8')
m = re.search(r"<release>([^<]+)</release>", meta)
if m:
version = m.group(1)
else:
m = re.search(r"<latest>([^<]+)</latest>", meta)
if m:
version = m.group(1)
else:
vs = re.findall(r"<version>([^<]+)</version>", meta)
if vs:
version = vs[-1]
except Exception as e:
print("could not fetch maven metadata, falling back to LATEST: %s" % e)
artifact = "com.jetbrains.intellij.java:java-decompiler-engine:%s" % version
run("mvn dependency:get -DremoteRepositories=jetbrains::default::https://www.jetbrains.com/intellij-repository/releases/ -Dartifact=%s -Ddest=." % artifact)
jars = glob.glob("%s/%s" % (os.getcwd(), "java-decompiler-engine*.jar"))
jar = None
if jars:
jar = jars[0]
else:
# fallback: check local maven repository
m2_path = os.path.expanduser(os.path.join('~', '.m2', 'repository'))
local_jar = os.path.join(m2_path, 'com', 'jetbrains', 'intellij', 'java', 'java-decompiler-engine', version, 'java-decompiler-engine-%s.jar' % version)
if os.path.exists(local_jar):
jar = local_jar
if not jar:
print("expected jar is not found!")
return
print("latest jar: %s"%(jar))
shutil.copyfile(jar, showjar.fernflowerpath())
os.chdir(rawdir)
def initEnv():
ensure_dir(_SOURCE_DIR)
global _last_update_time
readme_path = os.path.join(_ROOT_PATH, 'README.md')
with open(readme_path, 'r', encoding='utf-8') as f:
content = f.read()
datestring = re.search(r"update\sat\s(\d+-\d+-\d+)", content)
_last_update_time = datetime.strptime(datestring.group(1), '%Y-%m-%d')
# debug code
_last_update_time = _last_update_time - timedelta(days=0)
print("last update time: %s"%(_last_update_time))
def main():
initEnv()
enjarify_updater()
dex2jar_updater()
jadx_updater()
apktool_updater()
fernflower_updater()
if __name__ == '__main__':
main()