1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#!/usr/bin/env python
import argparse
import atexit
import cStringIO
import os
import pycurl
import sys
import tempfile
import time
# Public artifacts BUILD-INFO.txt
build_info = 'Format-Version: 0.5\n\nFiles-Pattern: *\nLicense-Type: open\n'
class API_v1(object):
def __init__(self, server, build_info, api_key):
self.server = server
self.api_base = server
self.build_info = build_info
self.api_key = api_key
self.curl = pycurl.Curl()
def __del__(self):
self.curl.close()
def _upload_data(self, url, data, retry_count=3):
response = cStringIO.StringIO()
self.curl.setopt(pycurl.URL, url)
self.curl.setopt(pycurl.HTTPPOST, data)
self.curl.setopt(pycurl.WRITEFUNCTION, response.write)
try:
self.curl.perform()
except Exception as e:
if retry_count > 0:
# server could be reloading or something. give it a second and
# try again
print('Upload failed for %s, retrying in 2 seconds' % url)
time.sleep(2)
return self._upload(url, data, retry_count - 1)
else:
return str(e)
return response.getvalue()
def upload_file(self, url, filename):
data = [
('file', (pycurl.FORM_FILE, filename)),
('key', (pycurl.FORM_CONTENTS, self.api_key)),
]
return self._upload_data(url, data)
def upload_transfer_queue(self, transfer_queue):
transfer_failures = []
for transfer_item in transfer_queue:
http_status = self.upload_file(
transfer_item, transfer_queue[transfer_item])
if http_status != 'OK':
transfer_failures.append('%s: %s' % (transfer_item, http_status))
return transfer_failures
def get_transfer_queue(self, src, dst):
if self.api_base[-1] != '/' and dst[0] != '/':
# one of these needs to be a slash to produce a url
dst = '/' + dst
transfer_queue = {}
src_dir = os.path.abspath(src)
for root, dirs, files in os.walk(src_dir):
dst_dir = dst
if not root.endswith(dst): # in sub directory
dst_dir = os.path.join(dst, root[len(src_dir) + 1:])
for f in files:
dst_file = '%s%s/%s' % (self.api_base, dst_dir, f)
transfer_queue[dst_file] = os.path.join(root, f)
build_info_file = os.path.join(root, 'BUILD-INFO.txt')
if not os.path.exists(build_info_file):
dst_file = '%s%s/%s' % (
self.api_base, dst_dir, 'BUILD-INFO.txt')
transfer_queue[dst_file] = self.build_info
return transfer_queue
def upload(self, src, dst):
transfer_queue = self.get_transfer_queue(src, dst)
return self.upload_transfer_queue(transfer_queue)
def main():
parser = argparse.ArgumentParser(
description='Copy file(s) from source to destination')
parser.add_argument('-k', '--key', help='key used for the copy')
parser.add_argument('--server', default='http://snapshots.linaro.org/',
help='Publishing API server. default=%(default)s')
parser.add_argument('-b', '--build-info', help='Custom build-info file')
parser.add_argument('src', help='source file(s) to copy')
parser.add_argument('dst', help='destination to copy the file(s)')
arguments = parser.parse_args()
# Publish key is required. Fallback to PUBLISH_KEY environment
# variable when it isn't passed as an argument
if arguments.key:
key = arguments.key
else:
key = os.environ.get('PUBLISH_KEY')
if key is None:
sys.exit('Key is not defined.')
if not arguments.build_info:
fd, arguments.build_info = tempfile.mkstemp(prefix='BUILD-INFO.txt')
atexit.register(os.unlink, arguments.build_info)
os.write(fd, build_info)
api = API_v1(arguments.server, arguments.build_info, key)
transfer_failures = api.upload(arguments.src, arguments.dst)
if len(transfer_failures) > 0:
sys.exit('Failed to transfer:\n %s' % '\n '.join(transfer_failures))
if __name__ == '__main__':
main()
|