mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-08-17 03:40:11 +02:00
Merge branch 'implement-gettext' into 'master'
first implementation of localization using gettext Closes #342 See merge request fdroid/fdroidserver!338
This commit is contained in:
commit
a2eaf37394
3
.gitignore
vendored
3
.gitignore
vendored
@ -44,3 +44,6 @@ makebuildserver.config.py
|
|||||||
/tests/repo/info.guardianproject.checkey/en-US/phoneScreenshots/checkey.png
|
/tests/repo/info.guardianproject.checkey/en-US/phoneScreenshots/checkey.png
|
||||||
/tests/urzip-πÇÇπÇÇ现代汉语通用字-български-عربي1234.apk
|
/tests/urzip-πÇÇπÇÇ现代汉语通用字-български-عربي1234.apk
|
||||||
/unsigned/
|
/unsigned/
|
||||||
|
|
||||||
|
# generated by gettext
|
||||||
|
locale/*/LC_MESSAGES/fdroidserver.mo
|
||||||
|
@ -6,10 +6,12 @@ test:
|
|||||||
- cd tests
|
- cd tests
|
||||||
- ./complete-ci-tests
|
- ./complete-ci-tests
|
||||||
|
|
||||||
# Test that the parsing of the .txt format didn't change
|
# Test that the parsing of the .txt format didn't change from last
|
||||||
# from last released version.
|
# released version. Ensure that the official tags are included when
|
||||||
|
# running these tests on forks as well.
|
||||||
metadata_v0:
|
metadata_v0:
|
||||||
script:
|
script:
|
||||||
|
- git fetch https://gitlab.com/fdroid/fdroidserver 0.8
|
||||||
- cd tests
|
- cd tests
|
||||||
- export GITCOMMIT=`git describe`
|
- export GITCOMMIT=`git describe`
|
||||||
- git checkout 0.8 # bump after release
|
- git checkout 0.8 # bump after release
|
||||||
|
50
fdroid
50
fdroid
@ -22,36 +22,38 @@ import logging
|
|||||||
|
|
||||||
import fdroidserver.common
|
import fdroidserver.common
|
||||||
import fdroidserver.metadata
|
import fdroidserver.metadata
|
||||||
|
from fdroidserver import _
|
||||||
from argparse import ArgumentError
|
from argparse import ArgumentError
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
|
||||||
commands = OrderedDict([
|
commands = OrderedDict([
|
||||||
("build", "Build a package from source"),
|
("build", _("Build a package from source")),
|
||||||
("init", "Quickly start a new repository"),
|
("init", _("Quickly start a new repository")),
|
||||||
("publish", "Sign and place packages in the repo"),
|
("publish", _("Sign and place packages in the repo")),
|
||||||
("gpgsign", "Add gpg signatures for packages in repo"),
|
("gpgsign", _("Add gpg signatures for packages in repo")),
|
||||||
("update", "Update repo information for new packages"),
|
("update", _("Update repo information for new packages")),
|
||||||
("verify", "Verify the integrity of downloaded packages"),
|
("verify", _("Verify the integrity of downloaded packages")),
|
||||||
("checkupdates", "Check for updates to applications"),
|
("checkupdates", _("Check for updates to applications")),
|
||||||
("import", "Add a new application from its source code"),
|
("import", _("Add a new application from its source code")),
|
||||||
("install", "Install built packages on devices"),
|
("install", _("Install built packages on devices")),
|
||||||
("readmeta", "Read all the metadata files and exit"),
|
("readmeta", _("Read all the metadata files and exit")),
|
||||||
("rewritemeta", "Rewrite all the metadata files"),
|
("rewritemeta", _("Rewrite all the metadata files")),
|
||||||
("lint", "Warn about possible metadata errors"),
|
("lint", _("Warn about possible metadata errors")),
|
||||||
("scanner", "Scan the source code of a package"),
|
("scanner", _("Scan the source code of a package")),
|
||||||
("dscanner", "Dynamically scan APKs post build"),
|
("dscanner", _("Dynamically scan APKs post build")),
|
||||||
("stats", "Update the stats of the repo"),
|
("stats", _("Update the stats of the repo")),
|
||||||
("server", "Interact with the repo HTTP server"),
|
("server", _("Interact with the repo HTTP server")),
|
||||||
("signindex", "Sign indexes created using update --nosign"),
|
("signindex", _("Sign indexes created using update --nosign")),
|
||||||
("btlog", "Update the binary transparency log for a URL"),
|
("btlog", _("Update the binary transparency log for a URL")),
|
||||||
("signatures", "Extract signatures from APKs"),
|
("signatures", _("Extract signatures from APKs")),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
def print_help():
|
def print_help():
|
||||||
print("usage: fdroid [-h|--help|--version] <command> [<args>]")
|
print(_("usage: fdroid [-h|--help|--version] <command> [<args>]"))
|
||||||
print("")
|
print("")
|
||||||
print("Valid commands are:")
|
print(_("Valid commands are:"))
|
||||||
for cmd, summary in commands.items():
|
for cmd, summary in commands.items():
|
||||||
print(" " + cmd + ' ' * (15 - len(cmd)) + summary)
|
print(" " + cmd + ' ' * (15 - len(cmd)) + summary)
|
||||||
print("")
|
print("")
|
||||||
@ -70,7 +72,7 @@ def main():
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif command == '--version':
|
elif command == '--version':
|
||||||
import os.path
|
import os.path
|
||||||
output = 'no version info found!'
|
output = _('no version info found!')
|
||||||
cmddir = os.path.realpath(os.path.dirname(__file__))
|
cmddir = os.path.realpath(os.path.dirname(__file__))
|
||||||
moduledir = os.path.realpath(os.path.dirname(fdroidserver.common.__file__) + '/..')
|
moduledir = os.path.realpath(os.path.dirname(fdroidserver.common.__file__) + '/..')
|
||||||
if cmddir == moduledir:
|
if cmddir == moduledir:
|
||||||
@ -97,7 +99,7 @@ def main():
|
|||||||
print(output),
|
print(output),
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
else:
|
else:
|
||||||
print("Command '%s' not recognised.\n" % command)
|
print(_("Command '%s' not recognised.\n" % command))
|
||||||
print_help()
|
print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@ -143,7 +145,7 @@ def main():
|
|||||||
# These should only be unexpected crashes due to bugs in the code
|
# These should only be unexpected crashes due to bugs in the code
|
||||||
# str(e) often doesn't contain a reason, so just show the backtrace
|
# str(e) often doesn't contain a reason, so just show the backtrace
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.critical("Unknown exception found!")
|
logging.critical(_("Unknown exception found!"))
|
||||||
raise
|
raise
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
import gettext
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# support running straight from git and standard installs
|
||||||
|
rootpaths = [
|
||||||
|
os.path.realpath(os.path.join(os.path.dirname(__file__), '..')),
|
||||||
|
sys.prefix + 'share',
|
||||||
|
]
|
||||||
|
|
||||||
|
localedir = None
|
||||||
|
for rootpath in rootpaths:
|
||||||
|
if len(glob.glob(os.path.join(rootpath, 'locale', '*', 'LC_MESSAGES', 'fdroidserver.mo'))) > 0:
|
||||||
|
localedir = os.path.join(rootpath, 'locale')
|
||||||
|
break
|
||||||
|
|
||||||
|
gettext.bindtextdomain('fdroidserver', localedir)
|
||||||
|
gettext.textdomain('fdroidserver')
|
||||||
|
_ = gettext.gettext
|
@ -40,9 +40,10 @@ import xml.dom.minidom
|
|||||||
import zipfile
|
import zipfile
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
from .exception import FDroidException
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import server
|
from . import server
|
||||||
|
from .exception import FDroidException
|
||||||
|
|
||||||
|
|
||||||
options = None
|
options = None
|
||||||
@ -117,12 +118,12 @@ For more info on this idea:
|
|||||||
jarin.close()
|
jarin.close()
|
||||||
gitrepo.index.add([repof, ])
|
gitrepo.index.add([repof, ])
|
||||||
|
|
||||||
files = []
|
output_files = []
|
||||||
for root, dirs, filenames in os.walk(repodir):
|
for root, dirs, files in os.walk(repodir):
|
||||||
for f in filenames:
|
for f in files:
|
||||||
files.append(os.path.relpath(os.path.join(root, f), repodir))
|
output_files.append(os.path.relpath(os.path.join(root, f), repodir))
|
||||||
output = collections.OrderedDict()
|
output = collections.OrderedDict()
|
||||||
for f in sorted(files):
|
for f in sorted(output_files):
|
||||||
repofile = os.path.join(repodir, f)
|
repofile = os.path.join(repodir, f)
|
||||||
stat = os.stat(repofile)
|
stat = os.stat(repofile)
|
||||||
output[f] = (
|
output[f] = (
|
||||||
@ -151,11 +152,11 @@ def main():
|
|||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("--git-repo",
|
parser.add_argument("--git-repo",
|
||||||
default=os.path.join(os.getcwd(), 'binary_transparency'),
|
default=os.path.join(os.getcwd(), 'binary_transparency'),
|
||||||
help="Path to the git repo to use as the log")
|
help=_("Path to the git repo to use as the log"))
|
||||||
parser.add_argument("-u", "--url", default='https://f-droid.org',
|
parser.add_argument("-u", "--url", default='https://f-droid.org',
|
||||||
help="The base URL for the repo to log (default: https://f-droid.org)")
|
help=_("The base URL for the repo to log (default: https://f-droid.org)"))
|
||||||
parser.add_argument("--git-remote", default=None,
|
parser.add_argument("--git-remote", default=None,
|
||||||
help="Push the log to this git remote repository")
|
help=_("Push the log to this git remote repository"))
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
if options.verbose:
|
if options.verbose:
|
||||||
|
@ -32,6 +32,7 @@ from configparser import ConfigParser
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import net
|
from . import net
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@ -96,19 +97,19 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
|
|||||||
|
|
||||||
# Helper to copy the contents of a directory to the server...
|
# Helper to copy the contents of a directory to the server...
|
||||||
def send_dir(path):
|
def send_dir(path):
|
||||||
root = os.path.dirname(path)
|
startroot = os.path.dirname(path)
|
||||||
main = os.path.basename(path)
|
main = os.path.basename(path)
|
||||||
ftp.mkdir(main)
|
ftp.mkdir(main)
|
||||||
for r, d, f in os.walk(path):
|
for root, dirs, files in os.walk(path):
|
||||||
rr = os.path.relpath(r, root)
|
rr = os.path.relpath(root, startroot)
|
||||||
ftp.chdir(rr)
|
ftp.chdir(rr)
|
||||||
for dd in d:
|
for d in dirs:
|
||||||
ftp.mkdir(dd)
|
ftp.mkdir(d)
|
||||||
for ff in f:
|
for f in files:
|
||||||
lfile = os.path.join(root, rr, ff)
|
lfile = os.path.join(startroot, rr, f)
|
||||||
if not os.path.islink(lfile):
|
if not os.path.islink(lfile):
|
||||||
ftp.put(lfile, ff)
|
ftp.put(lfile, f)
|
||||||
ftp.chmod(ff, os.stat(lfile).st_mode)
|
ftp.chmod(f, os.stat(lfile).st_mode)
|
||||||
for i in range(len(rr.split('/'))):
|
for i in range(len(rr.split('/'))):
|
||||||
ftp.chdir('..')
|
ftp.chdir('..')
|
||||||
ftp.chdir('..')
|
ftp.chdir('..')
|
||||||
@ -162,7 +163,7 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
|
|||||||
ftp.mkdir(d)
|
ftp.mkdir(d)
|
||||||
ftp.chdir(d)
|
ftp.chdir(d)
|
||||||
ftp.put(libsrc, lp[-1])
|
ftp.put(libsrc, lp[-1])
|
||||||
for _ in lp[:-1]:
|
for _ignored in lp[:-1]:
|
||||||
ftp.chdir('..')
|
ftp.chdir('..')
|
||||||
# Copy any srclibs that are required...
|
# Copy any srclibs that are required...
|
||||||
srclibpaths = []
|
srclibpaths = []
|
||||||
@ -995,33 +996,33 @@ def parse_commandline():
|
|||||||
|
|
||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("appid", nargs='*', help="app-id with optional versionCode in the form APPID[:VERCODE]")
|
parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
|
||||||
parser.add_argument("-l", "--latest", action="store_true", default=False,
|
parser.add_argument("-l", "--latest", action="store_true", default=False,
|
||||||
help="Build only the latest version of each package")
|
help=_("Build only the latest version of each package"))
|
||||||
parser.add_argument("-s", "--stop", action="store_true", default=False,
|
parser.add_argument("-s", "--stop", action="store_true", default=False,
|
||||||
help="Make the build stop on exceptions")
|
help=_("Make the build stop on exceptions"))
|
||||||
parser.add_argument("-t", "--test", action="store_true", default=False,
|
parser.add_argument("-t", "--test", action="store_true", default=False,
|
||||||
help="Test mode - put output in the tmp directory only, and always build, even if the output already exists.")
|
help=_("Test mode - put output in the tmp directory only, and always build, even if the output already exists."))
|
||||||
parser.add_argument("--server", action="store_true", default=False,
|
parser.add_argument("--server", action="store_true", default=False,
|
||||||
help="Use build server")
|
help=_("Use build server"))
|
||||||
parser.add_argument("--resetserver", action="store_true", default=False,
|
parser.add_argument("--resetserver", action="store_true", default=False,
|
||||||
help="Reset and create a brand new build server, even if the existing one appears to be ok.")
|
help=_("Reset and create a brand new build server, even if the existing one appears to be ok."))
|
||||||
parser.add_argument("--on-server", dest="onserver", action="store_true", default=False,
|
parser.add_argument("--on-server", dest="onserver", action="store_true", default=False,
|
||||||
help="Specify that we're running on the build server")
|
help=_("Specify that we're running on the build server"))
|
||||||
parser.add_argument("--skip-scan", dest="skipscan", action="store_true", default=False,
|
parser.add_argument("--skip-scan", dest="skipscan", action="store_true", default=False,
|
||||||
help="Skip scanning the source code for binaries and other problems")
|
help=_("Skip scanning the source code for binaries and other problems"))
|
||||||
parser.add_argument("--dscanner", action="store_true", default=False,
|
parser.add_argument("--dscanner", action="store_true", default=False,
|
||||||
help="Setup an emulator, install the apk on it and perform a drozer scan")
|
help=_("Setup an emulator, install the apk on it and perform a drozer scan"))
|
||||||
parser.add_argument("--no-tarball", dest="notarball", action="store_true", default=False,
|
parser.add_argument("--no-tarball", dest="notarball", action="store_true", default=False,
|
||||||
help="Don't create a source tarball, useful when testing a build")
|
help=_("Don't create a source tarball, useful when testing a build"))
|
||||||
parser.add_argument("--no-refresh", dest="refresh", action="store_false", default=True,
|
parser.add_argument("--no-refresh", dest="refresh", action="store_false", default=True,
|
||||||
help="Don't refresh the repository, useful when testing a build with no internet connection")
|
help=_("Don't refresh the repository, useful when testing a build with no internet connection"))
|
||||||
parser.add_argument("-f", "--force", action="store_true", default=False,
|
parser.add_argument("-f", "--force", action="store_true", default=False,
|
||||||
help="Force build of disabled apps, and carries on regardless of scan problems. Only allowed in test mode.")
|
help=_("Force build of disabled apps, and carries on regardless of scan problems. Only allowed in test mode."))
|
||||||
parser.add_argument("-a", "--all", action="store_true", default=False,
|
parser.add_argument("-a", "--all", action="store_true", default=False,
|
||||||
help="Build all applications available")
|
help=_("Build all applications available"))
|
||||||
parser.add_argument("-w", "--wiki", default=False, action="store_true",
|
parser.add_argument("-w", "--wiki", default=False, action="store_true",
|
||||||
help="Update the wiki")
|
help=_("Update the wiki"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -1316,7 +1317,7 @@ def main():
|
|||||||
logging.info("Cleaning up after ourselves.")
|
logging.info("Cleaning up after ourselves.")
|
||||||
docker.clean()
|
docker.clean()
|
||||||
|
|
||||||
logging.info("Finished.")
|
logging.info(_("Finished"))
|
||||||
if len(build_succeeded) > 0:
|
if len(build_succeeded) > 0:
|
||||||
logging.info(str(len(build_succeeded)) + ' builds succeeded')
|
logging.info(str(len(build_succeeded)) + ' builds succeeded')
|
||||||
if len(failed_apps) > 0:
|
if len(failed_apps) > 0:
|
||||||
|
@ -30,6 +30,7 @@ from distutils.version import LooseVersion
|
|||||||
import logging
|
import logging
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from .exception import VCSException, FDroidException, MetaDataException
|
from .exception import VCSException, FDroidException, MetaDataException
|
||||||
@ -302,10 +303,10 @@ def check_gplay(app):
|
|||||||
# Return all directories under startdir that contain any of the manifest
|
# Return all directories under startdir that contain any of the manifest
|
||||||
# files, and thus are probably an Android project.
|
# files, and thus are probably an Android project.
|
||||||
def dirs_with_manifest(startdir):
|
def dirs_with_manifest(startdir):
|
||||||
for r, d, f in os.walk(startdir):
|
for root, dirs, files in os.walk(startdir):
|
||||||
if any(m in f for m in [
|
if any(m in files for m in [
|
||||||
'AndroidManifest.xml', 'pom.xml', 'build.gradle']):
|
'AndroidManifest.xml', 'pom.xml', 'build.gradle']):
|
||||||
yield r
|
yield root
|
||||||
|
|
||||||
|
|
||||||
# Tries to find a new subdir starting from the root build_dir. Returns said
|
# Tries to find a new subdir starting from the root build_dir. Returns said
|
||||||
@ -509,15 +510,15 @@ def main():
|
|||||||
# Parse command line...
|
# Parse command line...
|
||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("appid", nargs='*', help="app-id to check for updates")
|
parser.add_argument("appid", nargs='*', help=_("applicationId to check for updates"))
|
||||||
parser.add_argument("--auto", action="store_true", default=False,
|
parser.add_argument("--auto", action="store_true", default=False,
|
||||||
help="Process auto-updates")
|
help=_("Process auto-updates"))
|
||||||
parser.add_argument("--autoonly", action="store_true", default=False,
|
parser.add_argument("--autoonly", action="store_true", default=False,
|
||||||
help="Only process apps with auto-updates")
|
help=_("Only process apps with auto-updates"))
|
||||||
parser.add_argument("--commit", action="store_true", default=False,
|
parser.add_argument("--commit", action="store_true", default=False,
|
||||||
help="Commit changes")
|
help=_("Commit changes"))
|
||||||
parser.add_argument("--gplay", action="store_true", default=False,
|
parser.add_argument("--gplay", action="store_true", default=False,
|
||||||
help="Only print differences with the Play Store")
|
help=_("Only print differences with the Play Store"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -567,7 +568,7 @@ def main():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("...checkupdate failed for {0} : {1}".format(appid, e))
|
logging.error("...checkupdate failed for {0} : {1}".format(appid, e))
|
||||||
|
|
||||||
logging.info("Finished.")
|
logging.info(_("Finished"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -49,6 +49,7 @@ from pyasn1.error import PyAsn1Error
|
|||||||
from distutils.util import strtobool
|
from distutils.util import strtobool
|
||||||
|
|
||||||
import fdroidserver.metadata
|
import fdroidserver.metadata
|
||||||
|
from fdroidserver import _
|
||||||
from fdroidserver.exception import FDroidException, VCSException, BuildException
|
from fdroidserver.exception import FDroidException, VCSException, BuildException
|
||||||
from .asynchronousfilereader import AsynchronousFileReader
|
from .asynchronousfilereader import AsynchronousFileReader
|
||||||
|
|
||||||
@ -123,9 +124,9 @@ default_config = {
|
|||||||
|
|
||||||
def setup_global_opts(parser):
|
def setup_global_opts(parser):
|
||||||
parser.add_argument("-v", "--verbose", action="store_true", default=False,
|
parser.add_argument("-v", "--verbose", action="store_true", default=False,
|
||||||
help="Spew out even more information than normal")
|
help=_("Spew out even more information than normal"))
|
||||||
parser.add_argument("-q", "--quiet", action="store_true", default=False,
|
parser.add_argument("-q", "--quiet", action="store_true", default=False,
|
||||||
help="Restrict output to warnings and errors")
|
help=_("Restrict output to warnings and errors"))
|
||||||
|
|
||||||
|
|
||||||
def fill_config_defaults(thisconfig):
|
def fill_config_defaults(thisconfig):
|
||||||
@ -1022,9 +1023,9 @@ def retrieve_string(app_dir, string, xmlfiles=None):
|
|||||||
os.path.join(app_dir, 'res'),
|
os.path.join(app_dir, 'res'),
|
||||||
os.path.join(app_dir, 'src', 'main', 'res'),
|
os.path.join(app_dir, 'src', 'main', 'res'),
|
||||||
]:
|
]:
|
||||||
for r, d, f in os.walk(res_dir):
|
for root, dirs, files in os.walk(res_dir):
|
||||||
if os.path.basename(r) == 'values':
|
if os.path.basename(root) == 'values':
|
||||||
xmlfiles += [os.path.join(r, x) for x in f if x.endswith('.xml')]
|
xmlfiles += [os.path.join(root, x) for x in files if x.endswith('.xml')]
|
||||||
|
|
||||||
name = string[len('@string/'):]
|
name = string[len('@string/'):]
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ from time import sleep
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from subprocess import CalledProcessError, check_output
|
from subprocess import CalledProcessError, check_output
|
||||||
|
|
||||||
from fdroidserver import common, metadata
|
from . import _
|
||||||
|
from . import common
|
||||||
|
from . import metadata
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from docker import Client
|
from docker import Client
|
||||||
@ -407,25 +409,25 @@ def main():
|
|||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"app_id", nargs='*',
|
"app_id", nargs='*',
|
||||||
help="app-id with optional versioncode in the form APPID[:VERCODE]")
|
help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-l", "--latest", action="store_true", default=False,
|
"-l", "--latest", action="store_true", default=False,
|
||||||
help="Scan only the latest version of each package")
|
help=_("Scan only the latest version of each package"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--clean-after", default=False, action='store_true',
|
"--clean-after", default=False, action='store_true',
|
||||||
help="Clean after all scans have finished")
|
help=_("Clean after all scans have finished"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--clean-before", default=False, action='store_true',
|
"--clean-before", default=False, action='store_true',
|
||||||
help="Clean before the scans start and rebuild the container")
|
help=_("Clean before the scans start and rebuild the container"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--clean-only", default=False, action='store_true',
|
"--clean-only", default=False, action='store_true',
|
||||||
help="Clean up all containers and then exit")
|
help=_("Clean up all containers and then exit"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--init-only", default=False, action='store_true',
|
"--init-only", default=False, action='store_true',
|
||||||
help="Prepare drozer to run a scan")
|
help=_("Prepare drozer to run a scan"))
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--repo-path", default="repo", action="store",
|
"--repo-path", default="repo", action="store",
|
||||||
help="Override path for repo APKs (default: ./repo)")
|
help=_("Override path for repo APKs (default: ./repo)"))
|
||||||
|
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
config = common.read_config(options)
|
config = common.read_config(options)
|
||||||
|
@ -21,6 +21,7 @@ import glob
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from .common import FDroidPopen
|
from .common import FDroidPopen
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
@ -46,7 +47,7 @@ def main():
|
|||||||
|
|
||||||
for output_dir in repodirs:
|
for output_dir in repodirs:
|
||||||
if not os.path.isdir(output_dir):
|
if not os.path.isdir(output_dir):
|
||||||
raise FDroidException("Missing output directory '" + output_dir + "'")
|
raise FDroidException(_("Missing output directory") + " '" + output_dir + "'")
|
||||||
|
|
||||||
# Process any apks that are waiting to be signed...
|
# Process any apks that are waiting to be signed...
|
||||||
for f in sorted(glob.glob(os.path.join(output_dir, '*.*'))):
|
for f in sorted(glob.glob(os.path.join(output_dir, '*.*'))):
|
||||||
|
@ -26,6 +26,7 @@ from argparse import ArgumentParser
|
|||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
@ -59,7 +60,7 @@ def getrepofrompage(url):
|
|||||||
repo = page[index + 9:]
|
repo = page[index + 9:]
|
||||||
index = repo.find('<')
|
index = repo.find('<')
|
||||||
if index == -1:
|
if index == -1:
|
||||||
return (None, "Error while getting repo address")
|
return (None, _("Error while getting repo address"))
|
||||||
repo = repo[:index]
|
repo = repo[:index]
|
||||||
repo = repo.split('"')[0]
|
repo = repo.split('"')[0]
|
||||||
return (repotype, repo)
|
return (repotype, repo)
|
||||||
@ -71,12 +72,12 @@ def getrepofrompage(url):
|
|||||||
repo = page[index + 10:]
|
repo = page[index + 10:]
|
||||||
index = repo.find('<')
|
index = repo.find('<')
|
||||||
if index == -1:
|
if index == -1:
|
||||||
return (None, "Error while getting repo address")
|
return (None, _("Error while getting repo address"))
|
||||||
repo = repo[:index]
|
repo = repo[:index]
|
||||||
repo = repo.split('"')[0]
|
repo = repo.split('"')[0]
|
||||||
return (repotype, repo)
|
return (repotype, repo)
|
||||||
|
|
||||||
return (None, "No information found." + page)
|
return (None, _("No information found.") + page)
|
||||||
|
|
||||||
|
|
||||||
config = None
|
config = None
|
||||||
@ -87,7 +88,7 @@ def get_metadata_from_url(app, url):
|
|||||||
|
|
||||||
tmp_dir = 'tmp'
|
tmp_dir = 'tmp'
|
||||||
if not os.path.isdir(tmp_dir):
|
if not os.path.isdir(tmp_dir):
|
||||||
logging.info("Creating temporary directory")
|
logging.info(_("Creating temporary directory"))
|
||||||
os.makedirs(tmp_dir)
|
os.makedirs(tmp_dir)
|
||||||
|
|
||||||
# Figure out what kind of project it is...
|
# Figure out what kind of project it is...
|
||||||
@ -190,15 +191,15 @@ def main():
|
|||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("-u", "--url", default=None,
|
parser.add_argument("-u", "--url", default=None,
|
||||||
help="Project URL to import from.")
|
help=_("Project URL to import from."))
|
||||||
parser.add_argument("-s", "--subdir", default=None,
|
parser.add_argument("-s", "--subdir", default=None,
|
||||||
help="Path to main android project subdirectory, if not in root.")
|
help=_("Path to main android project subdirectory, if not in root."))
|
||||||
parser.add_argument("-c", "--categories", default=None,
|
parser.add_argument("-c", "--categories", default=None,
|
||||||
help="Comma separated list of categories.")
|
help=_("Comma separated list of categories."))
|
||||||
parser.add_argument("-l", "--license", default=None,
|
parser.add_argument("-l", "--license", default=None,
|
||||||
help="Overall license of the project.")
|
help=_("Overall license of the project."))
|
||||||
parser.add_argument("--rev", default=None,
|
parser.add_argument("--rev", default=None,
|
||||||
help="Allows a different revision (or git branch) to be specified for the initial import")
|
help=_("Allows a different revision (or git branch) to be specified for the initial import"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -214,7 +215,7 @@ def main():
|
|||||||
|
|
||||||
local_metadata_files = common.get_local_metadata_files()
|
local_metadata_files = common.get_local_metadata_files()
|
||||||
if local_metadata_files != []:
|
if local_metadata_files != []:
|
||||||
raise FDroidException("This repo already has local metadata: %s" % local_metadata_files[0])
|
raise FDroidException(_("This repo already has local metadata: %s") % local_metadata_files[0])
|
||||||
|
|
||||||
if options.url is None and os.path.isdir('.git'):
|
if options.url is None and os.path.isdir('.git'):
|
||||||
app.AutoName = os.path.basename(os.getcwd())
|
app.AutoName = os.path.basename(os.getcwd())
|
||||||
@ -252,11 +253,11 @@ def main():
|
|||||||
|
|
||||||
versionName, versionCode, package = common.parse_androidmanifests(paths, app)
|
versionName, versionCode, package = common.parse_androidmanifests(paths, app)
|
||||||
if not package:
|
if not package:
|
||||||
raise FDroidException("Couldn't find package ID")
|
raise FDroidException(_("Couldn't find package ID"))
|
||||||
if not versionName:
|
if not versionName:
|
||||||
logging.warn("Couldn't find latest version name")
|
logging.warn(_("Couldn't find latest version name"))
|
||||||
if not versionCode:
|
if not versionCode:
|
||||||
logging.warn("Couldn't find latest version code")
|
logging.warn(_("Couldn't find latest version code"))
|
||||||
else:
|
else:
|
||||||
spec = os.path.join(root_dir, 'buildozer.spec')
|
spec = os.path.join(root_dir, 'buildozer.spec')
|
||||||
if os.path.exists(spec):
|
if os.path.exists(spec):
|
||||||
@ -268,7 +269,7 @@ def main():
|
|||||||
versionName = bconfig.get('app', 'version')
|
versionName = bconfig.get('app', 'version')
|
||||||
versionCode = None
|
versionCode = None
|
||||||
else:
|
else:
|
||||||
raise FDroidException("No android or kivy project could be found. Specify --subdir?")
|
raise FDroidException(_("No android or kivy project could be found. Specify --subdir?"))
|
||||||
|
|
||||||
# Make sure it's actually new...
|
# Make sure it's actually new...
|
||||||
if package in apps:
|
if package in apps:
|
||||||
|
@ -34,7 +34,11 @@ from binascii import hexlify, unhexlify
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from xml.dom.minidom import Document
|
from xml.dom.minidom import Document
|
||||||
|
|
||||||
from fdroidserver import metadata, signindex, common, net
|
from . import _
|
||||||
|
from . import common
|
||||||
|
from . import metadata
|
||||||
|
from . import net
|
||||||
|
from . import signindex
|
||||||
from fdroidserver.common import FDroidPopen, FDroidPopenBytes
|
from fdroidserver.common import FDroidPopen, FDroidPopenBytes
|
||||||
from fdroidserver.exception import FDroidException, VerificationException, MetaDataException
|
from fdroidserver.exception import FDroidException, VerificationException, MetaDataException
|
||||||
|
|
||||||
@ -62,16 +66,16 @@ def make(apps, sortedids, apks, repodir, archive):
|
|||||||
if not common.options.nosign:
|
if not common.options.nosign:
|
||||||
if 'repo_keyalias' not in common.config:
|
if 'repo_keyalias' not in common.config:
|
||||||
nosigningkey = True
|
nosigningkey = True
|
||||||
logging.critical("'repo_keyalias' not found in config.py!")
|
logging.critical(_("'repo_keyalias' not found in config.py!"))
|
||||||
if 'keystore' not in common.config:
|
if 'keystore' not in common.config:
|
||||||
nosigningkey = True
|
nosigningkey = True
|
||||||
logging.critical("'keystore' not found in config.py!")
|
logging.critical(_("'keystore' not found in config.py!"))
|
||||||
if 'keystorepass' not in common.config:
|
if 'keystorepass' not in common.config:
|
||||||
nosigningkey = True
|
nosigningkey = True
|
||||||
logging.critical("'keystorepass' not found in config.py!")
|
logging.critical(_("'keystorepass' not found in config.py!"))
|
||||||
if 'keypass' not in common.config:
|
if 'keypass' not in common.config:
|
||||||
nosigningkey = True
|
nosigningkey = True
|
||||||
logging.critical("'keypass' not found in config.py!")
|
logging.critical(_("'keypass' not found in config.py!"))
|
||||||
if not os.path.exists(common.config['keystore']):
|
if not os.path.exists(common.config['keystore']):
|
||||||
nosigningkey = True
|
nosigningkey = True
|
||||||
logging.critical("'" + common.config['keystore'] + "' does not exist!")
|
logging.critical("'" + common.config['keystore'] + "' does not exist!")
|
||||||
@ -104,7 +108,7 @@ def make(apps, sortedids, apks, repodir, archive):
|
|||||||
for mirror in sorted(common.config.get('mirrors', [])):
|
for mirror in sorted(common.config.get('mirrors', [])):
|
||||||
base = os.path.basename(urllib.parse.urlparse(mirror).path.rstrip('/'))
|
base = os.path.basename(urllib.parse.urlparse(mirror).path.rstrip('/'))
|
||||||
if common.config.get('nonstandardwebroot') is not True and base != 'fdroid':
|
if common.config.get('nonstandardwebroot') is not True and base != 'fdroid':
|
||||||
logging.error("mirror '" + mirror + "' does not end with 'fdroid'!")
|
logging.error(_("mirror '%s' does not end with 'fdroid'!") % mirror)
|
||||||
mirrorcheckfailed = True
|
mirrorcheckfailed = True
|
||||||
# must end with / or urljoin strips a whole path segment
|
# must end with / or urljoin strips a whole path segment
|
||||||
if mirror.endswith('/'):
|
if mirror.endswith('/'):
|
||||||
@ -115,7 +119,7 @@ def make(apps, sortedids, apks, repodir, archive):
|
|||||||
for url in get_mirror_service_urls(mirror):
|
for url in get_mirror_service_urls(mirror):
|
||||||
mirrors.append(url + '/' + repodir)
|
mirrors.append(url + '/' + repodir)
|
||||||
if mirrorcheckfailed:
|
if mirrorcheckfailed:
|
||||||
raise FDroidException("Malformed repository mirrors.")
|
raise FDroidException(_("Malformed repository mirrors."))
|
||||||
if mirrors:
|
if mirrors:
|
||||||
repodict['mirrors'] = mirrors
|
repodict['mirrors'] = mirrors
|
||||||
|
|
||||||
@ -144,7 +148,7 @@ def make(apps, sortedids, apks, repodir, archive):
|
|||||||
elif all(isinstance(item, str) for item in common.config[key]):
|
elif all(isinstance(item, str) for item in common.config[key]):
|
||||||
packageNames = common.config[key]
|
packageNames = common.config[key]
|
||||||
else:
|
else:
|
||||||
raise TypeError('only accepts strings, lists, and tuples')
|
raise TypeError(_('only accepts strings, lists, and tuples'))
|
||||||
requestsdict[command] = packageNames
|
requestsdict[command] = packageNames
|
||||||
|
|
||||||
make_v0(appsWithPackages, apks, repodir, repodict, requestsdict)
|
make_v0(appsWithPackages, apks, repodir, repodict, requestsdict)
|
||||||
@ -199,7 +203,7 @@ def make_v1(apps, packages, repodir, repodict, requestsdict):
|
|||||||
for package in packages:
|
for package in packages:
|
||||||
packageName = package['packageName']
|
packageName = package['packageName']
|
||||||
if packageName not in apps:
|
if packageName not in apps:
|
||||||
logging.info('Ignoring package without metadata: ' + package['apkName'])
|
logging.info(_('Ignoring package without metadata: ') + package['apkName'])
|
||||||
continue
|
continue
|
||||||
if packageName in output_packages:
|
if packageName in output_packages:
|
||||||
packagelist = output_packages[packageName]
|
packagelist = output_packages[packageName]
|
||||||
@ -224,7 +228,7 @@ def make_v1(apps, packages, repodir, repodict, requestsdict):
|
|||||||
json.dump(output, fp, default=_index_encoder_default)
|
json.dump(output, fp, default=_index_encoder_default)
|
||||||
|
|
||||||
if common.options.nosign:
|
if common.options.nosign:
|
||||||
logging.debug('index-v1 must have a signature, use `fdroid signindex` to create it!')
|
logging.debug(_('index-v1 must have a signature, use `fdroid signindex` to create it!'))
|
||||||
else:
|
else:
|
||||||
signindex.config = common.config
|
signindex.config = common.config
|
||||||
signindex.sign_index_v1(repodir, json_name)
|
signindex.sign_index_v1(repodir, json_name)
|
||||||
@ -501,9 +505,9 @@ def make_v0(apps, apks, repodir, repodict, requestsdict):
|
|||||||
if 'repo_keyalias' in common.config:
|
if 'repo_keyalias' in common.config:
|
||||||
|
|
||||||
if common.options.nosign:
|
if common.options.nosign:
|
||||||
logging.info("Creating unsigned index in preparation for signing")
|
logging.info(_("Creating unsigned index in preparation for signing"))
|
||||||
else:
|
else:
|
||||||
logging.info("Creating signed index with this key (SHA256):")
|
logging.info(_("Creating signed index with this key (SHA256):"))
|
||||||
logging.info("%s" % repo_pubkey_fingerprint)
|
logging.info("%s" % repo_pubkey_fingerprint)
|
||||||
|
|
||||||
# Create a jar of the index...
|
# Create a jar of the index...
|
||||||
@ -613,7 +617,7 @@ def download_repo_index(url_str, etag=None, verify_fingerprint=True):
|
|||||||
if verify_fingerprint:
|
if verify_fingerprint:
|
||||||
query = urllib.parse.parse_qs(url.query)
|
query = urllib.parse.parse_qs(url.query)
|
||||||
if 'fingerprint' not in query:
|
if 'fingerprint' not in query:
|
||||||
raise VerificationException("No fingerprint in URL.")
|
raise VerificationException(_("No fingerprint in URL."))
|
||||||
fingerprint = query['fingerprint'][0]
|
fingerprint = query['fingerprint'][0]
|
||||||
|
|
||||||
url = urllib.parse.SplitResult(url.scheme, url.netloc, url.path + '/index-v1.jar', '', '')
|
url = urllib.parse.SplitResult(url.scheme, url.netloc, url.path + '/index-v1.jar', '', '')
|
||||||
@ -635,7 +639,7 @@ def download_repo_index(url_str, etag=None, verify_fingerprint=True):
|
|||||||
|
|
||||||
# compare the fingerprint if verify_fingerprint is True
|
# compare the fingerprint if verify_fingerprint is True
|
||||||
if verify_fingerprint and fingerprint.upper() != public_key_fingerprint:
|
if verify_fingerprint and fingerprint.upper() != public_key_fingerprint:
|
||||||
raise VerificationException("The repository's fingerprint does not match.")
|
raise VerificationException(_("The repository's fingerprint does not match."))
|
||||||
|
|
||||||
# load repository index from JSON
|
# load repository index from JSON
|
||||||
index = json.loads(jar.read('index-v1.json').decode("utf-8"))
|
index = json.loads(jar.read('index-v1.json').decode("utf-8"))
|
||||||
@ -655,7 +659,7 @@ def verify_jar_signature(file):
|
|||||||
:raises: VerificationException() if the JAR's signature could not be verified
|
:raises: VerificationException() if the JAR's signature could not be verified
|
||||||
"""
|
"""
|
||||||
if not common.verify_apk_signature(file, jar=True):
|
if not common.verify_apk_signature(file, jar=True):
|
||||||
raise VerificationException("The repository's index could not be verified.")
|
raise VerificationException(_("The repository's index could not be verified."))
|
||||||
|
|
||||||
|
|
||||||
def get_public_key_from_jar(jar):
|
def get_public_key_from_jar(jar):
|
||||||
@ -670,9 +674,9 @@ def get_public_key_from_jar(jar):
|
|||||||
# extract certificate from jar
|
# extract certificate from jar
|
||||||
certs = [n for n in jar.namelist() if common.CERT_PATH_REGEX.match(n)]
|
certs = [n for n in jar.namelist() if common.CERT_PATH_REGEX.match(n)]
|
||||||
if len(certs) < 1:
|
if len(certs) < 1:
|
||||||
raise VerificationException("Found no signing certificates for repository.")
|
raise VerificationException(_("Found no signing certificates for repository."))
|
||||||
if len(certs) > 1:
|
if len(certs) > 1:
|
||||||
raise VerificationException("Found multiple signing certificates for repository.")
|
raise VerificationException(_("Found multiple signing certificates for repository."))
|
||||||
|
|
||||||
# extract public key from certificate
|
# extract public key from certificate
|
||||||
public_key = common.get_certificate(jar.read(certs[0]))
|
public_key = common.get_certificate(jar.read(certs[0]))
|
||||||
|
@ -27,6 +27,7 @@ import sys
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
|
|
||||||
@ -53,15 +54,15 @@ def main():
|
|||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("-d", "--distinguished-name", default=None,
|
parser.add_argument("-d", "--distinguished-name", default=None,
|
||||||
help="X.509 'Distiguished Name' used when generating keys")
|
help=_("X.509 'Distiguished Name' used when generating keys"))
|
||||||
parser.add_argument("--keystore", default=None,
|
parser.add_argument("--keystore", default=None,
|
||||||
help="Path to the keystore for the repo signing key")
|
help=_("Path to the keystore for the repo signing key"))
|
||||||
parser.add_argument("--repo-keyalias", default=None,
|
parser.add_argument("--repo-keyalias", default=None,
|
||||||
help="Alias of the repo signing key in the keystore")
|
help=_("Alias of the repo signing key in the keystore"))
|
||||||
parser.add_argument("--android-home", default=None,
|
parser.add_argument("--android-home", default=None,
|
||||||
help="Path to the Android SDK (sometimes set in ANDROID_HOME)")
|
help=_("Path to the Android SDK (sometimes set in ANDROID_HOME)"))
|
||||||
parser.add_argument("--no-prompt", action="store_true", default=False,
|
parser.add_argument("--no-prompt", action="store_true", default=False,
|
||||||
help="Do not prompt for Android SDK path, just fail")
|
help=_("Do not prompt for Android SDK path, just fail"))
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
# find root install prefix
|
# find root install prefix
|
||||||
@ -106,8 +107,7 @@ def main():
|
|||||||
'AppData', 'Local', 'Android', 'android-sdk')
|
'AppData', 'Local', 'Android', 'android-sdk')
|
||||||
while not options.no_prompt:
|
while not options.no_prompt:
|
||||||
try:
|
try:
|
||||||
s = input('Enter the path to the Android SDK ('
|
s = input(_('Enter the path to the Android SDK (%s) here:\n> ') % default_sdk_path)
|
||||||
+ default_sdk_path + ') here:\n> ')
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print('')
|
print('')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@ -231,21 +231,20 @@ def main():
|
|||||||
common.write_to_config(test_config, 'keydname', c['keydname'])
|
common.write_to_config(test_config, 'keydname', c['keydname'])
|
||||||
common.genkeystore(c)
|
common.genkeystore(c)
|
||||||
|
|
||||||
logging.info('Built repo based in "' + fdroiddir + '"')
|
msg = '\n'
|
||||||
logging.info('with this config:')
|
msg += _('Built repo based in "%s" with this config:') % fdroiddir
|
||||||
logging.info(' Android SDK:\t\t\t' + config['sdk_path'])
|
msg += '\n\n Android SDK:\t\t\t' + config['sdk_path']
|
||||||
if aapt:
|
if aapt:
|
||||||
logging.info(' Android SDK Build Tools:\t' + os.path.dirname(aapt))
|
msg += '\n Android SDK Build Tools:\t' + os.path.dirname(aapt)
|
||||||
logging.info(' Android NDK r12b (optional):\t$ANDROID_NDK')
|
msg += '\n Android NDK r12b (optional):\t$ANDROID_NDK'
|
||||||
logging.info(' Keystore for signing key:\t' + keystore)
|
msg += '\n ' + _('Keystore for signing key:\t') + keystore
|
||||||
if repo_keyalias is not None:
|
if repo_keyalias is not None:
|
||||||
logging.info(' Alias for key in store:\t' + repo_keyalias)
|
msg += '\n Alias for key in store:\t' + repo_keyalias
|
||||||
logging.info('\nTo complete the setup, add your APKs to "' +
|
msg += '\n\n' + '''To complete the setup, add your APKs to "%s"
|
||||||
os.path.join(fdroiddir, 'repo') + '"' + '''
|
|
||||||
then run "fdroid update -c; fdroid update". You might also want to edit
|
then run "fdroid update -c; fdroid update". You might also want to edit
|
||||||
"config.py" to set the URL, repo name, and more. You should also set up
|
"config.py" to set the URL, repo name, and more. You should also set up
|
||||||
a signing key (a temporary one might have been automatically generated).
|
a signing key (a temporary one might have been automatically generated).
|
||||||
|
|
||||||
For more info: https://f-droid.org/docs/Setup_an_F-Droid_App_Repo
|
For more info: https://f-droid.org/docs/Setup_an_F-Droid_App_Repo
|
||||||
and https://f-droid.org/docs/Signing_Process
|
and https://f-droid.org/docs/Signing_Process''' % os.path.join(fdroiddir, 'repo')
|
||||||
''')
|
logging.info(msg)
|
||||||
|
@ -23,6 +23,7 @@ import glob
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from .common import SdkToolsPopen
|
from .common import SdkToolsPopen
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
@ -49,19 +50,19 @@ def main():
|
|||||||
# Parse command line...
|
# Parse command line...
|
||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("appid", nargs='*', help="app-id with optional versionCode in the form APPID[:VERCODE]")
|
parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
|
||||||
parser.add_argument("-a", "--all", action="store_true", default=False,
|
parser.add_argument("-a", "--all", action="store_true", default=False,
|
||||||
help="Install all signed applications available")
|
help=_("Install all signed applications available"))
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
if not options.appid and not options.all:
|
if not options.appid and not options.all:
|
||||||
parser.error("option %s: If you really want to install all the signed apps, use --all" % "all")
|
parser.error(_("option %s: If you really want to install all the signed apps, use --all") % "all")
|
||||||
|
|
||||||
config = common.read_config(options)
|
config = common.read_config(options)
|
||||||
|
|
||||||
output_dir = 'repo'
|
output_dir = 'repo'
|
||||||
if not os.path.isdir(output_dir):
|
if not os.path.isdir(output_dir):
|
||||||
logging.info("No signed output directory - nothing to do")
|
logging.info(_("No signed output directory - nothing to do"))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if options.appid:
|
if options.appid:
|
||||||
@ -84,7 +85,7 @@ def main():
|
|||||||
|
|
||||||
for appid, apk in apks.items():
|
for appid, apk in apks.items():
|
||||||
if not apk:
|
if not apk:
|
||||||
raise FDroidException("No signed apk available for %s" % appid)
|
raise FDroidException(_("No signed apk available for %s") % appid)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
||||||
@ -95,10 +96,10 @@ def main():
|
|||||||
# Get device list each time to avoid device not found errors
|
# Get device list each time to avoid device not found errors
|
||||||
devs = devices()
|
devs = devices()
|
||||||
if not devs:
|
if not devs:
|
||||||
raise FDroidException("No attached devices found")
|
raise FDroidException(_("No attached devices found"))
|
||||||
logging.info("Installing %s..." % apk)
|
logging.info(_("Installing %s...") % apk)
|
||||||
for dev in devs:
|
for dev in devs:
|
||||||
logging.info("Installing %s on %s..." % (apk, dev))
|
logging.info(_("Installing %s on %s...") % (apk, dev))
|
||||||
p = SdkToolsPopen(['adb', "-s", dev, "install", apk])
|
p = SdkToolsPopen(['adb', "-s", dev, "install", apk])
|
||||||
fail = ""
|
fail = ""
|
||||||
for line in p.output.splitlines():
|
for line in p.output.splitlines():
|
||||||
@ -108,12 +109,12 @@ def main():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if fail == "INSTALL_FAILED_ALREADY_EXISTS":
|
if fail == "INSTALL_FAILED_ALREADY_EXISTS":
|
||||||
logging.warn("%s is already installed on %s." % (apk, dev))
|
logging.warn(_("%s is already installed on %s.") % (apk, dev))
|
||||||
else:
|
else:
|
||||||
raise FDroidException("Failed to install %s on %s: %s" % (
|
raise FDroidException(_("Failed to install %s on %s: %s") % (
|
||||||
apk, dev, fail))
|
apk, dev, fail))
|
||||||
|
|
||||||
logging.info("\nFinished")
|
logging.info('\n' + _('Finished'))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -22,6 +22,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from . import rewritemeta
|
from . import rewritemeta
|
||||||
@ -47,7 +48,7 @@ https_enforcings = [
|
|||||||
|
|
||||||
def forbid_shortener(domain):
|
def forbid_shortener(domain):
|
||||||
return (re.compile(r'https?://[^/]*' + re.escape(domain) + r'/.*'),
|
return (re.compile(r'https?://[^/]*' + re.escape(domain) + r'/.*'),
|
||||||
"URL shorteners should not be used")
|
_("URL shorteners should not be used"))
|
||||||
|
|
||||||
|
|
||||||
http_url_shorteners = [
|
http_url_shorteners = [
|
||||||
@ -62,9 +63,9 @@ http_url_shorteners = [
|
|||||||
|
|
||||||
http_checks = https_enforcings + http_url_shorteners + [
|
http_checks = https_enforcings + http_url_shorteners + [
|
||||||
(re.compile(r'.*github\.com/[^/]+/[^/]+\.git'),
|
(re.compile(r'.*github\.com/[^/]+/[^/]+\.git'),
|
||||||
"Appending .git is not necessary"),
|
_("Appending .git is not necessary")),
|
||||||
(re.compile(r'.*://[^/]*(github|gitlab|bitbucket|rawgit)[^/]*/([^/]+/){1,3}master'),
|
(re.compile(r'.*://[^/]*(github|gitlab|bitbucket|rawgit)[^/]*/([^/]+/){1,3}master'),
|
||||||
"Use /HEAD instead of /master to point at a file in the default branch"),
|
_("Use /HEAD instead of /master to point at a file in the default branch")),
|
||||||
]
|
]
|
||||||
|
|
||||||
regex_checks = {
|
regex_checks = {
|
||||||
@ -73,44 +74,44 @@ regex_checks = {
|
|||||||
'Repo': https_enforcings,
|
'Repo': https_enforcings,
|
||||||
'IssueTracker': http_checks + [
|
'IssueTracker': http_checks + [
|
||||||
(re.compile(r'.*github\.com/[^/]+/[^/]+/*$'),
|
(re.compile(r'.*github\.com/[^/]+/[^/]+/*$'),
|
||||||
"/issues is missing"),
|
_("/issues is missing")),
|
||||||
(re.compile(r'.*gitlab\.com/[^/]+/[^/]+/*$'),
|
(re.compile(r'.*gitlab\.com/[^/]+/[^/]+/*$'),
|
||||||
"/issues is missing"),
|
_("/issues is missing")),
|
||||||
],
|
],
|
||||||
'Donate': http_checks + [
|
'Donate': http_checks + [
|
||||||
(re.compile(r'.*flattr\.com'),
|
(re.compile(r'.*flattr\.com'),
|
||||||
"Flattr donation methods belong in the FlattrID flag"),
|
_("Flattr donation methods belong in the FlattrID flag")),
|
||||||
],
|
],
|
||||||
'Changelog': http_checks,
|
'Changelog': http_checks,
|
||||||
'Author Name': [
|
'Author Name': [
|
||||||
(re.compile(r'^\s'),
|
(re.compile(r'^\s'),
|
||||||
"Unnecessary leading space"),
|
_("Unnecessary leading space")),
|
||||||
(re.compile(r'.*\s$'),
|
(re.compile(r'.*\s$'),
|
||||||
"Unnecessary trailing space"),
|
_("Unnecessary trailing space")),
|
||||||
],
|
],
|
||||||
'Summary': [
|
'Summary': [
|
||||||
(re.compile(r'.*\b(free software|open source)\b.*', re.IGNORECASE),
|
(re.compile(r'.*\b(free software|open source)\b.*', re.IGNORECASE),
|
||||||
"No need to specify that the app is Free Software"),
|
_("No need to specify that the app is Free Software")),
|
||||||
(re.compile(r'.*((your|for).*android|android.*(app|device|client|port|version))', re.IGNORECASE),
|
(re.compile(r'.*((your|for).*android|android.*(app|device|client|port|version))', re.IGNORECASE),
|
||||||
"No need to specify that the app is for Android"),
|
_("No need to specify that the app is for Android")),
|
||||||
(re.compile(r'.*[a-z0-9][.!?]( |$)'),
|
(re.compile(r'.*[a-z0-9][.!?]( |$)'),
|
||||||
"Punctuation should be avoided"),
|
_("Punctuation should be avoided")),
|
||||||
(re.compile(r'^\s'),
|
(re.compile(r'^\s'),
|
||||||
"Unnecessary leading space"),
|
_("Unnecessary leading space")),
|
||||||
(re.compile(r'.*\s$'),
|
(re.compile(r'.*\s$'),
|
||||||
"Unnecessary trailing space"),
|
_("Unnecessary trailing space")),
|
||||||
],
|
],
|
||||||
'Description': [
|
'Description': [
|
||||||
(re.compile(r'\s*[*#][^ .]'),
|
(re.compile(r'\s*[*#][^ .]'),
|
||||||
"Invalid bulleted list"),
|
_("Invalid bulleted list")),
|
||||||
(re.compile(r'^\s'),
|
(re.compile(r'^\s'),
|
||||||
"Unnecessary leading space"),
|
_("Unnecessary leading space")),
|
||||||
(re.compile(r'.*\s$'),
|
(re.compile(r'.*\s$'),
|
||||||
"Unnecessary trailing space"),
|
_("Unnecessary trailing space")),
|
||||||
(re.compile(r'.*([^[]|^)\[[^:[\]]+( |\]|$)'),
|
(re.compile(r'.*([^[]|^)\[[^:[\]]+( |\]|$)'),
|
||||||
"Invalid link - use [http://foo.bar Link title] or [http://foo.bar]"),
|
_("Invalid link - use [http://foo.bar Link title] or [http://foo.bar]")),
|
||||||
(re.compile(r'(^|.* )https?://[^ ]+'),
|
(re.compile(r'(^|.* )https?://[^ ]+'),
|
||||||
"Unlinkified link - use [http://foo.bar Link title] or [http://foo.bar]"),
|
_("Unlinkified link - use [http://foo.bar Link title] or [http://foo.bar]")),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +156,7 @@ def check_ucm_tags(app):
|
|||||||
and lastbuild.versionCode == app.CurrentVersionCode
|
and lastbuild.versionCode == app.CurrentVersionCode
|
||||||
and not lastbuild.forcevercode
|
and not lastbuild.forcevercode
|
||||||
and any(s in lastbuild.commit for s in '.,_-/')):
|
and any(s in lastbuild.commit for s in '.,_-/')):
|
||||||
yield "Last used commit '%s' looks like a tag, but Update Check Mode is '%s'" % (
|
yield _("Last used commit '%s' looks like a tag, but Update Check Mode is '%s'") % (
|
||||||
lastbuild.commit, app.UpdateCheckMode)
|
lastbuild.commit, app.UpdateCheckMode)
|
||||||
|
|
||||||
|
|
||||||
@ -163,11 +164,11 @@ def check_char_limits(app):
|
|||||||
limits = config['char_limits']
|
limits = config['char_limits']
|
||||||
|
|
||||||
if len(app.Summary) > limits['summary']:
|
if len(app.Summary) > limits['summary']:
|
||||||
yield "Summary of length %s is over the %i char limit" % (
|
yield _("Summary of length %s is over the %i char limit") % (
|
||||||
len(app.Summary), limits['summary'])
|
len(app.Summary), limits['summary'])
|
||||||
|
|
||||||
if len(app.Description) > limits['description']:
|
if len(app.Description) > limits['description']:
|
||||||
yield "Description of length %s is over the %i char limit" % (
|
yield _("Description of length %s is over the %i char limit") % (
|
||||||
len(app.Description), limits['description'])
|
len(app.Description), limits['description'])
|
||||||
|
|
||||||
|
|
||||||
@ -185,12 +186,12 @@ def check_old_links(app):
|
|||||||
for f in ['WebSite', 'SourceCode', 'IssueTracker', 'Changelog']:
|
for f in ['WebSite', 'SourceCode', 'IssueTracker', 'Changelog']:
|
||||||
v = app.get(f)
|
v = app.get(f)
|
||||||
if any(s in v for s in old_sites):
|
if any(s in v for s in old_sites):
|
||||||
yield "App is in '%s' but has a link to '%s'" % (app.Repo, v)
|
yield _("App is in '%s' but has a link to '%s'") % (app.Repo, v)
|
||||||
|
|
||||||
|
|
||||||
def check_useless_fields(app):
|
def check_useless_fields(app):
|
||||||
if app.UpdateCheckName == app.id:
|
if app.UpdateCheckName == app.id:
|
||||||
yield "Update Check Name is set to the known app id - it can be removed"
|
yield _("Update Check Name is set to the known app id - it can be removed")
|
||||||
|
|
||||||
|
|
||||||
filling_ucms = re.compile(r'^(Tags.*|RepoManifest.*)')
|
filling_ucms = re.compile(r'^(Tags.*|RepoManifest.*)')
|
||||||
@ -199,12 +200,12 @@ filling_ucms = re.compile(r'^(Tags.*|RepoManifest.*)')
|
|||||||
def check_checkupdates_ran(app):
|
def check_checkupdates_ran(app):
|
||||||
if filling_ucms.match(app.UpdateCheckMode):
|
if filling_ucms.match(app.UpdateCheckMode):
|
||||||
if not app.AutoName and not app.CurrentVersion and app.CurrentVersionCode == '0':
|
if not app.AutoName and not app.CurrentVersion and app.CurrentVersionCode == '0':
|
||||||
yield "UCM is set but it looks like checkupdates hasn't been run yet"
|
yield _("UCM is set but it looks like checkupdates hasn't been run yet")
|
||||||
|
|
||||||
|
|
||||||
def check_empty_fields(app):
|
def check_empty_fields(app):
|
||||||
if not app.Categories:
|
if not app.Categories:
|
||||||
yield "Categories are not set"
|
yield _("Categories are not set")
|
||||||
|
|
||||||
|
|
||||||
all_categories = set([
|
all_categories = set([
|
||||||
@ -231,12 +232,12 @@ all_categories = set([
|
|||||||
def check_categories(app):
|
def check_categories(app):
|
||||||
for categ in app.Categories:
|
for categ in app.Categories:
|
||||||
if categ not in all_categories:
|
if categ not in all_categories:
|
||||||
yield "Category '%s' is not valid" % categ
|
yield _("Category '%s' is not valid" % categ)
|
||||||
|
|
||||||
|
|
||||||
def check_duplicates(app):
|
def check_duplicates(app):
|
||||||
if app.Name and app.Name == app.AutoName:
|
if app.Name and app.Name == app.AutoName:
|
||||||
yield "Name '%s' is just the auto name - remove it" % app.Name
|
yield _("Name '%s' is just the auto name - remove it") % app.Name
|
||||||
|
|
||||||
links_seen = set()
|
links_seen = set()
|
||||||
for f in ['Source Code', 'Web Site', 'Issue Tracker', 'Changelog']:
|
for f in ['Source Code', 'Web Site', 'Issue Tracker', 'Changelog']:
|
||||||
@ -245,25 +246,25 @@ def check_duplicates(app):
|
|||||||
continue
|
continue
|
||||||
v = v.lower()
|
v = v.lower()
|
||||||
if v in links_seen:
|
if v in links_seen:
|
||||||
yield "Duplicate link in '%s': %s" % (f, v)
|
yield _("Duplicate link in '%s': %s") % (f, v)
|
||||||
else:
|
else:
|
||||||
links_seen.add(v)
|
links_seen.add(v)
|
||||||
|
|
||||||
name = app.Name or app.AutoName
|
name = app.Name or app.AutoName
|
||||||
if app.Summary and name:
|
if app.Summary and name:
|
||||||
if app.Summary.lower() == name.lower():
|
if app.Summary.lower() == name.lower():
|
||||||
yield "Summary '%s' is just the app's name" % app.Summary
|
yield _("Summary '%s' is just the app's name") % app.Summary
|
||||||
|
|
||||||
if app.Summary and app.Description and len(app.Description) == 1:
|
if app.Summary and app.Description and len(app.Description) == 1:
|
||||||
if app.Summary.lower() == app.Description[0].lower():
|
if app.Summary.lower() == app.Description[0].lower():
|
||||||
yield "Description '%s' is just the app's summary" % app.Summary
|
yield _("Description '%s' is just the app's summary") % app.Summary
|
||||||
|
|
||||||
seenlines = set()
|
seenlines = set()
|
||||||
for l in app.Description.splitlines():
|
for l in app.Description.splitlines():
|
||||||
if len(l) < 1:
|
if len(l) < 1:
|
||||||
continue
|
continue
|
||||||
if l in seenlines:
|
if l in seenlines:
|
||||||
yield "Description has a duplicate line"
|
yield _("Description has a duplicate line")
|
||||||
seenlines.add(l)
|
seenlines.add(l)
|
||||||
|
|
||||||
|
|
||||||
@ -276,7 +277,7 @@ def check_mediawiki_links(app):
|
|||||||
url = um.group(1)
|
url = um.group(1)
|
||||||
for m, r in http_checks:
|
for m, r in http_checks:
|
||||||
if m.match(url):
|
if m.match(url):
|
||||||
yield "URL '%s' in Description: %s" % (url, r)
|
yield _("URL '%s' in Description: %s") % (url, r)
|
||||||
|
|
||||||
|
|
||||||
def check_bulleted_lists(app):
|
def check_bulleted_lists(app):
|
||||||
@ -291,7 +292,7 @@ def check_bulleted_lists(app):
|
|||||||
if l[0] == lchar and l[1] == ' ':
|
if l[0] == lchar and l[1] == ' ':
|
||||||
lcount += 1
|
lcount += 1
|
||||||
if lcount > 2 and lchar not in validchars:
|
if lcount > 2 and lchar not in validchars:
|
||||||
yield "Description has a list (%s) but it isn't bulleted (*) nor numbered (#)" % lchar
|
yield _("Description has a list (%s) but it isn't bulleted (*) nor numbered (#)") % lchar
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
lchar = l[0]
|
lchar = l[0]
|
||||||
@ -304,18 +305,18 @@ def check_builds(app):
|
|||||||
for build in app.builds:
|
for build in app.builds:
|
||||||
if build.disable:
|
if build.disable:
|
||||||
if build.disable.startswith('Generated by import.py'):
|
if build.disable.startswith('Generated by import.py'):
|
||||||
yield "Build generated by `fdroid import` - remove disable line once ready"
|
yield _("Build generated by `fdroid import` - remove disable line once ready")
|
||||||
continue
|
continue
|
||||||
for s in ['master', 'origin', 'HEAD', 'default', 'trunk']:
|
for s in ['master', 'origin', 'HEAD', 'default', 'trunk']:
|
||||||
if build.commit and build.commit.startswith(s):
|
if build.commit and build.commit.startswith(s):
|
||||||
yield "Branch '%s' used as commit in build '%s'" % (s, build.versionName)
|
yield _("Branch '%s' used as commit in build '%s'") % (s, build.versionName)
|
||||||
for srclib in build.srclibs:
|
for srclib in build.srclibs:
|
||||||
ref = srclib.split('@')[1].split('/')[0]
|
ref = srclib.split('@')[1].split('/')[0]
|
||||||
if ref.startswith(s):
|
if ref.startswith(s):
|
||||||
yield "Branch '%s' used as commit in srclib '%s'" % (s, srclib)
|
yield _("Branch '%s' used as commit in srclib '%s'") % (s, srclib)
|
||||||
for key in build.keys():
|
for key in build.keys():
|
||||||
if key not in supported_flags:
|
if key not in supported_flags:
|
||||||
yield key + ' is not an accepted build field'
|
yield _('%s is not an accepted build field') % key
|
||||||
|
|
||||||
|
|
||||||
def check_files_dir(app):
|
def check_files_dir(app):
|
||||||
@ -326,7 +327,7 @@ def check_files_dir(app):
|
|||||||
for name in os.listdir(dir_path):
|
for name in os.listdir(dir_path):
|
||||||
path = os.path.join(dir_path, name)
|
path = os.path.join(dir_path, name)
|
||||||
if not (os.path.isfile(path) or name == 'signatures' or locale_pattern.match(name)):
|
if not (os.path.isfile(path) or name == 'signatures' or locale_pattern.match(name)):
|
||||||
yield "Found non-file at %s" % path
|
yield _("Found non-file at %s") % path
|
||||||
continue
|
continue
|
||||||
files.add(name)
|
files.add(name)
|
||||||
|
|
||||||
@ -334,45 +335,45 @@ def check_files_dir(app):
|
|||||||
for build in app.builds:
|
for build in app.builds:
|
||||||
for fname in build.patch:
|
for fname in build.patch:
|
||||||
if fname not in files:
|
if fname not in files:
|
||||||
yield "Unknown file %s in build '%s'" % (fname, build.versionName)
|
yield _("Unknown file %s in build '%s'") % (fname, build.versionName)
|
||||||
else:
|
else:
|
||||||
used.add(fname)
|
used.add(fname)
|
||||||
|
|
||||||
for name in files.difference(used):
|
for name in files.difference(used):
|
||||||
if locale_pattern.match(name):
|
if locale_pattern.match(name):
|
||||||
continue
|
continue
|
||||||
yield "Unused file at %s" % os.path.join(dir_path, name)
|
yield _("Unused file at %s") % os.path.join(dir_path, name)
|
||||||
|
|
||||||
|
|
||||||
def check_format(app):
|
def check_format(app):
|
||||||
if options.format and not rewritemeta.proper_format(app):
|
if options.format and not rewritemeta.proper_format(app):
|
||||||
yield "Run rewritemeta to fix formatting"
|
yield _("Run rewritemeta to fix formatting")
|
||||||
|
|
||||||
|
|
||||||
def check_license_tag(app):
|
def check_license_tag(app):
|
||||||
'''Ensure all license tags are in https://spdx.org/license-list'''
|
'''Ensure all license tags are in https://spdx.org/license-list'''
|
||||||
if app.License.rstrip('+') not in SPDX:
|
if app.License.rstrip('+') not in SPDX:
|
||||||
yield 'Invalid license tag "%s"! Use only tags from https://spdx.org/license-list' \
|
yield _('Invalid license tag "%s"! Use only tags from https://spdx.org/license-list') \
|
||||||
% (app.License)
|
% (app.License)
|
||||||
|
|
||||||
|
|
||||||
def check_extlib_dir(apps):
|
def check_extlib_dir(apps):
|
||||||
dir_path = os.path.join('build', 'extlib')
|
dir_path = os.path.join('build', 'extlib')
|
||||||
files = set()
|
unused_extlib_files = set()
|
||||||
for root, dirs, names in os.walk(dir_path):
|
for root, dirs, files in os.walk(dir_path):
|
||||||
for name in names:
|
for name in files:
|
||||||
files.add(os.path.join(root, name)[len(dir_path) + 1:])
|
unused_extlib_files.add(os.path.join(root, name)[len(dir_path) + 1:])
|
||||||
|
|
||||||
used = set()
|
used = set()
|
||||||
for app in apps:
|
for app in apps:
|
||||||
for build in app.builds:
|
for build in app.builds:
|
||||||
for path in build.extlibs:
|
for path in build.extlibs:
|
||||||
if path not in files:
|
if path not in unused_extlib_files:
|
||||||
yield "%s: Unknown extlib %s in build '%s'" % (app.id, path, build.versionName)
|
yield _("%s: Unknown extlib %s in build '%s'") % (app.id, path, build.versionName)
|
||||||
else:
|
else:
|
||||||
used.add(path)
|
used.add(path)
|
||||||
|
|
||||||
for path in files.difference(used):
|
for path in unused_extlib_files.difference(used):
|
||||||
if any(path.endswith(s) for s in [
|
if any(path.endswith(s) for s in [
|
||||||
'.gitignore',
|
'.gitignore',
|
||||||
'source.txt', 'origin.txt', 'md5.txt',
|
'source.txt', 'origin.txt', 'md5.txt',
|
||||||
@ -381,7 +382,7 @@ def check_extlib_dir(apps):
|
|||||||
'NOTICE', 'NOTICE.txt',
|
'NOTICE', 'NOTICE.txt',
|
||||||
]):
|
]):
|
||||||
continue
|
continue
|
||||||
yield "Unused extlib at %s" % os.path.join(dir_path, path)
|
yield _("Unused extlib at %s") % os.path.join(dir_path, path)
|
||||||
|
|
||||||
|
|
||||||
def check_for_unsupported_metadata_files(basedir=""):
|
def check_for_unsupported_metadata_files(basedir=""):
|
||||||
@ -397,7 +398,7 @@ def check_for_unsupported_metadata_files(basedir=""):
|
|||||||
for t in formats:
|
for t in formats:
|
||||||
exists = exists or os.path.exists(f + '.' + t)
|
exists = exists or os.path.exists(f + '.' + t)
|
||||||
if not exists:
|
if not exists:
|
||||||
print('"' + f + '/" has no matching metadata file!')
|
print(_('"%s/" has no matching metadata file!') % f)
|
||||||
return_value = True
|
return_value = True
|
||||||
elif not os.path.splitext(f)[1][1:] in formats:
|
elif not os.path.splitext(f)[1][1:] in formats:
|
||||||
print('"' + f.replace(basedir, '')
|
print('"' + f.replace(basedir, '')
|
||||||
@ -415,8 +416,8 @@ def main():
|
|||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("-f", "--format", action="store_true", default=False,
|
parser.add_argument("-f", "--format", action="store_true", default=False,
|
||||||
help="Also warn about formatting issues, like rewritemeta -l")
|
help=_("Also warn about formatting issues, like rewritemeta -l"))
|
||||||
parser.add_argument("appid", nargs='*', help="app-id in the form APPID")
|
parser.add_argument("appid", nargs='*', help=_("applicationId in the form APPID"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
|
@ -35,6 +35,7 @@ except ImportError:
|
|||||||
YamlLoader = Loader
|
YamlLoader = Loader
|
||||||
|
|
||||||
import fdroidserver.common
|
import fdroidserver.common
|
||||||
|
from fdroidserver import _
|
||||||
from fdroidserver.exception import MetaDataException, FDroidException
|
from fdroidserver.exception import MetaDataException, FDroidException
|
||||||
|
|
||||||
srclibs = None
|
srclibs = None
|
||||||
@ -1519,4 +1520,4 @@ def write_metadata(metadatapath, app):
|
|||||||
def add_metadata_arguments(parser):
|
def add_metadata_arguments(parser):
|
||||||
'''add common command line flags related to metadata processing'''
|
'''add common command line flags related to metadata processing'''
|
||||||
parser.add_argument("-W", default='error',
|
parser.add_argument("-W", default='error',
|
||||||
help="force errors to be warnings, or ignore")
|
help=_("force errors to be warnings, or ignore"))
|
||||||
|
@ -26,6 +26,7 @@ import hashlib
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from .common import FDroidPopen, SdkToolsPopen
|
from .common import FDroidPopen, SdkToolsPopen
|
||||||
@ -43,7 +44,7 @@ def main():
|
|||||||
parser = ArgumentParser(usage="%(prog)s [options] "
|
parser = ArgumentParser(usage="%(prog)s [options] "
|
||||||
"[APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
"[APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("appid", nargs='*', help="app-id with optional versionCode in the form APPID[:VERCODE]")
|
parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -51,27 +52,27 @@ def main():
|
|||||||
config = common.read_config(options)
|
config = common.read_config(options)
|
||||||
|
|
||||||
if not ('jarsigner' in config and 'keytool' in config):
|
if not ('jarsigner' in config and 'keytool' in config):
|
||||||
logging.critical('Java JDK not found! Install in standard location or set java_paths!')
|
logging.critical(_('Java JDK not found! Install in standard location or set java_paths!'))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
log_dir = 'logs'
|
log_dir = 'logs'
|
||||||
if not os.path.isdir(log_dir):
|
if not os.path.isdir(log_dir):
|
||||||
logging.info("Creating log directory")
|
logging.info(_("Creating log directory"))
|
||||||
os.makedirs(log_dir)
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
tmp_dir = 'tmp'
|
tmp_dir = 'tmp'
|
||||||
if not os.path.isdir(tmp_dir):
|
if not os.path.isdir(tmp_dir):
|
||||||
logging.info("Creating temporary directory")
|
logging.info(_("Creating temporary directory"))
|
||||||
os.makedirs(tmp_dir)
|
os.makedirs(tmp_dir)
|
||||||
|
|
||||||
output_dir = 'repo'
|
output_dir = 'repo'
|
||||||
if not os.path.isdir(output_dir):
|
if not os.path.isdir(output_dir):
|
||||||
logging.info("Creating output directory")
|
logging.info(_("Creating output directory"))
|
||||||
os.makedirs(output_dir)
|
os.makedirs(output_dir)
|
||||||
|
|
||||||
unsigned_dir = 'unsigned'
|
unsigned_dir = 'unsigned'
|
||||||
if not os.path.isdir(unsigned_dir):
|
if not os.path.isdir(unsigned_dir):
|
||||||
logging.warning("No unsigned directory - nothing to do")
|
logging.warning(_("No unsigned directory - nothing to do"))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not os.path.exists(config['keystore']):
|
if not os.path.exists(config['keystore']):
|
||||||
@ -95,7 +96,7 @@ def main():
|
|||||||
m.update(appid.encode('utf-8'))
|
m.update(appid.encode('utf-8'))
|
||||||
keyalias = m.hexdigest()[:8]
|
keyalias = m.hexdigest()[:8]
|
||||||
if keyalias in allaliases:
|
if keyalias in allaliases:
|
||||||
logging.error("There is a keyalias collision - publishing halted")
|
logging.error(_("There is a keyalias collision - publishing halted"))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
allaliases.append(keyalias)
|
allaliases.append(keyalias)
|
||||||
logging.info("{0} apps, {0} key aliases".format(len(allapps),
|
logging.info("{0} apps, {0} key aliases".format(len(allapps),
|
||||||
@ -208,13 +209,13 @@ def main():
|
|||||||
'SHA1withRSA', '-digestalg', 'SHA1',
|
'SHA1withRSA', '-digestalg', 'SHA1',
|
||||||
apkfile, keyalias], envs=env_vars)
|
apkfile, keyalias], envs=env_vars)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise BuildException("Failed to sign application")
|
raise BuildException(_("Failed to sign application"))
|
||||||
|
|
||||||
# Zipalign it...
|
# Zipalign it...
|
||||||
p = SdkToolsPopen(['zipalign', '-v', '4', apkfile,
|
p = SdkToolsPopen(['zipalign', '-v', '4', apkfile,
|
||||||
os.path.join(output_dir, apkfilename)])
|
os.path.join(output_dir, apkfilename)])
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise BuildException("Failed to align application")
|
raise BuildException(_("Failed to align application"))
|
||||||
os.remove(apkfile)
|
os.remove(apkfile)
|
||||||
|
|
||||||
# Move the source tarball into the output directory...
|
# Move the source tarball into the output directory...
|
||||||
|
@ -22,6 +22,7 @@ import os
|
|||||||
import logging
|
import logging
|
||||||
import io
|
import io
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
|
|
||||||
@ -51,10 +52,10 @@ def main():
|
|||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID [APPID ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("-l", "--list", action="store_true", default=False,
|
parser.add_argument("-l", "--list", action="store_true", default=False,
|
||||||
help="List files that would be reformatted")
|
help=_("List files that would be reformatted"))
|
||||||
parser.add_argument("-t", "--to", default=None,
|
parser.add_argument("-t", "--to", default=None,
|
||||||
help="Rewrite to a specific format: " + ', '.join(supported))
|
help=_("Rewrite to a specific format: ") + ', '.join(supported))
|
||||||
parser.add_argument("appid", nargs='*', help="app-id in the form APPID")
|
parser.add_argument("appid", nargs='*', help=_("applicationId in the form APPID"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -66,21 +67,21 @@ def main():
|
|||||||
apps = common.read_app_args(options.appid, allapps, False)
|
apps = common.read_app_args(options.appid, allapps, False)
|
||||||
|
|
||||||
if options.list and options.to is not None:
|
if options.list and options.to is not None:
|
||||||
parser.error("Cannot use --list and --to at the same time")
|
parser.error(_("Cannot use --list and --to at the same time"))
|
||||||
|
|
||||||
if options.to is not None and options.to not in supported:
|
if options.to is not None and options.to not in supported:
|
||||||
parser.error("Unsupported metadata format, use: --to [" + ' '.join(supported) + "]")
|
parser.error(_("Unsupported metadata format, use: --to [%s]") % ' '.join(supported))
|
||||||
|
|
||||||
for appid, app in apps.items():
|
for appid, app in apps.items():
|
||||||
path = app.metadatapath
|
path = app.metadatapath
|
||||||
base, ext = common.get_extension(path)
|
base, ext = common.get_extension(path)
|
||||||
if not options.to and ext not in supported:
|
if not options.to and ext not in supported:
|
||||||
logging.info("Ignoring %s file at '%s'" % (ext, path))
|
logging.info(_("Ignoring %s file at '%s'") % (ext, path))
|
||||||
continue
|
continue
|
||||||
elif options.to is not None:
|
elif options.to is not None:
|
||||||
logging.info("rewriting '%s' to %s" % (appid, options.to))
|
logging.info(_("rewriting '%s' to %s") % (appid, options.to))
|
||||||
else:
|
else:
|
||||||
logging.info("rewriting '%s'" % (appid))
|
logging.info(_("rewriting '%s'") % (appid))
|
||||||
|
|
||||||
to_ext = ext
|
to_ext = ext
|
||||||
if options.to is not None:
|
if options.to is not None:
|
||||||
@ -107,7 +108,7 @@ def main():
|
|||||||
if ext != to_ext:
|
if ext != to_ext:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
|
|
||||||
logging.debug("Finished.")
|
logging.debug(_("Finished"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -22,6 +22,7 @@ import traceback
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from .exception import BuildException, VCSException
|
from .exception import BuildException, VCSException
|
||||||
@ -165,20 +166,20 @@ def scan_source(build_dir, build):
|
|||||||
return any(command.match(line) for command in gradle_compile_commands)
|
return any(command.match(line) for command in gradle_compile_commands)
|
||||||
|
|
||||||
# Iterate through all files in the source code
|
# Iterate through all files in the source code
|
||||||
for dirpath, dirnames, filenames in os.walk(build_dir, topdown=True):
|
for root, dirs, files in os.walk(build_dir, topdown=True):
|
||||||
|
|
||||||
# It's topdown, so checking the basename is enough
|
# It's topdown, so checking the basename is enough
|
||||||
for ignoredir in ('.hg', '.git', '.svn', '.bzr'):
|
for ignoredir in ('.hg', '.git', '.svn', '.bzr'):
|
||||||
if ignoredir in dirnames:
|
if ignoredir in dirs:
|
||||||
dirnames.remove(ignoredir)
|
dirs.remove(ignoredir)
|
||||||
|
|
||||||
for curfile in filenames:
|
for curfile in files:
|
||||||
|
|
||||||
if curfile in ['.DS_Store']:
|
if curfile in ['.DS_Store']:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Path (relative) to the file
|
# Path (relative) to the file
|
||||||
filepath = os.path.join(dirpath, curfile)
|
filepath = os.path.join(root, curfile)
|
||||||
|
|
||||||
if os.path.islink(filepath):
|
if os.path.islink(filepath):
|
||||||
continue
|
continue
|
||||||
@ -256,7 +257,7 @@ def main():
|
|||||||
# Parse command line...
|
# Parse command line...
|
||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("appid", nargs='*', help="app-id with optional versionCode in the form APPID[:VERCODE]")
|
parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -329,8 +330,8 @@ def main():
|
|||||||
appid, traceback.format_exc()))
|
appid, traceback.format_exc()))
|
||||||
probcount += 1
|
probcount += 1
|
||||||
|
|
||||||
logging.info("Finished:")
|
logging.info(_("Finished"))
|
||||||
print("%d problems found" % probcount)
|
print(_("%d problems found") % probcount)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -29,6 +29,7 @@ from argparse import ArgumentParser
|
|||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
|
|
||||||
@ -154,7 +155,7 @@ def update_awsbucket_libcloud(repo_section):
|
|||||||
if obj.name.startswith(upload_dir + '/'):
|
if obj.name.startswith(upload_dir + '/'):
|
||||||
objs[obj.name] = obj
|
objs[obj.name] = obj
|
||||||
|
|
||||||
for root, _, files in os.walk(os.path.join(os.getcwd(), repo_section)):
|
for root, dirs, files in os.walk(os.path.join(os.getcwd(), repo_section)):
|
||||||
for name in files:
|
for name in files:
|
||||||
upload = False
|
upload = False
|
||||||
file_to_upload = os.path.join(root, name)
|
file_to_upload = os.path.join(root, name)
|
||||||
@ -307,9 +308,9 @@ def update_localcopy(repo_section, local_copy_dir):
|
|||||||
def _get_size(start_path='.'):
|
def _get_size(start_path='.'):
|
||||||
'''get size of all files in a dir https://stackoverflow.com/a/1392549'''
|
'''get size of all files in a dir https://stackoverflow.com/a/1392549'''
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for dirpath, dirnames, filenames in os.walk(start_path):
|
for root, dirs, files in os.walk(start_path):
|
||||||
for f in filenames:
|
for f in files:
|
||||||
fp = os.path.join(dirpath, f)
|
fp = os.path.join(root, f)
|
||||||
total_size += os.path.getsize(fp)
|
total_size += os.path.getsize(fp)
|
||||||
return total_size
|
return total_size
|
||||||
|
|
||||||
@ -577,19 +578,19 @@ def main():
|
|||||||
# Parse command line...
|
# Parse command line...
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("command", help="command to execute, either 'init' or 'update'")
|
parser.add_argument("command", help=_("command to execute, either 'init' or 'update'"))
|
||||||
parser.add_argument("-i", "--identity-file", default=None,
|
parser.add_argument("-i", "--identity-file", default=None,
|
||||||
help="Specify an identity file to provide to SSH for rsyncing")
|
help=_("Specify an identity file to provide to SSH for rsyncing"))
|
||||||
parser.add_argument("--local-copy-dir", default=None,
|
parser.add_argument("--local-copy-dir", default=None,
|
||||||
help="Specify a local folder to sync the repo to")
|
help=_("Specify a local folder to sync the repo to"))
|
||||||
parser.add_argument("--no-checksum", action="store_true", default=False,
|
parser.add_argument("--no-checksum", action="store_true", default=False,
|
||||||
help="Don't use rsync checksums")
|
help=_("Don't use rsync checksums"))
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
config = common.read_config(options)
|
config = common.read_config(options)
|
||||||
|
|
||||||
if options.command != 'init' and options.command != 'update':
|
if options.command != 'init' and options.command != 'update':
|
||||||
logging.critical("The only commands currently supported are 'init' and 'update'")
|
logging.critical(_("The only commands currently supported are 'init' and 'update'"))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if config.get('nonstandardwebroot') is True:
|
if config.get('nonstandardwebroot') is True:
|
||||||
@ -605,7 +606,7 @@ def main():
|
|||||||
elif len(s) == 2:
|
elif len(s) == 2:
|
||||||
host, fdroiddir = s
|
host, fdroiddir = s
|
||||||
else:
|
else:
|
||||||
logging.error('Malformed serverwebroot line: ' + serverwebroot)
|
logging.error(_('Malformed serverwebroot line:') + ' ' + serverwebroot)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
repobase = os.path.basename(fdroiddir)
|
repobase = os.path.basename(fdroiddir)
|
||||||
if standardwebroot and repobase != 'fdroid':
|
if standardwebroot and repobase != 'fdroid':
|
||||||
@ -624,7 +625,7 @@ def main():
|
|||||||
if local_copy_dir is not None:
|
if local_copy_dir is not None:
|
||||||
fdroiddir = local_copy_dir.rstrip('/')
|
fdroiddir = local_copy_dir.rstrip('/')
|
||||||
if os.path.exists(fdroiddir) and not os.path.isdir(fdroiddir):
|
if os.path.exists(fdroiddir) and not os.path.isdir(fdroiddir):
|
||||||
logging.error('local_copy_dir must be directory, not a file!')
|
logging.error(_('local_copy_dir must be directory, not a file!'))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if not os.path.exists(os.path.dirname(fdroiddir)):
|
if not os.path.exists(os.path.dirname(fdroiddir)):
|
||||||
logging.error('The root dir for local_copy_dir "'
|
logging.error('The root dir for local_copy_dir "'
|
||||||
@ -632,7 +633,7 @@ def main():
|
|||||||
+ '" does not exist!')
|
+ '" does not exist!')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if not os.path.isabs(fdroiddir):
|
if not os.path.isabs(fdroiddir):
|
||||||
logging.error('local_copy_dir must be an absolute path!')
|
logging.error(_('local_copy_dir must be an absolute path!'))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
repobase = os.path.basename(fdroiddir)
|
repobase = os.path.basename(fdroiddir)
|
||||||
if standardwebroot and repobase != 'fdroid':
|
if standardwebroot and repobase != 'fdroid':
|
||||||
@ -652,8 +653,8 @@ def main():
|
|||||||
and not config.get('binary_transparency_remote') \
|
and not config.get('binary_transparency_remote') \
|
||||||
and not config.get('virustotal_apikey') \
|
and not config.get('virustotal_apikey') \
|
||||||
and local_copy_dir is None:
|
and local_copy_dir is None:
|
||||||
logging.warn('No option set! Edit your config.py to set at least one among:\n'
|
logging.warn(_('No option set! Edit your config.py to set at least one of these:')
|
||||||
+ 'serverwebroot, servergitmirrors, local_copy_dir, awsbucket, virustotal_apikey, androidobservatory, or binary_transparency_remote')
|
+ '\nserverwebroot, servergitmirrors, local_copy_dir, awsbucket, virustotal_apikey, androidobservatory, or binary_transparency_remote')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
repo_sections = ['repo']
|
repo_sections = ['repo']
|
||||||
|
@ -22,6 +22,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import net
|
from . import net
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
@ -52,7 +53,7 @@ def extract(config, options):
|
|||||||
os.mkdir(tmp_dir)
|
os.mkdir(tmp_dir)
|
||||||
|
|
||||||
if not options.APK or len(options.APK) <= 0:
|
if not options.APK or len(options.APK) <= 0:
|
||||||
logging.critical('no APK supplied')
|
logging.critical(_('no APK supplied'))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# iterate over supplied APKs downlaod and extract them...
|
# iterate over supplied APKs downlaod and extract them...
|
||||||
@ -61,21 +62,21 @@ def extract(config, options):
|
|||||||
try:
|
try:
|
||||||
if os.path.isfile(apk):
|
if os.path.isfile(apk):
|
||||||
sigdir = extract_signature(apk)
|
sigdir = extract_signature(apk)
|
||||||
logging.info('fetched singatures for %s -> %s', apk, sigdir)
|
logging.info(_('fetched signatures for %s -> %s'), apk, sigdir)
|
||||||
elif httpre.match(apk):
|
elif httpre.match(apk):
|
||||||
if apk.startswith('https') or options.no_check_https:
|
if apk.startswith('https') or options.no_check_https:
|
||||||
try:
|
try:
|
||||||
tmp_apk = os.path.join(tmp_dir, 'signed.apk')
|
tmp_apk = os.path.join(tmp_dir, 'signed.apk')
|
||||||
net.download_file(apk, tmp_apk)
|
net.download_file(apk, tmp_apk)
|
||||||
sigdir = extract_signature(tmp_apk)
|
sigdir = extract_signature(tmp_apk)
|
||||||
logging.info('fetched singatures for %s -> %s', apk, sigdir)
|
logging.info(_('fetched signatures for %s -> %s'), apk, sigdir)
|
||||||
finally:
|
finally:
|
||||||
if tmp_apk and os.path.exists(tmp_apk):
|
if tmp_apk and os.path.exists(tmp_apk):
|
||||||
os.remove(tmp_apk)
|
os.remove(tmp_apk)
|
||||||
else:
|
else:
|
||||||
logging.warn('refuse downloading via insecure http connection (use https or specify --no-https-check): %s', apk)
|
logging.warn(_('refuse downloading via insecure http connection (use https or specify --no-https-check): %s'), apk)
|
||||||
except FDroidException as e:
|
except FDroidException as e:
|
||||||
logging.warning("failed fetching signatures for '%s': %s", apk, e)
|
logging.warning(_("failed fetching signatures for '%s': %s"), apk, e)
|
||||||
if e.detail:
|
if e.detail:
|
||||||
logging.debug(e.detail)
|
logging.debug(e.detail)
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ def main():
|
|||||||
parser = ArgumentParser(usage="%(prog)s [options] APK [APK...]")
|
parser = ArgumentParser(usage="%(prog)s [options] APK [APK...]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("APK", nargs='*',
|
parser.add_argument("APK", nargs='*',
|
||||||
help="signed APK, either a file-path or Https-URL are fine here.")
|
help=_("signed APK, either a file-path or HTTPS URL."))
|
||||||
parser.add_argument("--no-check-https", action="store_true", default=False)
|
parser.add_argument("--no-check-https", action="store_true", default=False)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import zipfile
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ def main():
|
|||||||
|
|
||||||
if 'jarsigner' not in config:
|
if 'jarsigner' not in config:
|
||||||
raise FDroidException(
|
raise FDroidException(
|
||||||
'Java jarsigner not found! Install in standard location or set java_paths!')
|
_('Java jarsigner not found! Install in standard location or set java_paths!'))
|
||||||
|
|
||||||
repodirs = ['repo']
|
repodirs = ['repo']
|
||||||
if config['archive_older'] != 0:
|
if config['archive_older'] != 0:
|
||||||
@ -114,7 +115,7 @@ def main():
|
|||||||
signed += 1
|
signed += 1
|
||||||
|
|
||||||
if signed == 0:
|
if signed == 0:
|
||||||
logging.info("Nothing to do")
|
logging.info(_("Nothing to do"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -30,6 +30,7 @@ import logging
|
|||||||
import subprocess
|
import subprocess
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import metadata
|
from . import metadata
|
||||||
|
|
||||||
@ -61,12 +62,12 @@ def main():
|
|||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("-d", "--download", action="store_true", default=False,
|
parser.add_argument("-d", "--download", action="store_true", default=False,
|
||||||
help="Download logs we don't have")
|
help=_("Download logs we don't have"))
|
||||||
parser.add_argument("--recalc", action="store_true", default=False,
|
parser.add_argument("--recalc", action="store_true", default=False,
|
||||||
help="Recalculate aggregate stats - use when changes "
|
help=_("Recalculate aggregate stats - use when changes "
|
||||||
"have been made that would invalidate old cached data.")
|
"have been made that would invalidate old cached data."))
|
||||||
parser.add_argument("--nologs", action="store_true", default=False,
|
parser.add_argument("--nologs", action="store_true", default=False,
|
||||||
help="Don't do anything logs-related")
|
help=_("Don't do anything logs-related"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -171,10 +172,10 @@ def main():
|
|||||||
uri = match.group('uri')
|
uri = match.group('uri')
|
||||||
if not uri.endswith('.apk'):
|
if not uri.endswith('.apk'):
|
||||||
continue
|
continue
|
||||||
_, apkname = os.path.split(uri)
|
_ignored, apkname = os.path.split(uri)
|
||||||
app = knownapks.getapp(apkname)
|
app = knownapks.getapp(apkname)
|
||||||
if app:
|
if app:
|
||||||
appid, _ = app
|
appid, _ignored = app
|
||||||
today['apps'][appid] += 1
|
today['apps'][appid] += 1
|
||||||
# Strip the '.apk' from apkname
|
# Strip the '.apk' from apkname
|
||||||
appver = apkname[:-4]
|
appver = apkname[:-4]
|
||||||
@ -298,7 +299,7 @@ def main():
|
|||||||
for apk in unknownapks:
|
for apk in unknownapks:
|
||||||
logging.info(apk)
|
logging.info(apk)
|
||||||
|
|
||||||
logging.info("Finished.")
|
logging.info(_("Finished"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -37,6 +37,7 @@ from binascii import hexlify
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import index
|
from . import index
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@ -1697,34 +1698,34 @@ def main():
|
|||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("--create-key", action="store_true", default=False,
|
parser.add_argument("--create-key", action="store_true", default=False,
|
||||||
help="Create a repo signing key in a keystore")
|
help=_("Create a repo signing key in a keystore"))
|
||||||
parser.add_argument("-c", "--create-metadata", action="store_true", default=False,
|
parser.add_argument("-c", "--create-metadata", action="store_true", default=False,
|
||||||
help="Create skeleton metadata files that are missing")
|
help=_("Create skeleton metadata files that are missing"))
|
||||||
parser.add_argument("--delete-unknown", action="store_true", default=False,
|
parser.add_argument("--delete-unknown", action="store_true", default=False,
|
||||||
help="Delete APKs and/or OBBs without metadata from the repo")
|
help=_("Delete APKs and/or OBBs without metadata from the repo"))
|
||||||
parser.add_argument("-b", "--buildreport", action="store_true", default=False,
|
parser.add_argument("-b", "--buildreport", action="store_true", default=False,
|
||||||
help="Report on build data status")
|
help=_("Report on build data status"))
|
||||||
parser.add_argument("-i", "--interactive", default=False, action="store_true",
|
parser.add_argument("-i", "--interactive", default=False, action="store_true",
|
||||||
help="Interactively ask about things that need updating.")
|
help=_("Interactively ask about things that need updating."))
|
||||||
parser.add_argument("-I", "--icons", action="store_true", default=False,
|
parser.add_argument("-I", "--icons", action="store_true", default=False,
|
||||||
help="Resize all the icons exceeding the max pixel size and exit")
|
help=_("Resize all the icons exceeding the max pixel size and exit"))
|
||||||
parser.add_argument("-e", "--editor", default="/etc/alternatives/editor",
|
parser.add_argument("-e", "--editor", default="/etc/alternatives/editor",
|
||||||
help="Specify editor to use in interactive mode. Default " +
|
help=_("Specify editor to use in interactive mode. Default ") +
|
||||||
"is /etc/alternatives/editor")
|
"is /etc/alternatives/editor")
|
||||||
parser.add_argument("-w", "--wiki", default=False, action="store_true",
|
parser.add_argument("-w", "--wiki", default=False, action="store_true",
|
||||||
help="Update the wiki")
|
help=_("Update the wiki"))
|
||||||
parser.add_argument("--pretty", action="store_true", default=False,
|
parser.add_argument("--pretty", action="store_true", default=False,
|
||||||
help="Produce human-readable index.xml")
|
help=_("Produce human-readable index.xml"))
|
||||||
parser.add_argument("--clean", action="store_true", default=False,
|
parser.add_argument("--clean", action="store_true", default=False,
|
||||||
help="Clean update - don't uses caches, reprocess all apks")
|
help=_("Clean update - don't uses caches, reprocess all apks"))
|
||||||
parser.add_argument("--nosign", action="store_true", default=False,
|
parser.add_argument("--nosign", action="store_true", default=False,
|
||||||
help="When configured for signed indexes, create only unsigned indexes at this stage")
|
help=_("When configured for signed indexes, create only unsigned indexes at this stage"))
|
||||||
parser.add_argument("--use-date-from-apk", action="store_true", default=False,
|
parser.add_argument("--use-date-from-apk", action="store_true", default=False,
|
||||||
help="Use date from apk instead of current time for newly added apks")
|
help=_("Use date from apk instead of current time for newly added apks"))
|
||||||
parser.add_argument("--rename-apks", action="store_true", default=False,
|
parser.add_argument("--rename-apks", action="store_true", default=False,
|
||||||
help="Rename APK files that do not match package.name_123.apk")
|
help=_("Rename APK files that do not match package.name_123.apk"))
|
||||||
parser.add_argument("--allow-disabled-algorithms", action="store_true", default=False,
|
parser.add_argument("--allow-disabled-algorithms", action="store_true", default=False,
|
||||||
help="Include APKs that are signed with disabled algorithms like MD5")
|
help=_("Include APKs that are signed with disabled algorithms like MD5"))
|
||||||
metadata.add_metadata_arguments(parser)
|
metadata.add_metadata_arguments(parser)
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
metadata.warnings_action = options.W
|
metadata.warnings_action = options.W
|
||||||
@ -1899,7 +1900,7 @@ def main():
|
|||||||
if options.wiki:
|
if options.wiki:
|
||||||
update_wiki(apps, sortedids, apks + archapks)
|
update_wiki(apps, sortedids, apks + archapks)
|
||||||
|
|
||||||
logging.info("Finished.")
|
logging.info(_("Finished"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -23,6 +23,7 @@ import requests
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from . import _
|
||||||
from . import common
|
from . import common
|
||||||
from . import net
|
from . import net
|
||||||
from .exception import FDroidException
|
from .exception import FDroidException
|
||||||
@ -38,19 +39,19 @@ def main():
|
|||||||
# Parse command line...
|
# Parse command line...
|
||||||
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
parser = ArgumentParser(usage="%(prog)s [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
|
||||||
common.setup_global_opts(parser)
|
common.setup_global_opts(parser)
|
||||||
parser.add_argument("appid", nargs='*', help="app-id with optional versionCode in the form APPID[:VERCODE]")
|
parser.add_argument("appid", nargs='*', help=_("applicationId with optional versionCode in the form APPID[:VERCODE]"))
|
||||||
options = parser.parse_args()
|
options = parser.parse_args()
|
||||||
|
|
||||||
config = common.read_config(options)
|
config = common.read_config(options)
|
||||||
|
|
||||||
tmp_dir = 'tmp'
|
tmp_dir = 'tmp'
|
||||||
if not os.path.isdir(tmp_dir):
|
if not os.path.isdir(tmp_dir):
|
||||||
logging.info("Creating temporary directory")
|
logging.info(_("Creating temporary directory"))
|
||||||
os.makedirs(tmp_dir)
|
os.makedirs(tmp_dir)
|
||||||
|
|
||||||
unsigned_dir = 'unsigned'
|
unsigned_dir = 'unsigned'
|
||||||
if not os.path.isdir(unsigned_dir):
|
if not os.path.isdir(unsigned_dir):
|
||||||
logging.error("No unsigned directory - nothing to do")
|
logging.error(_("No unsigned directory - nothing to do"))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
verified = 0
|
verified = 0
|
||||||
@ -83,7 +84,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
net.download_file(url.replace('/repo', '/archive'), dldir=tmp_dir)
|
net.download_file(url.replace('/repo', '/archive'), dldir=tmp_dir)
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
raise FDroidException('Downloading %s failed. %s', (url, e))
|
raise FDroidException(_('Downloading %s failed. %s'), (url, e))
|
||||||
|
|
||||||
compare_result = common.verify_apks(
|
compare_result = common.verify_apks(
|
||||||
remoteapk,
|
remoteapk,
|
||||||
@ -99,7 +100,7 @@ def main():
|
|||||||
logging.info("...NOT verified - {0}".format(e))
|
logging.info("...NOT verified - {0}".format(e))
|
||||||
notverified += 1
|
notverified += 1
|
||||||
|
|
||||||
logging.info("Finished")
|
logging.info(_("Finished"))
|
||||||
logging.info("{0} successfully verified".format(verified))
|
logging.info("{0} successfully verified".format(verified))
|
||||||
logging.info("{0} NOT verified".format(notverified))
|
logging.info("{0} NOT verified".format(notverified))
|
||||||
|
|
||||||
|
2
setup.py
2
setup.py
@ -17,6 +17,7 @@ setup(name='fdroidserver',
|
|||||||
author='The F-Droid Project',
|
author='The F-Droid Project',
|
||||||
author_email='team@f-droid.org',
|
author_email='team@f-droid.org',
|
||||||
url='https://f-droid.org',
|
url='https://f-droid.org',
|
||||||
|
license='AGPL-3.0',
|
||||||
packages=['fdroidserver', 'fdroidserver.asynchronousfilereader'],
|
packages=['fdroidserver', 'fdroidserver.asynchronousfilereader'],
|
||||||
scripts=['fdroid', 'fd-commit', 'makebuildserver'],
|
scripts=['fdroid', 'fd-commit', 'makebuildserver'],
|
||||||
data_files=[
|
data_files=[
|
||||||
@ -29,6 +30,7 @@ setup(name='fdroidserver',
|
|||||||
'examples/public-read-only-s3-bucket-policy.json',
|
'examples/public-read-only-s3-bucket-policy.json',
|
||||||
'examples/template.yml']),
|
'examples/template.yml']),
|
||||||
],
|
],
|
||||||
|
python_requires='>=3.4',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'clint',
|
'clint',
|
||||||
'GitPython',
|
'GitPython',
|
||||||
|
@ -8,11 +8,13 @@ import logging
|
|||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
import yaml
|
import yaml
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
localmodule = os.path.realpath(
|
localmodule = os.path.realpath(
|
||||||
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
|
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
|
||||||
@ -397,8 +399,15 @@ class UpdateTest(unittest.TestCase):
|
|||||||
self.assertFalse(os.path.exists(os.path.join('archive', apkName)))
|
self.assertFalse(os.path.exists(os.path.join('archive', apkName)))
|
||||||
self.assertTrue(os.path.exists(os.path.join('repo', apkName)))
|
self.assertTrue(os.path.exists(os.path.join('repo', apkName)))
|
||||||
|
|
||||||
|
javac = config['jarsigner'].replace('jarsigner', 'javac')
|
||||||
|
v = subprocess.check_output([javac, '-version'], stderr=subprocess.STDOUT)[6:-1].decode('utf-8')
|
||||||
|
if LooseVersion(v) < LooseVersion('1.8.0_132'):
|
||||||
|
print('SKIPPING: running tests with old Java (' + v + ')')
|
||||||
|
return
|
||||||
|
|
||||||
# this test only works on systems with fully updated Java/jarsigner
|
# this test only works on systems with fully updated Java/jarsigner
|
||||||
# that has MD5 listed in jdk.jar.disabledAlgorithms in java.security
|
# that has MD5 listed in jdk.jar.disabledAlgorithms in java.security
|
||||||
|
# https://blogs.oracle.com/java-platform-group/oracle-jre-will-no-longer-trust-md5-signed-code-by-default
|
||||||
skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
|
skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
|
||||||
knownapks,
|
knownapks,
|
||||||
allow_disabled_algorithms=False,
|
allow_disabled_algorithms=False,
|
||||||
|
Loading…
Reference in New Issue
Block a user