author | robin <robin@reportlab.com> |
Fri, 16 Jun 2017 16:04:40 +0100 | |
changeset 5 | 539b3d5f515e |
parent 4 | 1899f4fe9c9b |
child 6 | 2fe9dd0a6b76 |
permissions | -rw-r--r-- |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
1 |
VERSION='0.0.2' |
0 | 2 |
import os, sys, glob, time, json |
3 |
PROG=os.path.basename(sys.argv[0]) |
|
4 |
debug=verbosity=0 |
|
5 |
||
6 |
class PyPiRequestor(): |
|
7 |
scheme = 'https' |
|
8 |
host = os.environ.get('CITOOLS_SERVER','www.reportlab.com') |
|
9 |
root = '%s://%s' % (scheme,host) |
|
10 |
loginurl = "%s/accounts/login/" % root |
|
11 |
def __init__(self,debug=0): |
|
12 |
self.debug = debug |
|
13 |
import requests |
|
14 |
self.session = requests.session() |
|
15 |
||
16 |
def login(self,u,p,nxt='/test-7491/'): |
|
17 |
s = self.session |
|
18 |
resp = s.get(self.loginurl) |
|
19 |
loginpage = resp.text |
|
20 |
if self.debug>1: |
|
21 |
if self.debug>2: print('=============loginpage\n%r' % loginpage) |
|
22 |
resp = s.post(self.loginurl, |
|
23 |
data=dict( |
|
24 |
csrfmiddlewaretoken=s.cookies['csrftoken'], |
|
25 |
username=u, |
|
26 |
password=p, |
|
27 |
next=nxt, |
|
28 |
), |
|
29 |
headers=dict( |
|
30 |
Referer=self.loginurl, |
|
31 |
), |
|
32 |
) |
|
33 |
text = resp.text |
|
34 |
status_code = resp.status_code |
|
35 |
if debug>2: |
|
36 |
print('!!!!!\n%s\n!!!!!'% text) |
|
37 |
print('%s: test-7491 csrftoken=%r' % (PROG,resp.cookies.get('csrftoken','???'))) |
|
38 |
if text!='I am alive!' or status_code!=200: |
|
39 |
raise ValueError('%s: login at %r failed with status_code=%r' % (PROG,self.loginurl,status_code)) |
|
40 |
elif verbosity>=2: |
|
41 |
print('%s: logged in OK' % PROG) |
|
42 |
return status_code |
|
43 |
||
44 |
def _download(self,u,p, kind, fn, dst): |
|
45 |
self.login(u,p) |
|
46 |
base = '%s/pypi/%s/' % (self.root,kind) |
|
47 |
url = base + fn + '/' |
|
48 |
resp = self.session.get(url, |
|
49 |
data=dict(csrfmiddlewaretoken=self.session.cookies['csrftoken']), |
|
50 |
headers = dict(Referer=self.loginurl), |
|
51 |
) |
|
52 |
status_code = resp.status_code |
|
53 |
b = resp.content |
|
54 |
if debug>2: |
|
55 |
print('!!!!!\n%r\n!!!!!'% b) |
|
56 |
if status_code!=200: |
|
57 |
raise ValueError('%s: download %r failed with status_code=%r!\n%r' % (PROG,url,status_code,b)) |
|
58 |
if dst: |
|
59 |
fn = os.path.join(dst,fn) |
|
60 |
with open(fn,'wb') as f: |
|
61 |
f.write(b) |
|
62 |
if verbosity: |
|
63 |
print('%s: %r(%d bytes) downloaded from %r.' % (PROG, fn, len(b),base)) |
|
64 |
return resp.status_code |
|
65 |
||
66 |
def download(self,u,p,kind, fn, dst): |
|
67 |
for i in self.info(u,p,kind[:-1],fn): |
|
68 |
self._download(u,p,kind,i[0],dst) |
|
69 |
||
5 | 70 |
def info(self,u,p,kind,pat,subdir=''): |
0 | 71 |
#self.login(u,p) |
5 | 72 |
if subdir: |
73 |
subdir += '/' |
|
74 |
url = '%s/pypi/%s-info/%s%s/?json=1' % (self.root,kind,subdir,pat) |
|
0 | 75 |
resp = self.session.get(url, |
76 |
#data=dict(csrfmiddlewaretoken=self.session.cookies['csrftoken']), |
|
77 |
headers = dict(Referer=self.loginurl), |
|
78 |
) |
|
79 |
status_code = resp.status_code |
|
80 |
b = resp.content |
|
81 |
if debug>2: |
|
82 |
print('!!!!!\n%r\n!!!!!'% b) |
|
83 |
if status_code!=200: |
|
84 |
raise ValueError('%s: request %r failed with status_code=%r!\n%r' % (PROG,url,status_code,b)) |
|
85 |
I = json.loads(b) |
|
86 |
if verbosity>1: |
|
87 |
print('%s: %r --> %d rows' % (PROG, url, len(I))) |
|
88 |
return I |
|
89 |
||
5 | 90 |
def upload(self,u,p,kind,fn,subdir=''): |
0 | 91 |
self.login(u,p) |
5 | 92 |
if subdir: |
93 |
subdir = '/' + subdir |
|
94 |
url = '%s/pypi/upload-%s%s/' % (self.root,kind,subdir) |
|
0 | 95 |
files= dict(file=(os.path.basename(fn),open(fn,'rb'),'application/octet-stream')) |
96 |
resp = self.session.post(url, |
|
97 |
data=dict(csrfmiddlewaretoken=self.session.cookies['csrftoken']), |
|
98 |
files=files, |
|
99 |
headers = dict(Referer=self.loginurl), |
|
100 |
) |
|
101 |
status_code = resp.status_code |
|
102 |
text = resp.text |
|
103 |
if text!='OK' or status_code!=200: |
|
104 |
raise ValueError('%s: upload %r failed with status_code=%r!\n%r' % (PROG,url,status_code,text)) |
|
105 |
if verbosity: |
|
106 |
print('%s: uploaded %r to %r.' % (PROG,fn,url)) |
|
107 |
return resp.status_code |
|
108 |
||
5 | 109 |
def clear_cache(self,u,p,fn): |
110 |
self.login(u,p) |
|
111 |
url = '%s/pypi/clear-cache/%s/' % (self.root,fn) |
|
112 |
resp = self.session.post(url, |
|
113 |
data=dict(csrfmiddlewaretoken=self.session.cookies['csrftoken']), |
|
114 |
headers = dict(Referer=self.loginurl), |
|
115 |
) |
|
116 |
status_code = resp.status_code |
|
117 |
text = resp.text |
|
118 |
if not text.endswith('OK') or status_code!=200: |
|
119 |
raise ValueError('%s: clear-cache %r failed with status_code=%r!\n%r' % (PROG,url,status_code,text)) |
|
120 |
if verbosity: |
|
121 |
print('%s: cleared cache %r.' % (PROG,fn)) |
|
122 |
return resp.status_code |
|
123 |
||
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
124 |
def package_version(self,u,p,pkg): |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
125 |
I = self.info(u,p,'package','%s-*' % pkg) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
126 |
if not I: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
127 |
v = 'unknown' |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
128 |
else: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
129 |
v = '.'.join(map(str,list(sorted([tuple([int(x) for x in i[0].split('-',2)[1].split('.') if x and x[0] in '0123456789']) for i in I]))[-1])) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
130 |
return (pkg,v) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
131 |
|
0 | 132 |
def getoption(key,default=0,cnv=int): |
133 |
key = '--%s=' % key |
|
134 |
v = [x for x in sys.argv if x.startswith(key)] |
|
135 |
if v: |
|
136 |
for x in v: |
|
137 |
sys.argv.remove(x) |
|
138 |
v = cnv(v[-1][len(key):]) |
|
139 |
else: |
|
140 |
v = default |
|
141 |
return v |
|
142 |
||
143 |
def _file_info(fn): |
|
144 |
st = os.stat(fn) |
|
145 |
return (fn,st.st_size,st.st_mtime) |
|
146 |
||
4 | 147 |
def _list_fs(patterns,recur=False): |
148 |
for pat in patterns: |
|
149 |
for fn in glob.glob(pat): |
|
150 |
if not recur: |
|
151 |
yield fn |
|
152 |
elif os.path.isdir(fn): |
|
153 |
for r,s,F in os.walk(fn): |
|
154 |
yield r |
|
155 |
for f in F: |
|
156 |
yield os.path.join(r,f) |
|
157 |
else: |
|
158 |
yield fn |
|
159 |
||
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
160 |
def tabulate(I, |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
161 |
hdrs=['Name','Length',(5*' ')+'Modified'], |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
162 |
fmtmpl8='{:<%d}\x20{:>%d}\x20\x20{:<%d}', |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
163 |
cnvf=(str,str,lambda t: time.strftime('%Y%m%d %H:%M:%S',time.localtime(t))), |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
164 |
): |
0 | 165 |
if I: |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
166 |
rows = [hdrs] |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
167 |
for row in I: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
168 |
rows.append([c(r) for c,r in zip(cnvf,row)]) |
0 | 169 |
W = [max(map(len,col)) for col in [list(i) for i in zip(*rows)]] |
170 |
if debug>3: |
|
171 |
print('tabluate: rows=%s' % repr(rows)) |
|
172 |
print('tabluate: W=%s' % repr(W)) |
|
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
173 |
fmt = fmtmpl8 % tuple(W) |
0 | 174 |
print('\n'.join(fmt.format(*i) for i in rows)) |
175 |
||
176 |
def main(): |
|
177 |
u = os.environ.get('CITOOLS_USER','beta') |
|
178 |
p = os.environ.get('CITOOLS_PASSWORD','???') |
|
179 |
global debug, verbosity |
|
180 |
debug = getoption('debug') |
|
181 |
verbosity = getoption('verbosity') |
|
182 |
||
183 |
if debug>3: |
|
184 |
import logging |
|
185 |
||
186 |
# These two lines enable debugging at httplib level (requests->urllib3->http.client) |
|
187 |
# You will see the REQUEST, including HEADERS and DATA, and RESPONSE with HEADERS but without DATA. |
|
188 |
# The only thing missing will be the response.body which is not logged. |
|
189 |
try: |
|
190 |
import http.client as http_client |
|
191 |
except ImportError: |
|
192 |
# Python 2 |
|
193 |
import httplib as http_client |
|
194 |
http_client.HTTPConnection.debuglevel = 1 |
|
195 |
||
196 |
# You must initialize logging, otherwise you'll not see debug output. |
|
197 |
logging.basicConfig() |
|
198 |
logging.getLogger().setLevel(logging.DEBUG) |
|
199 |
requests_log = logging.getLogger("requests.packages.urllib3") |
|
200 |
requests_log.setLevel(logging.DEBUG) |
|
201 |
requests_log.propagate = True |
|
202 |
||
203 |
dst = getoption('dst',None,cnv=str) |
|
204 |
try: |
|
205 |
cmd = sys.argv[1] |
|
206 |
except: |
|
207 |
cmd = 'help' |
|
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
208 |
if cmd=='env': |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
209 |
print('Environment') |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
210 |
print('===========') |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
211 |
I = list(sorted(os.environ.iteritems())) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
212 |
i = max([len(i[0]) for i in I]) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
213 |
print(('{:<%d} {}' % i).format('Key','Value')) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
214 |
fmt = '{:<%d} = {}' % i |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
215 |
for i in I: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
216 |
print(fmt.format(*i)) |
0 | 217 |
elif cmd=='info': |
4 | 218 |
recur = [fn for fn in sys.argv[2:] if fn=='--recur'] |
219 |
if recur: |
|
220 |
map(sys.argv.remove,recur) |
|
221 |
recur = True |
|
222 |
tabulate([_file_info(i) for i in _list_fs(sys.argv[2:],recur)]) |
|
0 | 223 |
elif cmd=='help': |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
224 |
print('Usage %s [test|info|env|download-[resources|packages]|upload-[resources|packages]|[packages|resources]-info] path....' % PROG) |
0 | 225 |
else: |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
226 |
pypi = PyPiRequestor(debug=debug) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
227 |
if cmd=='test': |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
228 |
status_code = pypi.login(u,p) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
229 |
if debug: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
230 |
print('status=%s' % status_code) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
231 |
elif cmd.startswith('download-'): |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
232 |
kind = cmd.split('-')[1] |
5 | 233 |
if not kind in ('resources','packages', 'caches'): |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
234 |
raise ValueError('%s: invalid download kind: %r' % (PROG,kind)) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
235 |
if dst and not os.path.isdir(dst): |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
236 |
raise ValueError('%s: %r is not a directory!' % (PROG,dst)) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
237 |
for fn in sys.argv[2:]: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
238 |
pypi.download(u,p,kind,fn,dst) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
239 |
elif cmd.endswith('-info'): |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
240 |
kind = cmd.split('-')[0] |
5 | 241 |
if not kind in ('resource','package', 'cache'): |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
242 |
raise ValueError('%s: invalid info kind: %r' % (PROG,kind)) |
5 | 243 |
subdir = getoption('subdir','',str) if kind=='cache' else None |
244 |
tabulate([i for fn in sys.argv[2:] for i in pypi.info(u,p,kind,fn,subdir)]) |
|
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
245 |
elif cmd.startswith('upload-'): |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
246 |
kind = cmd.split('-')[1] |
5 | 247 |
if not kind in ('resources','packages', 'caches'): |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
248 |
raise ValueError('%s: invalid upload kind: %r' % (PROG,kind)) |
5 | 249 |
subdir = getoption('subdir','',str) if kind=='caches' else None |
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
250 |
for pat in sys.argv[2:]: |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
251 |
for fn in glob.glob(pat): |
5 | 252 |
pypi.upload(u,p,kind[:-1],fn,subdir) |
253 |
elif cmd=='clear-cache': |
|
254 |
for fn in sys.argv[2:]: |
|
255 |
pypi.clear_cache(u,p,fn) |
|
3
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
256 |
elif cmd=='package-version': |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
257 |
tabulate([pypi.package_version(u,p,fn) for fn in sys.argv[2:]], |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
258 |
hdrs = ['Package','Version'], |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
259 |
fmtmpl8 = '{:<%d} {:>%d}', |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
260 |
cnvf = (str,str), |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
261 |
) |
dd3ccb935508
added env and package-version commands
robin <robin@reportlab.com>
parents:
2
diff
changeset
|
262 |
else: |
5 | 263 |
raise ValueError('%s: unknown command %r' % (PROG,cmd)) |
0 | 264 |
if __name__=='__main__': |
265 |
main() |