chiark / gitweb /
Rename PopenResult.stdout to output since it also contains stderr
[fdroidserver.git] / fdroidserver / verify.py
1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*-
3 #
4 # verify.py - part of the FDroid server tools
5 # Copyright (C) 2013, Ciaran Gultnieks, ciaran@ciarang.com
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU Affero General Public License for more details.
16 #
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20 import sys
21 import os
22 import shutil
23 import subprocess
24 import glob
25 from optparse import OptionParser
26 import logging
27
28 import common
29 from common import FDroidPopen
30
31 options = None
32 config = None
33
34
35 def main():
36
37     global options, config
38
39     # Parse command line...
40     parser = OptionParser(usage="Usage: %prog [options] [APPID[:VERCODE] [APPID[:VERCODE] ...]]")
41     parser.add_option("-v", "--verbose", action="store_true", default=False,
42                       help="Spew out even more information than normal")
43     parser.add_option("-q", "--quiet", action="store_true", default=False,
44                       help="Restrict output to warnings and errors")
45     (options, args) = parser.parse_args()
46
47     config = common.read_config(options)
48
49     tmp_dir = 'tmp'
50     if not os.path.isdir(tmp_dir):
51         logging.info("Creating temporary directory")
52         os.makedirs(tmp_dir)
53
54     unsigned_dir = 'unsigned'
55     if not os.path.isdir(unsigned_dir):
56         logging.error("No unsigned directory - nothing to do")
57         sys.exit(0)
58
59     verified = 0
60     notverified = 0
61
62     vercodes = common.read_pkg_args(args, True)
63
64     for apkfile in sorted(glob.glob(os.path.join(unsigned_dir, '*.apk'))):
65
66         apkfilename = os.path.basename(apkfile)
67         appid, vercode = common.apknameinfo(apkfile)
68
69         if vercodes and appid not in vercodes:
70             continue
71         if vercodes[appid] and vercode not in vercodes[appid]:
72             continue
73
74         try:
75
76             logging.info("Processing " + apkfilename)
77
78             remoteapk = os.path.join(tmp_dir, apkfilename)
79             if os.path.exists(remoteapk):
80                 os.remove(remoteapk)
81             url = 'https://f-droid.org/repo/' + apkfilename
82             logging.info("...retrieving " + url)
83             p = FDroidPopen(['wget', url], cwd=tmp_dir)
84             if p.returncode != 0:
85                 raise Exception("Failed to get " + apkfilename)
86
87             thisdir = os.path.join(tmp_dir, 'this_apk')
88             thatdir = os.path.join(tmp_dir, 'that_apk')
89             for d in [thisdir, thatdir]:
90                 if os.path.exists(d):
91                     shutil.rmtree(d)
92                 os.mkdir(d)
93
94             if subprocess.call(['jar', 'xf',
95                                 os.path.join("..", "..", unsigned_dir, apkfilename)],
96                                cwd=thisdir) != 0:
97                 raise Exception("Failed to unpack local build of " + apkfilename)
98             if subprocess.call(['jar', 'xf',
99                                 os.path.join("..", "..", remoteapk)],
100                                cwd=thatdir) != 0:
101                 raise Exception("Failed to unpack remote build of " + apkfilename)
102
103             p = FDroidPopen(['diff', '-r', 'this_apk', 'that_apk'], cwd=tmp_dir)
104             lines = p.output.splitlines()
105             if len(lines) != 1 or 'META-INF' not in lines[0]:
106                 raise Exception("Unexpected diff output - " + p.output)
107
108             logging.info("...successfully verified")
109             verified += 1
110
111         except Exception, e:
112             logging.info("...NOT verified - {0}".format(e))
113             notverified += 1
114
115     logging.info("Finished")
116     logging.info("{0} successfully verified".format(verified))
117     logging.info("{0} NOT verified".format(notverified))
118
119 if __name__ == "__main__":
120     main()