chiark / gitweb /
Simple metadata generator
authorCiaran Gultnieks <ciaran@ciarang.com>
Sun, 5 Feb 2012 11:02:01 +0000 (11:02 +0000)
committerCiaran Gultnieks <ciaran@ciarang.com>
Sun, 5 Feb 2012 11:02:01 +0000 (11:02 +0000)
common.py
import.py [new file with mode: 0755]

index e88bf5517494086aec1d6216d854c0bb775581b7..8d12767d11e89e5e508b4981fdf22de236179847 100644 (file)
--- a/common.py
+++ b/common.py
@@ -65,6 +65,8 @@ class vcs:
     # be dirty, or even non-existent. If the repository does already exist
     # locally, it will be updated from the origin, but only once in the
     # lifetime of the vcs object.
+    # None is acceptable for 'rev' if you know you are cloning a clean copy of
+    # the repo - otherwise it must specify a valid revision.
     def gotorevision(self, rev):
         raise VCSException("This VCS type doesn't define gotorevision")
 
@@ -115,8 +117,9 @@ class vcs_git(vcs):
                     raise VCSException("Git fetch failed")
                 self.refreshed = True
         # Check out the appropriate revision...
-        if subprocess.call(['git', 'checkout', rev], cwd=self.local) != 0:
-            raise VCSException("Git checkout failed")
+        if rev:
+            if subprocess.call(['git', 'checkout', rev], cwd=self.local) != 0:
+                raise VCSException("Git checkout failed")
         # Get rid of any uncontrolled files left behind...
         if subprocess.call(['git', 'clean', '-dffx'], cwd=self.local) != 0:
             raise VCSException("Git clean failed")
@@ -165,15 +168,16 @@ class vcs_gitsvn(vcs):
                         cwd=self.local) != 0:
                     raise VCSException("Git svn rebase failed")
                 self.refreshed = True
-        # Figure out the git commit id corresponding to the svn revision...
-        p = subprocess.Popen(['git', 'svn', 'find-rev', 'r' + rev],
-            cwd=self.local, stdout=subprocess.PIPE)
-        rev = p.communicate()[0].rstrip()
-        if p.returncode != 0:
-            raise VCSException("Failed to get git treeish from svn rev")
-        # Check out the appropriate revision...
-        if subprocess.call(['git', 'checkout', rev], cwd=self.local) != 0:
-            raise VCSException("Git checkout failed")
+        if rev:
+            # Figure out the git commit id corresponding to the svn revision...
+            p = subprocess.Popen(['git', 'svn', 'find-rev', 'r' + rev],
+                cwd=self.local, stdout=subprocess.PIPE)
+            rev = p.communicate()[0].rstrip()
+            if p.returncode != 0:
+                raise VCSException("Failed to get git treeish from svn rev")
+            # Check out the appropriate revision...
+            if subprocess.call(['git', 'checkout', rev], cwd=self.local) != 0:
+                raise VCSException("Git checkout failed")
         # Get rid of any uncontrolled files left behind...
         if subprocess.call(['git', 'clean', '-dffx'], cwd=self.local) != 0:
             raise VCSException("Git clean failed")
@@ -204,10 +208,11 @@ class vcs_svn(vcs):
                         self.userargs(), cwd=self.local) != 0:
                     raise VCSException("Svn update failed")
                 self.refreshed = True
-        revargs = ['-r', rev]
-        if subprocess.call(['svn', 'update', '--force'] + revargs +
-                self.userargs(), cwd=self.local) != 0:
-            raise VCSException("Svn update failed")
+        if ref:
+            revargs = ['-r', rev]
+            if subprocess.call(['svn', 'update', '--force'] + revargs +
+                    self.userargs(), cwd=self.local) != 0:
+                raise VCSException("Svn update failed")
 
 
 class vcs_hg(vcs):
@@ -225,10 +230,11 @@ class vcs_hg(vcs):
                         cwd=self.local) != 0:
                     raise VCSException("Hg pull failed")
                 self.refreshed = True
-        revargs = [rev]
-        if subprocess.call(['hg', 'checkout', '-C'] + revargs,
-                cwd=self.local) != 0:
-            raise VCSException("Hg checkout failed")
+        if rev:
+            revargs = [rev]
+            if subprocess.call(['hg', 'checkout', '-C'] + revargs,
+                    cwd=self.local) != 0:
+                raise VCSException("Hg checkout failed")
 
 
 class vcs_bzr(vcs):
@@ -246,10 +252,11 @@ class vcs_bzr(vcs):
                         cwd=self.local) != 0:
                     raise VCSException("Bzr update failed")
                 self.refreshed = True
-        revargs = ['-r', rev]
-        if subprocess.call(['bzr', 'revert'] + revargs,
-                cwd=self.local) != 0:
-            raise VCSException("Bzr revert failed")
+        if rev:
+            revargs = ['-r', rev]
+            if subprocess.call(['bzr', 'revert'] + revargs,
+                    cwd=self.local) != 0:
+                raise VCSException("Bzr revert failed")
 
 class vcs_srclib(vcs):
 
@@ -290,7 +297,7 @@ def metafieldtype(name):
 # Parse metadata for a single application.
 #
 #  'metafile' - the filename to read. The package id for the application comes
-#               from this filename.
+#               from this filename. Pass None to get a blank entry.
 #
 # Returns a dictionary containing all the details of the application. There are
 # two major kinds of information in the dictionary. Keys beginning with capital
@@ -335,12 +342,15 @@ def parse_metadata(metafile, **kw):
             thisinfo['comments'].append((key, comment))
         del curcomments[:]
 
-    if not isinstance(metafile, file):
-        metafile = open(metafile, "r")
     thisinfo = {}
-    thisinfo['id'] = metafile.name[9:-4]
-    if kw.get("verbose", False):
-        print "Reading metadata for " + thisinfo['id']
+    if metafile:
+        if not isinstance(metafile, file):
+            metafile = open(metafile, "r")
+        thisinfo['id'] = metafile.name[9:-4]
+        if kw.get("verbose", False):
+            print "Reading metadata for " + thisinfo['id']
+    else:
+        thisinfo['id'] = None
 
     # Defaults for fields that come from metadata...
     thisinfo['Name'] = None
@@ -365,6 +375,9 @@ def parse_metadata(metafile, **kw):
     thisinfo['builds'] = []
     thisinfo['comments'] = []
 
+    if metafile is None:
+        return thisinfo
+
     mode = 0
     buildlines = []
     curcomments = []
diff --git a/import.py b/import.py
new file mode 100755 (executable)
index 0000000..eb4fe04
--- /dev/null
+++ b/import.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# import.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 subprocess
+import re
+from optparse import OptionParser
+
+#Read configuration...
+repo_name = None
+repo_description = None
+repo_icon = None
+repo_url = None
+execfile('config.py')
+
+import common
+
+# Parse command line...
+parser = OptionParser()
+parser.add_option("-u", "--url", default=None,
+                  help="Project URL to import from.")
+parser.add_option("-s", "--subdir", default=None,
+                  help="Path to main android project subdirectory, if not in root.")
+(options, args) = parser.parse_args()
+
+if not options.url:
+    print "Specify project url."
+    sys.exit(1)
+url = options.url
+
+tmp_dir = 'tmp'
+if not os.path.isdir(tmp_dir):
+    print "Creating temporary directory"
+    os.makedirs(tmp_dir)
+
+# Get all apps...
+apps = common.read_metadata()
+
+# Figure out what kind of project it is...
+projecttype = None
+if url.startswith('https://github.com'):
+    projecttype = 'github'
+    repo = url + '.git'
+    repotype = 'git'
+    sourcecode = url
+
+if not projecttype:
+    print "Unable to determine the project type."
+    sys.exit(1)
+
+# Get a copy of the source so we can extract some info...
+src_dir = os.path.join(tmp_dir, 'importer')
+if os.path.exists(tmp_dir):
+    shutil.rmtree(tmp_dir)
+vcs = common.getvcs(repotype, repo, src_dir)
+vcs.gotorevision(None)
+if options.subdir:
+    root_dir = os.path.join(src_dir, options.subdir)
+else:
+    root_dir = src_dir
+
+# Check AndroidManiifest.xml exists...
+manifest = os.path.join(root_dir, 'AndroidManifest.xml')
+if not os.path.exists(manifest):
+    print "AndroidManifest.xml did not exist in the expected location. Specify --subdir?"
+    sys.exit(1)
+
+# Extract some information...
+vcsearch = re.compile(r'.*android:versionCode="([^"]+)".*').search
+vnsearch = re.compile(r'.*android:versionName="([^"]+)".').search
+psearch = re.compile(r'.*package="([^"]+)".*').search
+version = None
+vercode = None
+package = None
+for line in file(manifest):
+    if not package:
+        matches = psearch(line)
+        if matches:
+            package = matches.group(1)
+    if not version:
+        matches = vnsearch(line)
+        if matches:
+            version = matches.group(1)
+    if not vercode:
+        matches = vcsearch(line)
+        if matches:
+            vercode = matches.group(1)
+if not package:
+    print "Couldn't find package ID"
+    sys.exit(1)
+if not version:
+    print "Couldn't find latest version name"
+    sys.exit(1)
+if not vercode:
+    print "Couldn't find latest version code"
+    sys.exit(1)
+
+# Make sure it's actually new...
+for app in apps:
+    if app['id'] == package:
+        print "Package ' + package + ' already exists"
+        sys.exit(1)
+
+# Construct the metadata...
+app = common.parse_metadata(None)
+app['id'] = package
+app['Web Site'] = url
+app['Source Code'] = sourcecode
+app['Repo Type'] = repotype
+app['Repo'] = repo
+metafile = os.path.join('metadata', package + '.txt')
+common.write_metadata(metafile, app)
+print "Wrote " + metafile
+