2 # -*- coding: utf-8 -*-
4 # import.py - part of the FDroid server tools
5 # Copyright (C) 2010-12, Ciaran Gultnieks, ciaran@ciarang.com
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.
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.
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/>.
24 from optparse import OptionParser
27 # Get the repo type and address from the given web page. The page is scanned
28 # in a rather naive manner for 'git clone xxxx', 'hg clone xxxx', etc, and
29 # when one of these is found it's assumed that's the information we want.
30 # Returns repotype, address, or None, reason
31 def getrepofrompage(url):
33 req = urllib.urlopen(url)
34 if req.getcode() != 200:
35 return (None, 'Unable to find source at ' + sourcecode + ' - return code ' + str(req.getcode()))
38 # Works for Google Code and BitBucket...
39 index = page.find('hg clone')
42 repo = page[index + 9:]
43 index = repo.find('<')
45 return (None, "Error while getting repo address")
47 repo = repo.split('"')[0]
48 return (repotype, repo)
50 # Works for Google Code and BitBucket...
51 index=page.find('git clone')
54 repo = page[index + 10:]
55 index = repo.find('<')
57 return (None, "Error while getting repo address")
59 repo = repo.split('"')[0]
60 return (repotype, repo)
63 index=page.find('svn checkout')
66 repo = page[index + 13:]
67 prefix = '<strong><em>http</em></strong>'
68 if not repo.startswith(prefix):
69 return (None, "Unexpected checkout instructions format")
70 repo = 'http' + repo[len(prefix):]
71 index = repo.find('<')
73 return (None, "Error while getting repo address - no end tag? '" + repo + "'")
76 index = repo.find(' ')
78 return (None, "Error while getting repo address - no space? '" + repo + "'")
80 repo = repo.split('"')[0]
81 return (repotype, repo)
83 return (None, "No information found." + page)
88 # Read configuration...
89 execfile('config.py', globals())
93 # Parse command line...
94 parser = OptionParser()
95 parser.add_option("-u", "--url", default=None,
96 help="Project URL to import from.")
97 parser.add_option("-s", "--subdir", default=None,
98 help="Path to main android project subdirectory, if not in root.")
99 parser.add_option("-r", "--repo", default=None,
100 help="Allows a different repo to be specified for a multi-repo google code project")
101 parser.add_option("--rev", default=None,
102 help="Allows a different revision (or git branch) to be specified for the initial import")
103 (options, args) = parser.parse_args()
106 print "Specify project url."
111 if not os.path.isdir(tmp_dir):
112 print "Creating temporary directory"
116 apps = common.read_metadata()
118 # Figure out what kind of project it is...
122 website = url #by default, we might override it
123 if url.startswith('git://'):
129 elif url.startswith('https://github.com'):
130 if url.endswith('/'):
132 if url.endswith('.git'):
133 print "A github URL should point to the project, not the git repo"
135 projecttype = 'github'
139 issuetracker = url + '/issues'
140 elif url.startswith('https://gitorious.org/'):
141 projecttype = 'gitorious'
142 repo = 'https://git.gitorious.org/' + url[22:] + '.git'
145 elif url.startswith('https://bitbucket.org/'):
146 if url.endswith('/'):
148 projecttype = 'bitbucket'
149 sourcecode = url + '/src'
150 issuetracker = url + '/issues'
151 # Figure out the repo type and adddress...
152 repotype, repo = getrepofrompage(sourcecode)
154 print "Unable to determine vcs type. " + repo
156 elif url.startswith('http://code.google.com/p/'):
157 if not url.endswith('/'):
159 projecttype = 'googlecode'
160 sourcecode = url + 'source/checkout'
162 sourcecode += "?repo=" + options.repo
163 issuetracker = url + 'issues/list'
165 # Figure out the repo type and adddress...
166 repotype, repo = getrepofrompage(sourcecode)
168 print "Unable to determine vcs type. " + repo
171 # Figure out the license...
172 req = urllib.urlopen(url)
173 if req.getcode() != 200:
174 print 'Unable to find project page at ' + sourcecode + ' - return code ' + str(req.getcode())
177 index = page.find('Code license')
179 print "Couldn't find license data"
182 lprefix = 'rel="nofollow">'
183 index = ltext.find(lprefix)
185 print "Couldn't find license text"
187 ltext = ltext[index + len(lprefix):]
188 index = ltext.find('<')
190 print "License text not formatted as expected"
192 ltext = ltext[:index]
193 if ltext == 'GNU GPL v3':
195 elif ltext == 'GNU GPL v2':
197 elif ltext == 'Apache License 2.0':
199 elif ltext == 'MIT License':
201 elif ltext == 'GNU Lesser GPL':
203 elif ltext == 'Mozilla Public License 1.1':
205 elif ltext == 'New BSD License':
208 print "License " + ltext + " is not recognised"
212 print "Unable to determine the project type."
213 print "The URL you supplied was not in one of the supported formats. Please consult"
214 print "the manual for a list of supported formats, and supply one of those."
217 # Get a copy of the source so we can extract some info...
218 print 'Getting source from ' + repotype + ' repo at ' + repo
219 src_dir = os.path.join(tmp_dir, 'importer')
220 if os.path.exists(src_dir):
221 shutil.rmtree(src_dir)
222 vcs = common.getvcs(repotype, repo, src_dir, sdk_path)
223 vcs.gotorevision(options.rev)
225 root_dir = os.path.join(src_dir, options.subdir)
229 # Check AndroidManiifest.xml exists...
230 if not os.path.exists(root_dir + '/AndroidManifest.xml'):
231 print "AndroidManifest.xml did not exist in the expected location. Specify --subdir?"
234 # Extract some information...
235 paths = common.manifest_paths(root_dir, None)
236 version, vercode, package = common.parse_androidmanifests(paths)
238 print "Couldn't find package ID"
241 print "WARNING: Couldn't find latest version name"
243 print "WARNING: Couldn't find latest version code"
245 # Make sure it's actually new...
247 if app['id'] == package:
248 print "Package " + package + " already exists"
251 # Construct the metadata...
252 app = common.parse_metadata(None)
254 app['Web Site'] = website
255 app['Source Code'] = sourcecode
257 app['Issue Tracker'] = issuetracker
259 app['License'] = license
260 app['Repo Type'] = repotype
263 # Create a build line...
265 build['version'] = version if version else '?'
266 build['vercode'] = vercode if vercode else '?'
267 build['commit'] = '?'
268 build['disable'] = 'Generated by import.py - check/set version fields and commit id'
270 build['subdir'] = options.subdir
271 if os.path.exists(os.path.join(root_dir, 'jni')):
272 build['buildjni'] = 'yes'
273 app['builds'].append(build)
275 # Keep the repo directory to save bandwidth...
276 if not os.path.exists('build'):
278 shutil.move(src_dir, os.path.join('build', package))
279 with open('build/.fdroidvcs-' + package, 'w') as f:
280 f.write(repotype + ' ' + repo)
282 metafile = os.path.join('metadata', package + '.txt')
283 common.write_metadata(metafile, app)
284 print "Wrote " + metafile
287 if __name__ == "__main__":