Switch to unified view

a/scripts/allura_import.py b/scripts/allura_import.py
...
...
7
import json
7
import json
8
from optparse import OptionParser
8
from optparse import OptionParser
9
from pprint import pprint
9
from pprint import pprint
10
from datetime import datetime
10
from datetime import datetime
11
11
12
from allura_api import AlluraApiClient
13
12
14
13
def parse_options():
15
def parse_options():
14
    optparser = OptionParser(usage='''%prog [options] <JSON dump>
16
    optparser = OptionParser(usage='''%prog [options] <JSON dump>
15
17
16
Import project data dump in JSON format into an Allura project.''')
18
Import project data dump in JSON format into an Allura project.''')
17
    optparser.add_option('-a', '--api-key', dest='api_key', help='API key')
19
    optparser.add_option('-a', '--api-ticket', dest='api_key', help='API ticket')
18
    optparser.add_option('-s', '--secret-key', dest='secret_key', help='Secret key')
20
    optparser.add_option('-s', '--secret-key', dest='secret_key', help='Secret key')
19
    optparser.add_option('-p', '--project', dest='project', help='Project to import to')
21
    optparser.add_option('-p', '--project', dest='project', help='Project to import to')
20
    optparser.add_option('-t', '--tracker', dest='tracker', help='Tracker to import to')
22
    optparser.add_option('-t', '--tracker', dest='tracker', help='Tracker to import to')
21
    optparser.add_option('-u', '--base-url', dest='base_url', default='https://sourceforge.net', help='Base Allura URL (%default)')
23
    optparser.add_option('-u', '--base-url', dest='base_url', default='https://sourceforge.net', help='Base Allura URL (%default)')
22
    optparser.add_option('-o', dest='import_opts', default=[], action='append', help='Specify import option(s)', metavar='opt=val')
24
    optparser.add_option('-o', dest='import_opts', default=[], action='append', help='Specify import option(s)', metavar='opt=val')
...
...
31
    if not options.project or not options.tracker:
33
    if not options.project or not options.tracker:
32
        optparser.error("Target project and tracker are required")
34
        optparser.error("Target project and tracker are required")
33
    return optparser, options, args
35
    return optparser, options, args
34
36
35
37
36
class AlluraRestClient(object):
37
38
    def __init__(self, base_url, api_key, secret_key):
39
        self.base_url = base_url
40
        self.api_key = api_key
41
        self.secret_key = secret_key
42
        
43
    def sign(self, path, params):
44
        params.append(('api_key', self.api_key))
45
        params.append(('api_timestamp', datetime.utcnow().isoformat()))
46
        message = path + '?' + urllib.urlencode(sorted(params))
47
        digest = hmac.new(self.secret_key, message, hashlib.sha256).hexdigest()
48
        params.append(('api_signature', digest))
49
        return params
50
51
    def call(self, url, **params):
52
        url = urlparse.urljoin(options.base_url, url)
53
        params = self.sign(urlparse.urlparse(url).path, params.items())
54
55
        try:
56
            result = urllib2.urlopen(url, urllib.urlencode(params))
57
            return result.read()
58
        except urllib2.HTTPError, e:
59
            if options.verbose:
60
                error_content = e.read()
61
                e.msg += '. Error response:\n' + error_content
62
            raise e
63
64
    
65
if __name__ == '__main__':
38
if __name__ == '__main__':
66
    optparser, options, args = parse_options()
39
    optparser, options, args = parse_options()
67
    url = '/rest/p/' + options.project + '/' + options.tracker
68
    if options.validate:
69
        url += '/validate_import'
70
    else:
71
        url += '/perform_import'
72
40
73
    import_options = {}
41
    import_options = {}
74
    for s in options.import_opts:
42
    for s in options.import_opts:
75
        k, v = s.split('=', 1)
43
        k, v = s.split('=', 1)
76
        if v == 'false':
44
        if v == 'false':
...
...
93
        finally:
61
        finally:
94
            f.close()
62
            f.close()
95
63
96
    import_options['user_map'] = user_map
64
    import_options['user_map'] = user_map
97
65
98
    cli = AlluraRestClient(options.base_url, options.api_key, options.secret_key)
66
    cli = AlluraApiClient(options.base_url, options.api_key, options.secret_key, options.verbose)
67
    url = '/rest/p/' + options.project + '/' + options.tracker
68
    doc_txt = open(args[0]).read()
69
    if options.validate:
70
        url += '/validate_import'
99
    print cli.call(url, doc=open(args[0]).read(), options=json.dumps(import_options))
71
        print cli.call(url, doc=doc_txt, options=json.dumps(import_options))
72
    else:
73
        url += '/perform_import'
74
75
        doc = json.loads(doc_txt)
76
        tickets_in = doc['trackers']['default']['artifacts']
77
        doc['trackers']['default']['artifacts'] = []
78
        if options.verbose:
79
            print "Importing %d tickets" % len(tickets_in)
80
81
        cnt = 0
82
        for ticket_in in tickets_in:
83
            cnt += 1
84
            doc['trackers']['default']['artifacts'] = [ticket_in]
85
            res = cli.call(url, doc=json.dumps(doc), options=json.dumps(import_options))
86
            assert res['status'] and not res['errors']
87
            if res['warnings']:
88
                print "Imported ticket id %s, warnings: %s" % (ticket_in['id'], res['warnings'])
89
            else:
90
                print "Imported ticket id %s" % (ticket_in['id'])