def devices(): p = FDroidPopen([config['adb'], "devices"]) if p.returncode != 0: raise FDroidException("An error occured when finding devices: %s" % p.output) lines = p.output.splitlines() if lines[0].startswith('* daemon not running'): lines = lines[2:] if len(lines) < 3: return [] lines = lines[1:-1] return [l.split()[0] for l in lines]
def check_http(app): try: if 'Update Check Data' not in app: raise FDroidException('Missing Update Check Data') urlcode, codeex, urlver, verex = app['Update Check Data'].split('|') vercode = "99999999" if len(urlcode) > 0: logging.debug("...requesting {0}".format(urlcode)) req = urllib2.Request(urlcode, None) resp = urllib2.urlopen(req, None, 20) page = resp.read() m = re.search(codeex, page) if not m: raise FDroidException("No RE match for version code") vercode = m.group(1) version = "??" if len(urlver) > 0: if urlver != '.': logging.debug("...requesting {0}".format(urlver)) req = urllib2.Request(urlver, None) resp = urllib2.urlopen(req, None, 20) page = resp.read() m = re.search(verex, page) if not m: raise FDroidException("No RE match for version") version = m.group(1) return (version, vercode) except FDroidException: msg = "Could not complete http check for app {0} due to unknown error: {1}".format( app['id'], traceback.format_exc()) return (None, msg)
def main(): global options, config options, args = parse_commandline() if not args and not options.all: raise OptionError( "If you really want to build all the apps, use --all", "all") config = common.read_config(options) if config['build_server_always']: options.server = True if options.resetserver and not options.server: raise OptionError( "Using --resetserver without --server makes no sense", "resetserver") log_dir = 'logs' if not os.path.isdir(log_dir): logging.info("Creating log directory") os.makedirs(log_dir) tmp_dir = 'tmp' if not os.path.isdir(tmp_dir): logging.info("Creating temporary directory") os.makedirs(tmp_dir) if options.test: output_dir = tmp_dir else: output_dir = 'unsigned' if not os.path.isdir(output_dir): logging.info("Creating output directory") os.makedirs(output_dir) if config['archive_older'] != 0: also_check_dir = 'archive' else: also_check_dir = None repo_dir = 'repo' build_dir = 'build' if not os.path.isdir(build_dir): logging.info("Creating build directory") os.makedirs(build_dir) srclib_dir = os.path.join(build_dir, 'srclib') extlib_dir = os.path.join(build_dir, 'extlib') # Read all app and srclib metadata allapps = metadata.read_metadata(xref=not options.onserver) apps = common.read_app_args(args, allapps, True) for appid, app in apps.items(): if (app['Disabled'] and not options.force ) or not app['Repo Type'] or not app['builds']: del apps[appid] if not apps: raise FDroidException("No apps to process.") if options.latest: for app in apps.itervalues(): for build in reversed(app['builds']): if build['disable'] and not options.force: continue app['builds'] = [build] break if options.wiki: import mwclient site = mwclient.Site((config['wiki_protocol'], config['wiki_server']), path=config['wiki_path']) site.login(config['wiki_user'], config['wiki_password']) # Build applications... failed_apps = {} build_succeeded = [] for appid, app in apps.iteritems(): first = True for thisbuild in app['builds']: wikilog = None try: # For the first build of a particular app, we need to set up # the source repo. We can reuse it on subsequent builds, if # there are any. if first: if app['Repo Type'] == 'srclib': build_dir = os.path.join('build', 'srclib', app['Repo']) else: build_dir = os.path.join('build', appid) # Set up vcs interface and make sure we have the latest code... logging.debug("Getting {0} vcs interface for {1}".format( app['Repo Type'], app['Repo'])) vcs = common.getvcs(app['Repo Type'], app['Repo'], build_dir) first = False logging.debug("Checking " + thisbuild['version']) if trybuild(app, thisbuild, build_dir, output_dir, also_check_dir, srclib_dir, extlib_dir, tmp_dir, repo_dir, vcs, options.test, options.server, options.force, options.onserver): build_succeeded.append(app) wikilog = "Build succeeded" except BuildException as be: logfile = open(os.path.join(log_dir, appid + '.log'), 'a+') logfile.write(str(be)) logfile.close() print("Could not build app %s due to BuildException: %s" % (appid, be)) if options.stop: sys.exit(1) failed_apps[appid] = be wikilog = be.get_wikitext() except VCSException as vcse: reason = str(vcse).split( '\n', 1)[0] if options.verbose else str(vcse) logging.error("VCS error while building app %s: %s" % (appid, reason)) if options.stop: sys.exit(1) failed_apps[appid] = vcse wikilog = str(vcse) except Exception as e: logging.error( "Could not build app %s due to unknown error: %s" % (appid, traceback.format_exc())) if options.stop: sys.exit(1) failed_apps[appid] = e wikilog = str(e) if options.wiki and wikilog: try: # Write a page with the last build log for this version code lastbuildpage = appid + '/lastbuild_' + thisbuild['vercode'] newpage = site.Pages[lastbuildpage] txt = "Build completed at " + time.strftime( "%Y-%m-%d %H:%M:%SZ", time.gmtime()) + "\n\n" + wikilog newpage.save(txt, summary='Build log') # Redirect from /lastbuild to the most recent build log newpage = site.Pages[appid + '/lastbuild'] newpage.save('#REDIRECT [[' + lastbuildpage + ']]', summary='Update redirect') except: logging.error( "Error while attempting to publish build log") for app in build_succeeded: logging.info("success: %s" % (app['id'])) if not options.verbose: for fa in failed_apps: logging.info("Build for app %s failed:\n%s" % (fa, failed_apps[fa])) logging.info("Finished.") if len(build_succeeded) > 0: logging.info(str(len(build_succeeded)) + ' builds succeeded') if len(failed_apps) > 0: logging.info(str(len(failed_apps)) + ' builds failed') sys.exit(0)
def main(): global options, config # Parse command line... parser = OptionParser( usage="Usage: %prog [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]") parser.add_option("-v", "--verbose", action="store_true", default=False, help="Spew out even more information than normal") parser.add_option("-q", "--quiet", action="store_true", default=False, help="Restrict output to warnings and errors") parser.add_option("-a", "--all", action="store_true", default=False, help="Install all signed applications available") (options, args) = parser.parse_args() if not args and not options.all: raise OptionError( "If you really want to install all the signed apps, use --all", "all") config = common.read_config(options) output_dir = 'repo' if not os.path.isdir(output_dir): logging.info("No signed output directory - nothing to do") sys.exit(0) if args: vercodes = common.read_pkg_args(args, True) apks = {appid: None for appid in vercodes} # Get the signed apk with the highest vercode for apkfile in sorted(glob.glob(os.path.join(output_dir, '*.apk'))): try: appid, vercode = common.apknameinfo(apkfile) except FDroidException: continue if appid not in apks: continue if vercodes[appid] and vercode not in vercodes[appid]: continue apks[appid] = apkfile for appid, apk in apks.iteritems(): if not apk: raise FDroidException("No signed apk available for %s" % appid) else: apks = { common.apknameinfo(apkfile)[0]: apkfile for apkfile in sorted(glob.glob(os.path.join(output_dir, '*.apk'))) } for appid, apk in apks.iteritems(): # Get device list each time to avoid device not found errors devs = devices() if not devs: raise FDroidException("No attached devices found") logging.info("Installing %s..." % apk) for dev in devs: logging.info("Installing %s on %s..." % (apk, dev)) p = FDroidPopen([config['adb'], "-s", dev, "install", apk]) fail = "" for line in p.output.splitlines(): if line.startswith("Failure"): fail = line[9:-1] if not fail: continue if fail == "INSTALL_FAILED_ALREADY_EXISTS": logging.warn("%s is already installed on %s." % (apk, dev)) else: raise FDroidException("Failed to install %s on %s: %s" % (apk, dev, fail)) logging.info("\nFinished")
def main(): global options, config # Parse command line... parser = OptionParser(usage="Usage: %prog [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]") parser.add_option("-v", "--verbose", action="store_true", default=False, help="Spew out even more information than normal") parser.add_option("-q", "--quiet", action="store_true", default=False, help="Restrict output to warnings and errors") (options, args) = parser.parse_args() config = common.read_config(options) tmp_dir = 'tmp' if not os.path.isdir(tmp_dir): logging.info("Creating temporary directory") os.makedirs(tmp_dir) unsigned_dir = 'unsigned' if not os.path.isdir(unsigned_dir): logging.error("No unsigned directory - nothing to do") sys.exit(0) verified = 0 notverified = 0 vercodes = common.read_pkg_args(args, True) for apkfile in sorted(glob.glob(os.path.join(unsigned_dir, '*.apk'))): apkfilename = os.path.basename(apkfile) appid, vercode = common.apknameinfo(apkfile) if vercodes and appid not in vercodes: continue if vercodes[appid] and vercode not in vercodes[appid]: continue try: logging.info("Processing " + apkfilename) remoteapk = os.path.join(tmp_dir, apkfilename) if os.path.exists(remoteapk): os.remove(remoteapk) url = 'https://f-droid.org/repo/' + apkfilename logging.info("...retrieving " + url) p = FDroidPopen(['wget', url], cwd=tmp_dir) if p.returncode != 0: raise FDroidException("Failed to get " + apkfilename) thisdir = os.path.join(tmp_dir, 'this_apk') thatdir = os.path.join(tmp_dir, 'that_apk') for d in [thisdir, thatdir]: if os.path.exists(d): shutil.rmtree(d) os.mkdir(d) if subprocess.call(['jar', 'xf', os.path.join("..", "..", unsigned_dir, apkfilename)], cwd=thisdir) != 0: raise FDroidException("Failed to unpack local build of " + apkfilename) if subprocess.call(['jar', 'xf', os.path.join("..", "..", remoteapk)], cwd=thatdir) != 0: raise FDroidException("Failed to unpack remote build of " + apkfilename) p = FDroidPopen(['diff', '-r', 'this_apk', 'that_apk'], cwd=tmp_dir) lines = p.output.splitlines() if len(lines) != 1 or 'META-INF' not in lines[0]: raise FDroidException("Unexpected diff output - " + p.output) logging.info("...successfully verified") verified += 1 except FDroidException, e: logging.info("...NOT verified - {0}".format(e)) notverified += 1
def main(): global options, config # Parse command line... parser = OptionParser( usage="Usage: %prog [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]") parser.add_option("-v", "--verbose", action="store_true", default=False, help="Spew out even more information than normal") parser.add_option("-q", "--quiet", action="store_true", default=False, help="Restrict output to warnings and errors") (options, args) = parser.parse_args() config = common.read_config(options) tmp_dir = 'tmp' if not os.path.isdir(tmp_dir): logging.info("Creating temporary directory") os.makedirs(tmp_dir) unsigned_dir = 'unsigned' if not os.path.isdir(unsigned_dir): logging.error("No unsigned directory - nothing to do") sys.exit(0) verified = 0 notverified = 0 vercodes = common.read_pkg_args(args, True) for apkfile in sorted(glob.glob(os.path.join(unsigned_dir, '*.apk'))): apkfilename = os.path.basename(apkfile) appid, vercode = common.apknameinfo(apkfile) if vercodes and appid not in vercodes: continue if vercodes[appid] and vercode not in vercodes[appid]: continue try: logging.info("Processing " + apkfilename) remoteapk = os.path.join(tmp_dir, apkfilename) if os.path.exists(remoteapk): os.remove(remoteapk) url = 'https://f-droid.org/repo/' + apkfilename logging.info("...retrieving " + url) common.download_file(url, dldir=tmp_dir) compare_result = common.compare_apks( os.path.join(unsigned_dir, apkfilename), remoteapk, tmp_dir) if compare_result: raise FDroidException(compare_result) logging.info("...successfully verified") verified += 1 except FDroidException, e: logging.info("...NOT verified - {0}".format(e)) notverified += 1