chiark / gitweb /
Basic source code scanner, doesn't do much yet
authorCiaran Gultnieks <ciaran@ciarang.com>
Tue, 3 Jan 2012 15:37:29 +0000 (15:37 +0000)
committerCiaran Gultnieks <ciaran@ciarang.com>
Tue, 3 Jan 2012 15:37:29 +0000 (15:37 +0000)
scanner.py [new file with mode: 0755]

diff --git a/scanner.py b/scanner.py
new file mode 100755 (executable)
index 0000000..843c287
--- /dev/null
@@ -0,0 +1,142 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+#
+# scanner.py - part of the FDroid server tools
+# Copyright (C) 2010-12, Ciaran Gultnieks, ciaran@ciarang.com
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# 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 shutil
+import re
+import urllib
+import time
+import subprocess
+from optparse import OptionParser
+import HTMLParser
+import common
+
+#Read configuration...
+execfile('config.py')
+
+
+# Parse command line...
+parser = OptionParser()
+parser.add_option("-v", "--verbose", action="store_true", default=False,
+                  help="Spew out even more information than normal")
+(options, args) = parser.parse_args()
+
+# Get all apps...
+apps = common.read_metadata(options.verbose)
+
+html_parser = HTMLParser.HTMLParser()
+
+problems = []
+
+for app in apps:
+
+    if app['disabled']:
+        print "Skipping %s: disabled" % app['id']
+    elif not app['builds']:
+        print "Skipping %s: no builds specified" % app['id']
+
+    if (app['disabled'] is None and app['repo'] != '' 
+            and app['repotype'] != '' and len(app['builds']) > 0):
+
+        print "Processing " + app['id']
+
+        build_dir = 'build/' + app['id']
+
+        # Set up vcs interface and make sure we have the latest code...
+        vcs = common.getvcs(app['repotype'], app['repo'], build_dir)
+
+        refreshed_source = False
+
+
+        for thisbuild in app['builds']:
+
+            if thisbuild['commit'].startswith('!'):
+                print ("..skipping version " + thisbuild['version'] + " - " +
+                        thisbuild['commit'][1:])
+            else:
+                print "..scanning version " + thisbuild['version']
+
+                if not refreshed_source:
+                    vcs.refreshlocal()
+                    refreshed_source = True
+
+                # Optionally, the actual app source can be in a subdirectory...
+                if thisbuild.has_key('subdir'):
+                    root_dir = os.path.join(build_dir, thisbuild['subdir'])
+                else:
+                    root_dir = build_dir
+
+                # Get a working copy of the right revision...
+                if options.verbose:
+                    print "Resetting repository to " + thisbuild['commit']
+                vcs.reset(thisbuild['commit'])
+
+                # Initialise submodules if requred...
+                if thisbuild.get('submodules', 'no')  == 'yes':
+                    vcs.initsubmodules()
+
+                # Generate (or update) the ant build file, build.xml...
+                if (thisbuild.get('update', 'yes') == 'yes' and
+                       not thisbuild.has_key('maven')):
+                    parms = [os.path.join(sdk_path, 'tools', 'android'),
+                             'update', 'project', '-p', '.']
+                    parms.append('--subprojects')
+                    if thisbuild.has_key('target'):
+                        parms.append('-t')
+                        parms.append(thisbuild['target'])
+                    if subprocess.call(parms, cwd=root_dir) != 0:
+                        print "Failed to update project"
+                        sys.exit(1)
+
+                # Delete unwanted file...
+                if thisbuild.has_key('rm'):
+                    os.remove(os.path.join(build_dir, thisbuild['rm']))
+
+                # Run a pre-build command if one is required...
+                if thisbuild.has_key('prebuild'):
+                    if subprocess.call(thisbuild['prebuild'],
+                            cwd=root_dir, shell=True) != 0:
+                        print "Error running pre-build command"
+                        sys.exit(1)
+
+                # Apply patches if any
+                if 'patch' in thisbuild:
+                    for patch in thisbuild['patch'].split(';'):
+                        print "Applying " + patch
+                        patch_path = os.path.join('metadata', app['id'], patch)
+                        if subprocess.call(['patch', '-p1',
+                                        '-i', os.path.abspath(patch_path)], cwd=build_dir) != 0:
+                            print "Failed to apply patch %s" % patch_path
+                            sys.exit(1)
+
+                # Scan for common known non-free blobs:
+                usual_suspects = ['flurryagent.jar', 'paypal_mpl.jar']
+                for r,d,f in os.walk(build_dir):
+                    for curfile in f:
+                        if curfile.lower() in usual_suspects:
+                            msg = 'Found probable non-free blob ' + os.path.join(r,file)
+                            msg += ' in ' + app['id'] + ' ' + thisbuild['version']
+                            problems.append(msg)
+
+print "Finished:"
+for problem in problems:
+    print problem
+print str(len(problems)) + ' problems.'
+