import logging
import requests
import shutil
-import sys
import tempfile
import xml.dom.minidom
import zipfile
from argparse import ArgumentParser
+from .exception import FDroidException
from . import common
from . import server
logging.getLogger("urllib3").setLevel(logging.WARNING)
if not os.path.exists(options.git_repo):
- logging.error('"' + options.git_repo + '/" does not exist! Create it, or use --git-repo')
- sys.exit(1)
+ raise FDroidException(
+ '"%s" does not exist! Create it, or use --git-repo' % options.git_repo)
session = requests.Session()
from . import net
from . import metadata
from . import scanner
-from .common import FDroidException, BuildException, VCSException, FDroidPopen, SdkToolsPopen
+from .common import FDroidPopen, SdkToolsPopen
+from .exception import FDroidException, BuildException, VCSException
try:
import paramiko
if k.endswith("_orig"):
continue
logging.critical(" %s: %s" % (k, v))
- sys.exit(3)
+ raise FDroidException()
elif not os.path.isdir(ndk_path):
logging.critical("Android NDK '%s' is not a directory!" % ndk_path)
- sys.exit(3)
+ raise FDroidException()
common.set_FDroidPopen_env(build)
try:
net.download_file(url, local_filename=of)
except requests.exceptions.HTTPError as e:
- raise FDroidException('downloading Binaries from %s failed' % url) from e
+ raise FDroidException(
+ 'Downloading Binaries from %s failed. %s' % (url, e))
# Now we check weather the build can be verified to
# match the supplied binary or not. Should the
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import sys
import os
import re
import urllib.request
from . import common
from . import metadata
-from .common import VCSException, FDroidException
-from .metadata import MetaDataException
+from .exception import VCSException, FDroidException, MetaDataException
# Check for a new version by looking at a document retrieved via HTTP.
gitcmd.extend(['--author', config['auto_author']])
gitcmd.extend(["--", metadatapath])
if subprocess.call(gitcmd) != 0:
- logging.error("Git commit failed")
- sys.exit(1)
+ raise FDroidException("Git commit failed")
config = None
from distutils.util import strtobool
import fdroidserver.metadata
+from fdroidserver.exception import FDroidException, VCSException, BuildException
from .asynchronousfilereader import AsynchronousFileReader
code = compile(f.read(), config_file, 'exec')
exec(code, None, config)
elif len(get_local_metadata_files()) == 0:
- logging.critical("Missing config file - is this a repo directory?")
- sys.exit(2)
+ raise FDroidException("Missing config file - is this a repo directory?")
for k in ('mirrors', 'install_list', 'uninstall_list', 'serverwebroot', 'servergitroot'):
if k in config:
def ensure_build_tools_exists(thisconfig):
if not test_sdk_exists(thisconfig):
- sys.exit(3)
+ raise FDroidException("Android SDK not found.")
build_tools = os.path.join(thisconfig['sdk_path'], 'build-tools')
versioned_build_tools = os.path.join(build_tools, thisconfig['build_tools'])
if not os.path.isdir(versioned_build_tools):
- logging.critical('Android Build Tools path "'
- + versioned_build_tools + '" does not exist!')
- sys.exit(3)
+ raise FDroidException(
+ 'Android Build Tools path "' + versioned_build_tools + '" does not exist!')
def get_local_metadata_files():
return re.match("[A-Za-z_][A-Za-z_0-9.]+$", name)
-class FDroidException(Exception):
-
- def __init__(self, value, detail=None):
- self.value = value
- self.detail = detail
-
- def shortened_detail(self):
- if len(self.detail) < 16000:
- return self.detail
- return '[...]\n' + self.detail[-16000:]
-
- def get_wikitext(self):
- ret = repr(self.value) + "\n"
- if self.detail:
- ret += "=detail=\n"
- ret += "<pre>\n" + self.shortened_detail() + "</pre>\n"
- return ret
-
- def __str__(self):
- ret = self.value
- if self.detail:
- ret += "\n==== detail begin ====\n%s\n==== detail end ====" % self.detail.strip()
- return ret
-
-
-class VCSException(FDroidException):
- pass
-
-
-class BuildException(FDroidException):
- pass
-
-
# Get the specified source library.
# Returns the path to it. Normally this is the path to be used when referencing
# it, which may be a subdirectory of the actual project. If you want the base
p = SdkToolsPopen(['aapt', 'dump', 'xmltree', apkfile, 'AndroidManifest.xml'],
output=False)
if p.returncode != 0:
- logging.critical("Failed to get apk manifest information")
- sys.exit(1)
+ raise FDroidException("Failed to get apk manifest information")
for line in p.output.splitlines():
if 'android:debuggable' in line and not line.endswith('0x0'):
return True
try:
from androguard.core.bytecodes.apk import APK
except ImportError:
- logging.critical("androguard library is not installed and aapt not present")
- sys.exit(1)
+ raise FDroidException("androguard library is not installed and aapt not present")
apkobject = APK(apkfile)
if apkobject.is_valid_APK():
config[cmd] = find_sdk_tools_cmd(commands[0])
abscmd = config[cmd]
if abscmd is None:
- logging.critical("Could not find '%s' on your system" % cmd)
- sys.exit(1)
+ raise FDroidException("Could not find '%s' on your system" % cmd)
if cmd == 'aapt':
test_aapt_version(config['aapt'])
return FDroidPopen([abscmd] + commands[1:],
--- /dev/null
+class FDroidException(Exception):
+
+ def __init__(self, value=None, detail=None):
+ self.value = value
+ self.detail = detail
+
+ def shortened_detail(self):
+ if len(self.detail) < 16000:
+ return self.detail
+ return '[...]\n' + self.detail[-16000:]
+
+ def get_wikitext(self):
+ ret = repr(self.value) + "\n"
+ if self.detail:
+ ret += "=detail=\n"
+ ret += "<pre>\n" + self.shortened_detail() + "</pre>\n"
+ return ret
+
+ def __str__(self):
+ ret = self.value
+ if self.detail:
+ ret += "\n==== detail begin ====\n%s\n==== detail end ====" % self.detail.strip()
+ return ret
+
+
+class MetaDataException(Exception):
+
+ def __init__(self, value):
+ self.value = value
+
+ def __str__(self):
+ return self.value
+
+
+class VCSException(FDroidException):
+ pass
+
+
+class BuildException(FDroidException):
+ pass
+
+
+class VerificationException(FDroidException):
+ pass
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import sys
import os
import glob
from argparse import ArgumentParser
from . import common
from .common import FDroidPopen
+from .exception import FDroidException
config = None
options = None
for output_dir in repodirs:
if not os.path.isdir(output_dir):
- logging.error("Missing output directory '" + output_dir + "'")
- sys.exit(1)
+ raise FDroidException("Missing output directory '" + output_dir + "'")
# Process any apks that are waiting to be signed...
for f in sorted(glob.glob(os.path.join(output_dir, '*.*'))):
gpgargs.append(os.path.join(output_dir, filename))
p = FDroidPopen(gpgargs)
if p.returncode != 0:
- logging.error("Signing failed.")
- sys.exit(1)
+ raise FDroidException("Signing failed.")
logging.info('Signed ' + filename)
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import binascii
-import sys
import os
import shutil
import urllib.request
from . import common
from . import metadata
+from .exception import FDroidException
# Get the repo type and address from the given web page. The page is scanned
# Figure out the repo type and adddress...
repotype, repo = getrepofrompage(app.SourceCode)
if not repotype:
- logging.error("Unable to determine vcs type. " + repo)
- sys.exit(1)
+ raise FDroidException("Unable to determine vcs type. " + repo)
elif url.startswith('https://') and url.endswith('.git'):
projecttype = 'git'
repo = url
app.SourceCode = ""
app.WebSite = ""
if not projecttype:
- logging.error("Unable to determine the project type.")
- logging.error("The URL you supplied was not in one of the supported formats. Please consult")
- logging.error("the manual for a list of supported formats, and supply one of those.")
- sys.exit(1)
+ raise FDroidException("Unable to determine the project type. " +
+ "The URL you supplied was not in one of the supported formats. " +
+ "Please consult the manual for a list of supported formats, " +
+ "and supply one of those.")
# Ensure we have a sensible-looking repo address at this point. If not, we
# might have got a page format we weren't expecting. (Note that we
not repo.startswith('https://') and
not repo.startswith('git://'))) or
' ' in repo):
- logging.error("Repo address '{0}' does not seem to be valid".format(repo))
- sys.exit(1)
+ raise FDroidException("Repo address '{0}' does not seem to be valid".format(repo))
# Get a copy of the source so we can extract some info...
logging.info('Getting source from ' + repotype + ' repo at ' + repo)
local_metadata_files = common.get_local_metadata_files()
if local_metadata_files != []:
- logging.error("This repo already has local metadata: %s" % local_metadata_files[0])
- sys.exit(1)
+ raise FDroidException("This repo already has local metadata: %s" % local_metadata_files[0])
if options.url is None and os.path.isdir('.git'):
app.AutoName = os.path.basename(os.getcwd())
build.disable = 'Generated by import.py - check/set version fields and commit id'
write_local_file = False
else:
- logging.error("Specify project url.")
- sys.exit(1)
+ raise FDroidException("Specify project url.")
# Extract some information...
paths = common.manifest_paths(root_dir, [])
versionName, versionCode, package = common.parse_androidmanifests(paths, app)
if not package:
- logging.error("Couldn't find package ID")
- sys.exit(1)
+ raise FDroidException("Couldn't find package ID")
if not versionName:
logging.warn("Couldn't find latest version name")
if not versionCode:
versionName = bconfig.get('app', 'version')
versionCode = None
else:
- logging.error("No android or kivy project could be found. Specify --subdir?")
- sys.exit(1)
+ raise FDroidException("No android or kivy project could be found. Specify --subdir?")
# Make sure it's actually new...
if package in apps:
- logging.error("Package " + package + " already exists")
- sys.exit(1)
+ raise FDroidException("Package " + package + " already exists")
# Create a build line...
build.versionName = versionName or '?'
import os
import re
import shutil
-import sys
import tempfile
import urllib.parse
import zipfile
from fdroidserver import metadata, signindex, common, net
from fdroidserver.common import FDroidPopen, FDroidPopenBytes
-from fdroidserver.metadata import MetaDataException
+from fdroidserver.exception import FDroidException, VerificationException, MetaDataException
def make(apps, sortedids, apks, repodir, archive):
nosigningkey = True
logging.critical("'" + common.config['keystore'] + "' does not exist!")
if nosigningkey:
- logging.warning("`fdroid update` requires a signing key, you can create one using:")
- logging.warning("\tfdroid update --create-key")
- sys.exit(1)
+ raise FDroidException("`fdroid update` requires a signing key, " +
+ "you can create one using: fdroid update --create-key")
repodict = collections.OrderedDict()
repodict['timestamp'] = datetime.utcnow()
if mirror is not None:
mirrors.append(mirror + '/')
if mirrorcheckfailed:
- sys.exit(1)
+ raise FDroidException("Malformed repository mirrors.")
if mirrors:
repodict['mirrors'] = mirrors
# Check for duplicates - they will make the client unhappy...
for i in range(len(apklist) - 1):
if apklist[i]['versionCode'] == apklist[i + 1]['versionCode']:
- logging.critical("duplicate versions: '%s' - '%s'" % (
+ raise FDroidException("duplicate versions: '%s' - '%s'" % (
apklist[i]['apkName'], apklist[i + 1]['apkName']))
- sys.exit(1)
current_version_code = 0
current_version_file = None
jar_output = 'index_unsigned.jar' if common.options.nosign else 'index.jar'
p = FDroidPopen(['jar', 'cf', jar_output, 'index.xml'], cwd=repodir)
if p.returncode != 0:
- logging.critical("Failed to create {0}".format(jar_output))
- sys.exit(1)
+ raise FDroidException("Failed to create {0}".format(jar_output))
# Sign the index...
signed = os.path.join(repodir, 'index.jar')
msg = "Failed to get repo pubkey!"
if common.config['keystore'] == 'NONE':
msg += ' Is your crypto smartcard plugged in?'
- logging.critical(msg)
- sys.exit(1)
+ raise FDroidException(msg)
pubkey = p.output
repo_pubkey_fingerprint = common.get_cert_fingerprint(pubkey)
return hexlify(pubkey), repo_pubkey_fingerprint
return '/'.join(segments)
-class VerificationException(Exception):
- pass
-
-
def download_repo_index(url_str, etag=None, verify_fingerprint=True):
"""
Downloads the repository index from the given :param url_str
import logging
from . import common
+from .exception import FDroidException
config = {}
options = None
if common.test_sdk_exists(test_config):
break
if not common.test_sdk_exists(test_config):
- sys.exit(3)
+ raise FDroidException("Android SDK not found.")
if not os.path.exists('config.py'):
# 'metadata' and 'tmp' are created in fdroid
else:
logging.warn('Looks like this is already an F-Droid repo, cowardly refusing to overwrite it...')
logging.info('Try running `fdroid init` in an empty directory.')
- sys.exit()
+ raise FDroidException('Repository already exists.')
if 'aapt' not in test_config or not os.path.isfile(test_config['aapt']):
# try to find a working aapt, in all the recent possible paths
import logging
from . import common
-from .common import SdkToolsPopen, FDroidException
+from .common import SdkToolsPopen
+from .exception import FDroidException
options = None
config = None
YamlLoader = Loader
import fdroidserver.common
+from fdroidserver.exception import MetaDataException
srclibs = None
warnings_action = None
-class MetaDataException(Exception):
-
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return self.value
-
-
def warn_or_exception(value):
'''output warning or Exception depending on -W'''
if warnings_action == 'ignore':
from . import common
from . import metadata
-from .common import FDroidPopen, SdkToolsPopen, BuildException
+from .common import FDroidPopen, SdkToolsPopen
+from .exception import BuildException
config = None
options = None
from . import common
from . import metadata
-from .common import BuildException, VCSException
+from .exception import BuildException, VCSException
config = None
options = None
import shutil
from . import common
+from .exception import FDroidException
config = None
options = None
'--exclude', indexjar,
'--exclude', indexv1jar,
repo_section, s3url]) != 0:
- sys.exit(1)
+ raise FDroidException()
logging.debug('s3cmd sync all files in ' + repo_section + ' to ' + s3url)
if subprocess.call(s3cmdargs +
['--no-check-md5',
'--exclude', indexjar,
'--exclude', indexv1jar,
repo_section, s3url]) != 0:
- sys.exit(1)
+ raise FDroidException()
logging.debug('s3cmd sync indexes ' + repo_section + ' to ' + s3url + ' and delete')
s3cmdargs.append('--delete-removed')
else:
s3cmdargs.append('--check-md5')
if subprocess.call(s3cmdargs + [repo_section, s3url]) != 0:
- sys.exit(1)
+ raise FDroidException()
def update_awsbucket_libcloud(repo_section):
from libcloud.storage.providers import get_driver
if not config.get('awsaccesskeyid') or not config.get('awssecretkey'):
- logging.error('To use awsbucket, you must set awssecretkey and awsaccesskeyid in config.py!')
- sys.exit(1)
+ raise FDroidException(
+ 'To use awsbucket, you must set awssecretkey and awsaccesskeyid in config.py!')
awsbucket = config['awsbucket']
cls = get_driver(Provider.S3)
['--exclude', indexxml, '--exclude', indexjar,
'--exclude', indexv1jar,
repo_section, serverwebroot]) != 0:
- sys.exit(1)
+ raise FDroidException()
if subprocess.call(rsyncargs + [repo_section, serverwebroot]) != 0:
- sys.exit(1)
+ raise FDroidException()
# upload "current version" symlinks if requested
if config['make_current_version_link'] and repo_section == 'repo':
links_to_upload = []
links_to_upload.append(f)
if len(links_to_upload) > 0:
if subprocess.call(rsyncargs + links_to_upload + [serverwebroot]) != 0:
- sys.exit(1)
+ raise FDroidException()
def _local_sync(fromdir, todir):
rsyncargs += ['--quiet']
logging.debug(' '.join(rsyncargs + [fromdir, todir]))
if subprocess.call(rsyncargs + [fromdir, todir]) != 0:
- sys.exit(1)
+ raise FDroidException()
def sync_from_localcopy(repo_section, local_copy_dir):
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import sys
import os
import zipfile
from argparse import ArgumentParser
import logging
from . import common
+from .exception import FDroidException
config = None
options = None
}
p = common.FDroidPopen(args, envs=env_vars)
if p.returncode != 0:
- logging.critical("Failed to sign %s!" % jar)
- sys.exit(1)
+ raise FDroidException("Failed to sign %s!" % jar)
def sign_index_v1(repodir, json_name):
config = common.read_config(options)
if 'jarsigner' not in config:
- logging.critical('Java jarsigner not found! Install in standard location or set java_paths!')
- sys.exit(1)
+ raise FDroidException(
+ 'Java jarsigner not found! Install in standard location or set java_paths!')
repodirs = ['repo']
if config['archive_older'] != 0:
signed = 0
for output_dir in repodirs:
if not os.path.isdir(output_dir):
- logging.error("Missing output directory '" + output_dir + "'")
- sys.exit(1)
+ raise FDroidException("Missing output directory '" + output_dir + "'")
unsigned = os.path.join(output_dir, 'index_unsigned.jar')
if os.path.exists(unsigned):
from . import common
from . import index
from . import metadata
-from .common import BuildException, SdkToolsPopen
+from .common import SdkToolsPopen
+from .exception import BuildException, FDroidException
METADATA_VERSION = 18
continue
stat = os.stat(filename)
if stat.st_size == 0:
- logging.error(filename + ' is zero size!')
- sys.exit(1)
+ raise FDroidException(filename + ' is zero size!')
shasum = sha256sum(filename)
usecache = False
logging.error("Could not find {0} to remove it".format(apkfile))
else:
logging.error("Failed to get apk information, skipping " + apkfile)
- raise BuildException("Invaild APK")
+ raise BuildException("Invalid APK")
for line in p.output.splitlines():
if line.startswith("package:"):
try:
apk['versionCode'] = int(re.match(APK_VERCODE_PAT, line).group(1))
apk['versionName'] = re.match(APK_VERNAME_PAT, line).group(1)
except Exception as e:
- logging.error("Package matching failed: " + str(e))
- logging.info("Line was: " + line)
- sys.exit(1)
+ raise FDroidException("Package matching failed: " + str(e) + "\nLine was: " + line)
elif line.startswith("application:"):
apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
# Keep path to non-dpi icon in case we need it
logging.error("Failed to get apk information, skipping " + apkfile)
raise BuildException("Invaild APK")
except ImportError:
- logging.critical("androguard library is not installed and aapt not present")
- sys.exit(1)
+ raise FDroidException("androguard library is not installed and aapt not present")
except FileNotFoundError:
logging.error("Could not open apk file for analysis")
- raise BuildException("Invaild APK")
+ raise BuildException("Invalid APK")
apk['packageName'] = apkobject.get_package()
apk['versionCode'] = int(apkobject.get_androidversion_code())
config = common.read_config(options)
if not ('jarsigner' in config and 'keytool' in config):
- logging.critical('Java JDK not found! Install in standard location or set java_paths!')
- sys.exit(1)
+ raise FDroidException('Java JDK not found! Install in standard location or set java_paths!')
repodirs = ['repo']
if config['archive_older'] != 0:
from . import common
from . import net
-from .common import FDroidException
+from .exception import FDroidException
options = None
config = None
try:
net.download_file(url, dldir=tmp_dir)
except requests.exceptions.HTTPError as e:
- raise FDroidException('downloading %s failed', url) from e
+ raise FDroidException('Downloading %s failed. %s', (url, e))
compare_result = common.verify_apks(
remoteapk,