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 return (repotype, repo)
49 # Works for Google Code and BitBucket...
50 index=page.find('git clone')
53 repo = page[index + 10:]
54 index = repo.find('<')
56 return (None, "Error while getting repo address")
58 return (repotype, repo)
61 index=page.find('svn checkout')
64 repo = page[index + 13:]
65 prefix = '<strong><em>http</em></strong>'
66 if not repo.startswith(prefix):
67 return (None, "Unexpected checkout instructions format")
68 repo = 'http' + repo[len(prefix):]
69 index = repo.find('<')
71 return (None, "Error while getting repo address - no end tag? '" + repo + "'")
74 index = repo.find(' ')
76 return (None, "Error while getting repo address - no space? '" + repo + "'")
78 return (repotype, repo)
80 return (None, "No information found." + page)
85 # Read configuration...
86 execfile('config.py', globals())
90 # Parse command line...
91 parser = OptionParser()
92 parser.add_option("-u", "--url", default=None,
93 help="Project URL to import from.")
94 parser.add_option("-s", "--subdir", default=None,
95 help="Path to main android project subdirectory, if not in root.")
96 parser.add_option("-r", "--repo", default=None,
97 help="Allows a different repo to be specified for a multi-repo google code project")
98 (options, args) = parser.parse_args()
101 print "Specify project url."
106 if not os.path.isdir(tmp_dir):
107 print "Creating temporary directory"
111 apps = common.read_metadata()
113 # Figure out what kind of project it is...
117 website = url #by default, we might override it
118 if url.startswith('git://'):
124 elif url.startswith('https://github.com'):
125 if url.endswith('/'):
127 if url.endswith('.git'):
128 print "A github URL should point to the project, not the git repo"
130 projecttype = 'github'
134 elif url.startswith('https://gitorious.org/'):
135 projecttype = 'gitorious'
136 repo = 'https://git.gitorious.org/' + url[22:] + '.git'
139 elif url.startswith('https://bitbucket.org/'):
140 if url.endswith('/'):
142 projecttype = 'bitbucket'
143 sourcecode = url + '/src'
144 issuetracker = url + '/issues'
145 # Figure out the repo type and adddress...
146 repotype, repo = getrepofrompage(sourcecode)
148 print "Unable to determine vcs type. " + repo
150 elif url.startswith('http://code.google.com/p/'):
151 if not url.endswith('/'):
153 projecttype = 'googlecode'
154 sourcecode = url + 'source/checkout'
156 sourcecode += "?repo=" + options.repo
157 issuetracker = url + 'issues/list'
159 # Figure out the repo type and adddress...
160 repotype, repo = getrepofrompage(sourcecode)
162 print "Unable to determine vcs type. " + repo
165 # Figure out the license...
166 req = urllib.urlopen(url)
167 if req.getcode() != 200:
168 print 'Unable to find project page at ' + sourcecode + ' - return code ' + str(req.getcode())
171 index = page.find('Code license')
173 print "Couldn't find license data"
176 lprefix = 'rel="nofollow">'
177 index = ltext.find(lprefix)
179 print "Couldn't find license text"
181 ltext = ltext[index + len(lprefix):]
182 index = ltext.find('<')
184 print "License text not formatted as expected"
186 ltext = ltext[:index]
187 if ltext == 'GNU GPL v3':
189 elif ltext == 'GNU GPL v2':
191 elif ltext == 'Apache License 2.0':
193 elif ltext == 'MIT License':
195 elif ltext == 'GNU Lesser GPL':
197 elif ltext == 'Mozilla Public License 1.1':
199 elif ltext == 'New BSD License':
202 print "License " + ltext + " is not recognised"
206 print "Unable to determine the project type."
207 print "The URL you supplied was not in one of the supported formats. Please consult"
208 print "the manual for a list of supported formats, and supply one of those."
211 # Get a copy of the source so we can extract some info...
212 print 'Getting source from ' + repotype + ' repo at ' + repo
213 src_dir = os.path.join(tmp_dir, 'importer')
214 if os.path.exists(src_dir):
215 shutil.rmtree(src_dir)
216 vcs = common.getvcs(repotype, repo, src_dir, sdk_path)
217 vcs.gotorevision(None)
219 root_dir = os.path.join(src_dir, options.subdir)
223 # Check AndroidManiifest.xml exists...
224 if not os.path.exists(root_dir + '/AndroidManifest.xml'):
225 print "AndroidManifest.xml did not exist in the expected location. Specify --subdir?"
228 # Extract some information...
229 paths = common.manifest_paths(root_dir, None)
230 version, vercode, package = common.parse_androidmanifests(paths)
232 print "Couldn't find package ID"
235 print "Couldn't find latest version name"
238 print "Couldn't find latest version code"
241 # Make sure it's actually new...
243 if app['id'] == package:
244 print "Package " + package + " already exists"
247 # Construct the metadata...
248 app = common.parse_metadata(None)
250 app['Web Site'] = website
251 app['Source Code'] = sourcecode
253 app['Issue Tracker'] = issuetracker
255 app['License'] = license
256 app['Repo Type'] = repotype
259 # Create a build line...
261 build['version'] = version
262 build['vercode'] = vercode
263 build['commit'] = '?'
265 build['subdir'] = options.subdir
266 if os.path.exists(os.path.join(root_dir, 'jni')):
267 build['buildjni'] = 'yes'
268 app['builds'].append(build)
269 app['comments'].append(('build:' + version,
270 "#Generated by import.py - check this is the right version, and find the right commit!"))
272 # Keep the repo directory to save bandwidth...
273 if not os.path.exists('build'):
275 shutil.move(src_dir, os.path.join('build', package))
276 with open('build/.fdroidvcs-' + package, 'w') as f:
277 f.write(repotype + ' ' + repo)
279 metafile = os.path.join('metadata', package + '.txt')
280 common.write_metadata(metafile, app)
281 print "Wrote " + metafile
284 if __name__ == "__main__":