218 lines
6 KiB
Python
218 lines
6 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
# utils.py
|
|
#
|
|
# Utility functions for crowdin_sync.py and it's dependencies
|
|
#
|
|
# Copyright (C) 2014-2016 The CyanogenMod Project
|
|
# Copyright (C) 2017-2022 The LineageOS Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import itertools
|
|
import os
|
|
import sys
|
|
|
|
from distutils.util import strtobool
|
|
from lxml import etree
|
|
from threading import Thread
|
|
from time import sleep
|
|
from subprocess import Popen, PIPE
|
|
|
|
_DIR = os.path.dirname(os.path.realpath(__file__))
|
|
_DONE = False
|
|
|
|
|
|
def run_subprocess(cmd, silent=False, show_spinner=False):
|
|
t = start_spinner(show_spinner)
|
|
p = Popen(cmd, stdout=PIPE, stderr=PIPE, universal_newlines=True)
|
|
comm = p.communicate()
|
|
exit_code = p.returncode
|
|
if exit_code != 0 and not silent:
|
|
print(
|
|
"There was an error running the subprocess.\n"
|
|
"cmd: %s\n"
|
|
"exit code: %d\n"
|
|
"stdout: %s\n"
|
|
"stderr: %s" % (cmd, exit_code, comm[0], comm[1]),
|
|
file=sys.stderr,
|
|
)
|
|
stop_spinner(t)
|
|
return comm, exit_code
|
|
|
|
|
|
def start_spinner(show_spinner):
|
|
global _DONE
|
|
_DONE = False
|
|
if not show_spinner:
|
|
return None
|
|
t = Thread(target=spin_cursor)
|
|
t.start()
|
|
return t
|
|
|
|
|
|
def stop_spinner(t):
|
|
global _DONE
|
|
if t is None:
|
|
return
|
|
_DONE = True
|
|
t.join(1)
|
|
|
|
|
|
def spin_cursor():
|
|
global _DONE
|
|
spinner = itertools.cycle([".", "..", "...", "....", "....."])
|
|
while not _DONE:
|
|
sys.stdout.write("\x1b[1K\r")
|
|
output = next(spinner)
|
|
sys.stdout.write(output)
|
|
sys.stdout.flush()
|
|
sleep(0.5)
|
|
sys.stdout.write("\x1b[1K\r ")
|
|
|
|
|
|
def check_run(cmd):
|
|
p = Popen(cmd, stdout=sys.stdout, stderr=sys.stderr)
|
|
ret = p.wait()
|
|
if ret != 0:
|
|
joined = " ".join(cmd)
|
|
print(f"Failed to run cmd: {joined}", file=sys.stderr)
|
|
sys.exit(ret)
|
|
|
|
|
|
def find_xml(base_path):
|
|
for dp, dn, file_names in os.walk(base_path):
|
|
for f in file_names:
|
|
if os.path.splitext(f)[1] == ".xml":
|
|
yield os.path.join(dp, f)
|
|
|
|
|
|
def get_username(args):
|
|
username = args.username
|
|
if (args.gerrit or args.download or args.unzip) and username is None:
|
|
# try getting the username from git
|
|
msg, code = run_subprocess(
|
|
["git", "config", "--get", "review.review.lineageos.org.username"],
|
|
silent=True,
|
|
)
|
|
has_username = False
|
|
if code == 0:
|
|
username = msg[0].strip("\n")
|
|
if username != "":
|
|
has_username = user_prompt(
|
|
f"Argument -u/--username was not specified but found '{username}', "
|
|
f"continue?"
|
|
)
|
|
else:
|
|
print("Argument -u/--username is required!")
|
|
if not has_username:
|
|
sys.exit(1)
|
|
return username
|
|
|
|
|
|
def user_prompt(question):
|
|
while True:
|
|
user_input = input(question + " [y/n]: ")
|
|
try:
|
|
return bool(strtobool(user_input))
|
|
except ValueError:
|
|
print("Please use y/n or yes/no.\n")
|
|
|
|
|
|
# ################################# PREPARE ################################## #
|
|
|
|
|
|
def check_dependencies():
|
|
# Check for Java version of crowdin
|
|
cmd = ["which", "crowdin"]
|
|
msg, code = run_subprocess(cmd, silent=True)
|
|
if code != 0:
|
|
print("You have not installed crowdin.", file=sys.stderr)
|
|
return False
|
|
return True
|
|
|
|
|
|
def load_xml(x):
|
|
try:
|
|
return etree.parse(x)
|
|
except etree.XMLSyntaxError:
|
|
print(f"Malformed {x}", file=sys.stderr)
|
|
return None
|
|
except Exception:
|
|
print(f"You have no {x}", file=sys.stderr)
|
|
return None
|
|
|
|
|
|
def check_files(files):
|
|
for f in files:
|
|
if not os.path.isfile(f):
|
|
print(f"You have no {f}.", file=sys.stderr)
|
|
return False
|
|
return True
|
|
|
|
|
|
def get_base_path(default_branch):
|
|
base_path_branch_suffix = default_branch.replace("-", "_").replace(".", "_").upper()
|
|
base_path_env = f"LINEAGE_CROWDIN_BASE_PATH_{base_path_branch_suffix}"
|
|
base_path = os.getenv(base_path_env)
|
|
if base_path is None:
|
|
cwd = os.getcwd()
|
|
print(f"You have not set {base_path_env}. Defaulting to {cwd}")
|
|
base_path = cwd
|
|
if not os.path.isdir(base_path):
|
|
print(f"{base_path_env} is not a real directory: {base_path}")
|
|
sys.exit(1)
|
|
|
|
return base_path
|
|
|
|
|
|
def get_xml_files(base_path, default_branch):
|
|
xml_android = load_xml(x=f"{base_path}/android/default.xml")
|
|
if xml_android is None:
|
|
sys.exit(1)
|
|
|
|
xml_extra = load_xml(x=f"{_DIR}/config/{default_branch}_extra_packages.xml")
|
|
if xml_extra is None:
|
|
sys.exit(1)
|
|
|
|
xml_snippet = load_xml(x=f"{base_path}/android/snippets/lineage.xml")
|
|
if xml_snippet is not None:
|
|
xml_files = (xml_android, xml_snippet, xml_extra)
|
|
else:
|
|
xml_files = (xml_android, xml_extra)
|
|
|
|
return xml_files
|
|
|
|
|
|
def get_config_dict(config, default_branch):
|
|
config_dict = {}
|
|
if config:
|
|
config_dict["headers"] = ["custom config"]
|
|
config_dict["files"] = [f"{_DIR}/config/{config}"]
|
|
else:
|
|
config_dict["headers"] = [
|
|
"AOSP supported languages",
|
|
"non-AOSP supported languages",
|
|
]
|
|
config_dict["files"] = [
|
|
f"{_DIR}/config/{default_branch}.yaml",
|
|
f"{_DIR}/config/{default_branch}_aosp.yaml",
|
|
]
|
|
if not check_files(config_dict["files"]):
|
|
sys.exit(1)
|
|
return config_dict
|
|
|
|
|
|
def get_gerrit_base_cmd(username):
|
|
cmd = ["ssh", "-p", "29418", f"{username}@review.lineageos.org", "gerrit"]
|
|
return cmd
|