Skip to content

Commit 6c7db90

Browse files
committed
MVP
1 parent b756434 commit 6c7db90

12 files changed

+281
-0
lines changed

Dockerfile

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Use the official lightweight Python image.
2+
# https://hub.docker.com/_/python
3+
FROM python:3.10-slim
4+
5+
# Allow statements and log messages to immediately appear in the Knative logs
6+
ENV PYTHONUNBUFFERED True
7+
8+
# Copy local code to the container image.
9+
ENV APP_HOME /app
10+
WORKDIR $APP_HOME
11+
COPY . ./
12+
13+
# Install production dependencies.
14+
RUN pip install --no-cache-dir -r requirements.txt
15+
16+
# Run the web service on container startup. Here we use the gunicorn
17+
# webserver, with one worker process and 8 threads.
18+
# For environments with multiple CPU cores, increase the number of workers
19+
# to be equal to the cores available.
20+
# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
21+
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

docker-compose.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: "3.9"
2+
services:
3+
web:
4+
build: .
5+
ports:
6+
- "80:8080"
7+
environment:
8+
PORT: 8080

main.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import os
2+
3+
from flask import Flask, render_template, redirect, request, abort
4+
import requests
5+
import urllib.parse
6+
from io import BytesIO
7+
import zipfile
8+
9+
10+
app = Flask(__name__)
11+
12+
# Lightweight datastore ;)
13+
dists = {}
14+
15+
16+
@app.route("/")
17+
def index():
18+
if project := request.args.get("project"):
19+
return redirect(f"/project/{ project }")
20+
return render_template("index.html")
21+
22+
23+
@app.route("/project/<project_name>/")
24+
def versions(project_name):
25+
resp = requests.get(f"https://pypi.org/pypi/{project_name}/json")
26+
if resp.status_code != 200:
27+
return abort(404)
28+
29+
version_urls = ["." + "/" + version for version in resp.json()["releases"].keys()]
30+
return render_template("links.html", links=version_urls, h2=project_name)
31+
32+
33+
@app.route("/project/<project_name>/<version>/")
34+
def distributions(project_name, version):
35+
resp = requests.get(f"https://pypi.org/pypi/{project_name}/{version}/json")
36+
if resp.status_code != 200:
37+
return abort(404)
38+
39+
dist_urls = [
40+
"." + urllib.parse.urlparse(release["url"]).path + "/"
41+
for release in resp.json()["releases"][version]
42+
]
43+
return render_template(
44+
"links.html", links=dist_urls, h2=f"{project_name}=={version}"
45+
)
46+
47+
48+
def _get_dist(first, second, rest, distname):
49+
if distname in dists:
50+
return dists[distname]
51+
url = f"https://files.pythonhosted.org/packages/{first}/{second}/{rest}/{distname}"
52+
resp = requests.get(url)
53+
f = BytesIO()
54+
f.write(resp.content)
55+
input_zip = zipfile.ZipFile(f)
56+
dists[distname] = input_zip
57+
return input_zip
58+
59+
60+
@app.route(
61+
"/project/<project_name>/<version>/packages/<first>/<second>/<rest>/<distname>/"
62+
)
63+
def distribution(project_name, version, first, second, rest, distname):
64+
input_zip = _get_dist(first, second, rest, distname)
65+
file_urls = ["./" + filename for filename in input_zip.namelist()]
66+
67+
return render_template(
68+
"links.html",
69+
links=file_urls,
70+
h2=f"{project_name}=={version}",
71+
h3=distname,
72+
)
73+
74+
75+
@app.route(
76+
"/project/<project_name>/<version>/packages/<first>/<second>/<rest>/<distname>/<path:filepath>"
77+
)
78+
def file(project_name, version, first, second, rest, distname, filepath):
79+
input_zip = _get_dist(first, second, rest, distname)
80+
return render_template(
81+
"code.html",
82+
code=input_zip.read(filepath).decode(),
83+
h2=f"{project_name}=={version}",
84+
h3=distname,
85+
h4=filepath,
86+
)
87+
88+
89+
@app.route("/_health/")
90+
def health():
91+
return "OK"
92+
93+
94+
if __name__ == "__main__":
95+
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))

requirements.in

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Flask
2+
gunicorn
3+
requests

requirements.txt

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#
2+
# This file is autogenerated by pip-compile with python 3.10
3+
# To update, run:
4+
#
5+
# pip-compile --allow-unsafe --generate-hashes --output-file=requirements.txt requirements.in
6+
#
7+
certifi==2022.5.18.1 \
8+
--hash=sha256:9c5705e395cd70084351dd8ad5c41e65655e08ce46f2ec9cf6c2c08390f71eb7 \
9+
--hash=sha256:f1d53542ee8cbedbe2118b5686372fb33c297fcd6379b050cca0ef13a597382a
10+
# via requests
11+
charset-normalizer==2.0.12 \
12+
--hash=sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597 \
13+
--hash=sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df
14+
# via requests
15+
click==8.1.3 \
16+
--hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
17+
--hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
18+
# via flask
19+
flask==2.1.2 \
20+
--hash=sha256:315ded2ddf8a6281567edb27393010fe3406188bafbfe65a3339d5787d89e477 \
21+
--hash=sha256:fad5b446feb0d6db6aec0c3184d16a8c1f6c3e464b511649c8918a9be100b4fe
22+
# via -r requirements.in
23+
gunicorn==20.1.0 \
24+
--hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \
25+
--hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8
26+
# via -r requirements.in
27+
idna==3.3 \
28+
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \
29+
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d
30+
# via requests
31+
itsdangerous==2.1.2 \
32+
--hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
33+
--hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
34+
# via flask
35+
jinja2==3.1.2 \
36+
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
37+
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
38+
# via flask
39+
markupsafe==2.1.1 \
40+
--hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
41+
--hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
42+
--hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
43+
--hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
44+
--hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
45+
--hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
46+
--hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
47+
--hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
48+
--hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
49+
--hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
50+
--hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
51+
--hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
52+
--hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
53+
--hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
54+
--hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
55+
--hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
56+
--hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
57+
--hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
58+
--hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
59+
--hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
60+
--hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
61+
--hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
62+
--hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
63+
--hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
64+
--hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
65+
--hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
66+
--hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
67+
--hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
68+
--hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
69+
--hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
70+
--hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
71+
--hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
72+
--hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
73+
--hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
74+
--hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
75+
--hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
76+
--hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
77+
--hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
78+
--hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
79+
--hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
80+
# via jinja2
81+
requests==2.27.1 \
82+
--hash=sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61 \
83+
--hash=sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d
84+
# via -r requirements.in
85+
urllib3==1.26.9 \
86+
--hash=sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14 \
87+
--hash=sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e
88+
# via requests
89+
werkzeug==2.1.2 \
90+
--hash=sha256:1ce08e8093ed67d638d63879fd1ba3735817f7a80de3674d293f5984f25fb6e6 \
91+
--hash=sha256:72a4b735692dd3135217911cbeaa1be5fa3f62bffb8745c5215420a03dc55255
92+
# via flask
93+
94+
# The following packages are considered to be unsafe in a requirements file:
95+
setuptools==62.3.2 \
96+
--hash=sha256:68e45d17c9281ba25dc0104eadd2647172b3472d9e01f911efa57965e8d51a36 \
97+
--hash=sha256:a43bdedf853c670e5fed28e5623403bad2f73cf02f9a2774e91def6bda8265a7
98+
# via gunicorn

run.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
docker build . -t inspector
2+
docker run -e PORT=8080 -p 80:8080 -it inspector

static/prism.css

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)