chiark / gitweb /
Merge commit 'refs/merge-requests/85' of git://gitorious.org/f-droid/fdroidserver...
[fdroidserver.git] / import.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # import.py - part of the FDroid server tools
5 # Copyright (C) 2010-12, Ciaran Gultnieks, ciaran@ciarang.com
6 #
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.
11 #
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.
16 #
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/>.
19
20 import sys
21 import os
22 import shutil
23 import subprocess
24 import re
25 import urllib
26 from optparse import OptionParser
27
28 def main():
29
30     # Read configuration...
31     execfile('config.py', globals())
32
33     import common
34
35     # Parse command line...
36     parser = OptionParser()
37     parser.add_option("-u", "--url", default=None,
38                       help="Project URL to import from.")
39     parser.add_option("-s", "--subdir", default=None,
40                       help="Path to main android project subdirectory, if not in root.")
41     (options, args) = parser.parse_args()
42
43     if not options.url:
44         print "Specify project url."
45         sys.exit(1)
46     url = options.url
47
48     tmp_dir = 'tmp'
49     if not os.path.isdir(tmp_dir):
50         print "Creating temporary directory"
51         os.makedirs(tmp_dir)
52
53     # Get all apps...
54     apps = common.read_metadata()
55
56     # Figure out what kind of project it is...
57     projecttype = None
58     issuetracker = None
59     license = None
60     if url.startswith('https://github.com'):
61         projecttype = 'github'
62         repo = url + '.git'
63         repotype = 'git'
64         sourcecode = url
65     elif url.startswith('https://gitorious.org/'):
66         projecttype = 'gitorious'
67         repo = 'https://git.gitorious.org/' + url[22:] + '.git'
68         repotype = 'git'
69         sourcecode = url
70     elif url.startswith('https://bitbucket.org/'):
71         if url.endswith('/'):
72             url = url[:-1]
73         projecttype = 'bitbucket'
74         sourcecode = url + '/src'
75         issuetracker = url + '/issues'
76         repotype = 'hg'
77         repo = url
78     elif url.startswith('http://code.google.com/p/'):
79         if not url.endswith('/'):
80             url += '/';
81         projecttype = 'googlecode'
82         sourcecode = url + 'source/checkout'
83         issuetracker = url + 'issues/list'
84
85         # Figure out the repo type and adddress...
86         req = urllib.urlopen(sourcecode)
87         if req.getcode() != 200:
88             print 'Unable to find source at ' + sourcecode + ' - return code ' + str(req.getcode())
89             sys.exit(1)
90         page = req.read()
91         repotype = None
92         index = page.find('hg clone')
93         if index != -1:
94             repotype = 'hg'
95             repo = page[index + 9:]
96             index = repo.find('<')
97             if index == -1:
98                 print "Error while getting repo address"
99                 sys.exit(1)
100             repo = repo[:index]
101         if not repotype:
102             index=page.find('git clone')
103             if index != -1:
104                 repotype = 'git'
105                 repo = page[index + 10:]
106                 index = repo.find('<')
107                 if index == -1:
108                     print "Error while getting repo address"
109                     sys.exit(1)
110                 repo = repo[:index]
111         if not repotype:
112             index=page.find('svn checkout')
113             if index != -1:
114                 repotype = 'git-svn'
115                 repo = page[index + 13:]
116                 prefix = '<strong><em>http</em></strong>'
117                 if not repo.startswith(prefix):
118                     print "Unexpected checkout instructions format"
119                     sys.exit(1)
120                 repo = 'http' + repo[len(prefix):]
121                 index = repo.find('<')
122                 if index == -1:
123                     print "Error while getting repo address - no end tag? '" + repo + "'"
124                     sys.exit(1)
125                 repo = repo[:index]
126                 index = repo.find(' ')
127                 if index == -1:
128                     print "Error while getting repo address - no space? '" + repo + "'"
129                     sys.exit(1)
130                 repo = repo[:index]
131         if not repotype:
132             print "Unable to determine vcs type"
133             sys.exit(1)
134
135         # Figure out the license...
136         req = urllib.urlopen(url)
137         if req.getcode() != 200:
138             print 'Unable to find project page at ' + sourcecode + ' - return code ' + str(req.getcode())
139             sys.exit(1)
140         page = req.read()
141         index = page.find('Code license')
142         if index == -1:
143             print "Couldn't find license data"
144             sys.exit(1)
145         ltext = page[index:]
146         lprefix = 'rel="nofollow">'
147         index = ltext.find(lprefix)
148         if index == -1:
149             print "Couldn't find license text"
150             sys.exit(1)
151         ltext = ltext[index + len(lprefix):]
152         index = ltext.find('<')
153         if index == -1:
154             print "License text not formatted as expected"
155             sys.exit(1)
156         ltext = ltext[:index]
157         if ltext == 'GNU GPL v3':
158             license = 'GPLv3'
159         elif ltext == 'GNU GPL v2':
160             license = 'GPLv2'
161         elif ltext == 'Apache License 2.0':
162             license = 'Apache2'
163         elif ltext == 'MIT License':
164             license = 'MIT'
165         else:
166             print "License " + ltext + " is not recognised"
167             sys.exit(1)
168
169     if not projecttype:
170         print "Unable to determine the project type."
171         sys.exit(1)
172
173     # Get a copy of the source so we can extract some info...
174     print 'Getting source from ' + repotype + ' repo at ' + repo
175     src_dir = os.path.join(tmp_dir, 'importer')
176     if os.path.exists(tmp_dir):
177         shutil.rmtree(tmp_dir)
178     vcs = common.getvcs(repotype, repo, src_dir)
179     vcs.gotorevision(None)
180     if options.subdir:
181         root_dir = os.path.join(src_dir, options.subdir)
182     else:
183         root_dir = src_dir
184
185     # Check AndroidManiifest.xml exists...
186     manifest = os.path.join(root_dir, 'AndroidManifest.xml')
187     if not os.path.exists(manifest):
188         print "AndroidManifest.xml did not exist in the expected location. Specify --subdir?"
189         sys.exit(1)
190
191     # Extract some information...
192     version, vercode, package = common.parse_androidmanifest(manifest)
193     if not package:
194         print "Couldn't find package ID"
195         sys.exit(1)
196     if not version:
197         print "Couldn't find latest version name"
198         sys.exit(1)
199     if not vercode:
200         print "Couldn't find latest version code"
201         sys.exit(1)
202
203     # Make sure it's actually new...
204     for app in apps:
205         if app['id'] == package:
206             print "Package " + package + " already exists"
207             sys.exit(1)
208
209     # Construct the metadata...
210     app = common.parse_metadata(None)
211     app['id'] = package
212     app['Web Site'] = url
213     app['Source Code'] = sourcecode
214     if issuetracker:
215         app['Issue Tracker'] = issuetracker
216     if license:
217         app['License'] = license
218     app['Repo Type'] = repotype
219     app['Repo'] = repo
220
221     # Create a build line...
222     build = {}
223     build['version'] = version
224     build['vercode'] = vercode
225     build['commit'] = '?'
226     if options.subdir:
227         build['subdir'] = options.subdir
228     if os.path.exists(os.path.join(root_dir, 'jni')):
229         build['buildjni'] = 'yes'
230     app['builds'].append(build)
231     app['comments'].append(('build:' + version,
232         "#Generated by import.py - check this is the right version, and find the right commit!"))
233
234     metafile = os.path.join('metadata', package + '.txt')
235     common.write_metadata(metafile, app)
236     print "Wrote " + metafile
237
238
239 if __name__ == "__main__":
240     main()
241