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 paths = common.manifest_paths(root_dir, None)
232 version, vercode, package = common.parse_androidmanifests(paths)
234 print "Couldn't find package ID"
237 print "Couldn't find latest version name"
240 print "Couldn't find latest version code"
243 # Make sure it's actually new...
245 if app['id'] == package:
246 print "Package " + package + " already exists"
249 # Construct the metadata...
250 app = common.parse_metadata(None)
252 app['Web Site'] = website
253 app['Source Code'] = sourcecode
255 app['Issue Tracker'] = issuetracker
257 app['License'] = license
258 app['Repo Type'] = repotype
261 # Create a build line...
263 build['version'] = version
264 build['vercode'] = vercode
265 build['commit'] = '?'
267 build['subdir'] = options.subdir
268 if os.path.exists(os.path.join(root_dir, 'jni')):
269 build['buildjni'] = 'yes'
270 app['builds'].append(build)
271 app['comments'].append(('build:' + version,
272 "#Generated by import.py - check this is the right version, and find the right commit!"))
274 # Keep the repo directory to save bandwidth...
275 if not os.path.exists('build'):
277 shutil.move(src_dir, os.path.join('build', package))
278 with open('build/.fdroidvcs-' + package, 'w') as f:
279 f.write(repotype + ' ' + repo)
281 metafile = os.path.join('metadata', package + '.txt')
282 common.write_metadata(metafile, app)
283 print "Wrote " + metafile
286 if __name__ == "__main__":