# 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")
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")
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")
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):
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):
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):
# 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
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
thisinfo['builds'] = []
thisinfo['comments'] = []
+ if metafile is None:
+ return thisinfo
+
mode = 0
buildlines = []
curcomments = []
--- /dev/null
+#!/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
+