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/>.
26 from optparse import OptionParser
29 # Get the repo type and address from the given web page. The page is scanned
30 # in a rather naive manner for 'git clone xxxx', 'hg clone xxxx', etc, and
31 # when one of these is found it's assumed that's the information we want.
32 # Returns repotype, address, or None, reason
33 def getrepofrompage(url):
35 req = urllib.urlopen(url)
36 if req.getcode() != 200:
37 return (None, 'Unable to find source at ' + sourcecode + ' - return code ' + str(req.getcode()))
40 # Works for Google Code and BitBucket...
41 index = page.find('hg clone')
44 repo = page[index + 9:]
45 index = repo.find('<')
47 return (None, "Error while getting repo address")
49 return (repotype, repo)
51 # Works for Google Code and BitBucket...
52 index=page.find('git clone')
55 repo = page[index + 10:]
56 index = repo.find('<')
58 return (None, "Error while getting repo address")
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 return (repotype, repo)
82 return (None, "No information found." + page)
87 # Read configuration...
88 execfile('config.py', globals())
92 # Parse command line...
93 parser = OptionParser()
94 parser.add_option("-u", "--url", default=None,
95 help="Project URL to import from.")
96 parser.add_option("-s", "--subdir", default=None,
97 help="Path to main android project subdirectory, if not in root.")
98 parser.add_option("-r", "--repo", default=None,
99 help="Allows a different repo to be specified for a multi-repo google code project")
100 (options, args) = parser.parse_args()
103 print "Specify project url."
108 if not os.path.isdir(tmp_dir):
109 print "Creating temporary directory"
113 apps = common.read_metadata()
115 # Figure out what kind of project it is...
119 website = url #by default, we might override it
120 if url.startswith('git://'):
126 elif url.startswith('https://github.com'):
127 if url.endswith('/'):
129 if url.endswith('.git'):
130 print "A github URL should point to the project, not the git repo"
132 projecttype = 'github'
136 elif url.startswith('https://gitorious.org/'):
137 projecttype = 'gitorious'
138 repo = 'https://git.gitorious.org/' + url[22:] + '.git'
141 elif url.startswith('https://bitbucket.org/'):
142 if url.endswith('/'):
144 projecttype = 'bitbucket'
145 sourcecode = url + '/src'
146 issuetracker = url + '/issues'
147 # Figure out the repo type and adddress...
148 repotype, repo = getrepofrompage(sourcecode)
150 print "Unable to determine vcs type. " + repo
152 elif url.startswith('http://code.google.com/p/'):
153 if not url.endswith('/'):
155 projecttype = 'googlecode'
156 sourcecode = url + 'source/checkout'
158 sourcecode += "?repo=" + options.repo
159 issuetracker = url + 'issues/list'
161 # Figure out the repo type and adddress...
162 repotype, repo = getrepofrompage(sourcecode)
164 print "Unable to determine vcs type. " + repo
167 # Figure out the license...
168 req = urllib.urlopen(url)
169 if req.getcode() != 200:
170 print 'Unable to find project page at ' + sourcecode + ' - return code ' + str(req.getcode())
173 index = page.find('Code license')
175 print "Couldn't find license data"
178 lprefix = 'rel="nofollow">'
179 index = ltext.find(lprefix)
181 print "Couldn't find license text"
183 ltext = ltext[index + len(lprefix):]
184 index = ltext.find('<')
186 print "License text not formatted as expected"
188 ltext = ltext[:index]
189 if ltext == 'GNU GPL v3':
191 elif ltext == 'GNU GPL v2':
193 elif ltext == 'Apache License 2.0':
195 elif ltext == 'MIT License':
197 elif ltext == 'GNU Lesser GPL':
199 elif ltext == 'Mozilla Public License 1.1':
201 elif ltext == 'New BSD License':
204 print "License " + ltext + " is not recognised"
208 print "Unable to determine the project type."
209 print "The URL you supplied was not in one of the supported formats. Please consult"
210 print "the manual for a list of supported formats, and supply one of those."
213 # Get a copy of the source so we can extract some info...
214 print 'Getting source from ' + repotype + ' repo at ' + repo
215 src_dir = os.path.join(tmp_dir, 'importer')
216 if os.path.exists(src_dir):
217 shutil.rmtree(src_dir)
218 vcs = common.getvcs(repotype, repo, src_dir, sdk_path)
219 vcs.gotorevision(None)
221 root_dir = os.path.join(src_dir, options.subdir)
225 # Check AndroidManiifest.xml exists...
226 if not os.path.exists(root_dir + '/AndroidManifest.xml'):
227 print "AndroidManifest.xml did not exist in the expected location. Specify --subdir?"
230 # Extract some information...
231 version, vercode, package = common.parse_androidmanifest(root_dir)
233 print "Couldn't find package ID"
236 print "Couldn't find latest version name"
239 print "Couldn't find latest version code"
242 # Make sure it's actually new...
244 if app['id'] == package:
245 print "Package " + package + " already exists"
248 # Construct the metadata...
249 app = common.parse_metadata(None)
251 app['Web Site'] = website
252 app['Source Code'] = sourcecode
254 app['Issue Tracker'] = issuetracker
256 app['License'] = license
257 app['Repo Type'] = repotype
260 # Create a build line...
262 build['version'] = version
263 build['vercode'] = vercode
264 build['commit'] = '?'
266 build['subdir'] = options.subdir
267 if os.path.exists(os.path.join(root_dir, 'jni')):
268 build['buildjni'] = 'yes'
269 app['builds'].append(build)
270 app['comments'].append(('build:' + version,
271 "#Generated by import.py - check this is the right version, and find the right commit!"))
273 # Keep the repo directory to save bandwidth...
274 if not os.path.exists('build'):
276 shutil.move(src_dir, os.path.join('build', package))
277 with open('build/.fdroidvcs-' + package, 'w') as f:
278 f.write(repotype + ' ' + repo)
280 metafile = os.path.join('metadata', package + '.txt')
281 common.write_metadata(metafile, app)
282 print "Wrote " + metafile
285 if __name__ == "__main__":