|
| 1 | +import json |
| 2 | +import logging |
| 3 | + |
| 4 | +from flask import render_template, request, make_response, url_for |
| 5 | +from flask.helpers import send_file |
| 6 | +from tornado.util import ObjectDict |
| 7 | +from werkzeug.exceptions import NotFound |
| 8 | + |
| 9 | +from repocache.modular_view import ModularView, expose |
| 10 | +from repocache.vendor import Vendor |
| 11 | + |
| 12 | +logger = logging.getLogger(__name__) |
| 13 | + |
| 14 | + |
| 15 | +def create_upstream(name, section): |
| 16 | + '''create dict from section of ConfigParser''' |
| 17 | + tail = name[len('rust.upstream.'):] |
| 18 | + return ObjectDict(name=tail, **section) |
| 19 | + |
| 20 | + |
| 21 | +# RUSTUP_DIST_SERVER=https://static.rust-lang.org |
| 22 | +# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
| 23 | + |
| 24 | + |
| 25 | +class RustupRepository(ModularView, Vendor): |
| 26 | + @expose("/") |
| 27 | + def index(self): |
| 28 | + '''TODO: list cached packages''' |
| 29 | + return self.upstreams |
| 30 | + |
| 31 | + @expose("/index.html") |
| 32 | + def index_html(self): |
| 33 | + return render_template('rust/index.html') |
| 34 | + |
| 35 | + @expose("/rustup.sh") |
| 36 | + def sh(self): |
| 37 | + body = render_template('rust/rustup.sh') |
| 38 | + |
| 39 | + resp = make_response(body) |
| 40 | + resp.headers.set('Content-Type', 'text/plain') |
| 41 | + return resp |
| 42 | + |
| 43 | + @expose("/<string:un>") |
| 44 | + def root(self, un): |
| 45 | + ud = self.upstreams.get(un) |
| 46 | + if not ud: |
| 47 | + raise NotFound |
| 48 | + return ud |
| 49 | + |
| 50 | + @expose("/<string:un>/<path:filepath>") |
| 51 | + def file(self, un, filepath): |
| 52 | + # http://192.168.1.2:5000/rust/default/dist/channel-rust-stable.toml.sha256 |
| 53 | + ud = self.upstreams.get(un) |
| 54 | + if ud is None: |
| 55 | + raise NotFound |
| 56 | + |
| 57 | + ud = ObjectDict(ud) |
| 58 | + url = ud.url |
| 59 | + del ud['url'] |
| 60 | + |
| 61 | + f = self.fetch_or_load_binary( |
| 62 | + f'rust/{un}/{filepath}', |
| 63 | + fetch_handle=lambda: self.fetch(f'{url}/{filepath}', **ud), |
| 64 | + ) |
| 65 | + |
| 66 | + if filepath.endswith('.xz'): |
| 67 | + mimetype = 'application/x-tar' |
| 68 | + else: |
| 69 | + mimetype = 'application/octet-stream' |
| 70 | + return send_file(f, mimetype=mimetype) |
| 71 | + |
| 72 | + @expose("/<string:un>/-/v1/search") |
| 73 | + def search(self, un): |
| 74 | + ud = self.upstreams.get(un) |
| 75 | + if ud is None: |
| 76 | + raise NotFound |
| 77 | + |
| 78 | + resp = self.fetch(f'{ud.url}/-/v1/search', params=request.args, **ud) |
| 79 | + return resp.content |
| 80 | + |
| 81 | + # -/rust/v1/security/audits/quick |
| 82 | + @expose("/<string:un>/-/<path:left>", methods=('POST',)) |
| 83 | + def other(self, un, left): |
| 84 | + print('post:', request) |
| 85 | + return '' |
| 86 | + |
| 87 | + def __init__(self, config): |
| 88 | + ModularView.__init__( |
| 89 | + self, |
| 90 | + name='rust', |
| 91 | + url_prefix='/rust', |
| 92 | + ) |
| 93 | + |
| 94 | + self.upstreams = {} # upstream name => Dict |
| 95 | + |
| 96 | + for section_name in config: |
| 97 | + if section_name.startswith('rust.upstream.'): |
| 98 | + u = create_upstream(section_name, config[section_name]) |
| 99 | + self.upstreams[u.name] = u |
| 100 | + |
| 101 | + def _fetch(self, un, path): |
| 102 | + ud = self.upstreams.get(un) |
| 103 | + |
| 104 | + if ud is None: |
| 105 | + raise NotFound |
| 106 | + |
| 107 | + url = '{}/{}'.format( |
| 108 | + ud.url, |
| 109 | + path, |
| 110 | + ) |
| 111 | + |
| 112 | + ud = ObjectDict(ud) |
| 113 | + del ud['url'] |
| 114 | + |
| 115 | + return self.fetch(url, **ud) |
| 116 | + |
| 117 | + def ensure_package(self, un, name): |
| 118 | + # TODO: local |
| 119 | + jd = self.fetch_or_load_json( |
| 120 | + f'rust/{un}/{name}.json', |
| 121 | + fetch_handle=lambda: self._fetch(un, name), |
| 122 | + ) |
| 123 | + |
| 124 | + # replace `dist.tarball` as local url |
| 125 | + for v, vd in jd.get('versions').items(): |
| 126 | + # if un in |
| 127 | + ud = self.upstreams.get(un) |
| 128 | + prefix = f'{ud.url}/{name}/-/' |
| 129 | + pos = vd.dist.tarball.find(prefix) |
| 130 | + if pos == 0: |
| 131 | + filename = vd.dist.tarball[pos + len(prefix):] |
| 132 | + vd.dist._url = vd.dist.tarball |
| 133 | + vd.dist.tarball = url_for( |
| 134 | + 'npm.package_file', |
| 135 | + un=un, |
| 136 | + name=name, |
| 137 | + filename=filename, |
| 138 | + _external=True, |
| 139 | + ) |
| 140 | + return jd |
0 commit comments