ship it
This commit is contained in:
commit
d43d0646cd
3 changed files with 145 additions and 0 deletions
11
Dockerfile
Normal file
11
Dockerfile
Normal file
|
@ -0,0 +1,11 @@
|
|||
FROM reg.zknt.org/zknt/python:3.6.6-r0
|
||||
|
||||
COPY requirements.txt /app/requirements.txt
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache gcc libxml2 libxslt libxml2-dev musl-dev libxslt-dev python3-dev && pip3 install -r requirements.txt && apk del gcc libxml2-dev musl-dev libxslt-dev python3-dev
|
||||
|
||||
COPY . /app
|
||||
ENV FLASK_APP=app.py
|
||||
VOLUME /data
|
||||
EXPOSE 5000
|
||||
ENTRYPOINT flask run --host=0.0.0.0
|
128
app.py
Normal file
128
app.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
import dbm
|
||||
import json
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from flask import Flask
|
||||
|
||||
|
||||
class Store:
|
||||
def __init__(self, dbo):
|
||||
self.db = dbo
|
||||
|
||||
def add_version(self, pkg, version, bdate, branch='v3.8', arch='x86_64'):
|
||||
pkg_key = json.dumps((pkg, branch, arch))
|
||||
versions = json.loads(self.db.get(pkg_key, "{}"))
|
||||
if bdate not in versions:
|
||||
versions[bdate] = version
|
||||
self.db[pkg_key] = json.dumps(versions)
|
||||
|
||||
def get_feed(self, pkgs=None, branch='v3.8', arch='x86_64'):
|
||||
items = []
|
||||
if not pkgs:
|
||||
pkgs = ['bash']
|
||||
for pkg in pkgs:
|
||||
pkg_key = json.dumps((pkg, branch, arch))
|
||||
items = items + [(pkg, x[0], x[1]) for x in json.loads(self.db.get(pkg_key, "{}")).items()]
|
||||
return gen_feed(items)
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
db = dbm.open('/data/cache', 'c')
|
||||
pkg_store = Store(db)
|
||||
|
||||
|
||||
def get_release(pkg, branch="v3.8", arch="x86_64"):
|
||||
req = requests.get(
|
||||
"https://pkgs.alpinelinux.org/packages?name={}&branch={}&arch={}".format(
|
||||
pkg,
|
||||
branch,
|
||||
arch,
|
||||
)
|
||||
)
|
||||
soup = BeautifulSoup(req.text, 'html.parser')
|
||||
if not soup.find_all("td", class_="version"):
|
||||
return None
|
||||
if branch == "edge": # literal edge case -_-
|
||||
ver_link = soup.find_all("td", class_="version")[0].contents[1]
|
||||
version = ver_link.find_all("a")[0].contents[0]
|
||||
else:
|
||||
version = soup.find_all("td", class_="version")[0].contents[0]
|
||||
bdate = soup.find_all("td", class_="bdate")[0].contents[0]
|
||||
return (version, bdate)
|
||||
|
||||
|
||||
def gen_feed(items):
|
||||
from feedgen.feed import FeedGenerator
|
||||
from slugify import slugify
|
||||
feedgen = FeedGenerator()
|
||||
feedgen.id('https://alprss.zknt.org/feed/1')
|
||||
feedgen.title('alpine packagefeed')
|
||||
feedgen.link(href='https://alprss.zknt.org/', rel="alternate")
|
||||
feedgen.description('packages')
|
||||
for item in items:
|
||||
feedentry = feedgen.add_entry()
|
||||
feedentry.id('https://alprss.zknt.org/{}/{}-{}'.format(slugify(item[0]), slugify(item[2]), slugify(item[1])))
|
||||
feedentry.title("{} version: {}".format(item[0], item[2]))
|
||||
feedentry.published(item[1] + ' UTC')
|
||||
return feedgen
|
||||
|
||||
|
||||
@app.route('/rss')
|
||||
def handle():
|
||||
""" Dump all known packags to feed. """
|
||||
for pkg in ["bash"]:
|
||||
try:
|
||||
version, bdate = get_release(pkg)
|
||||
pkg_store.add_version(pkg, version, bdate)
|
||||
except TypeError:
|
||||
pass
|
||||
return pkg_store.get_feed().rss_str()
|
||||
|
||||
|
||||
@app.route('/rss/<pkglist>')
|
||||
def handle_list(pkglist):
|
||||
for pkg in pkglist.split(','):
|
||||
try:
|
||||
version, bdate = get_release(pkg)
|
||||
pkg_store.add_version(pkg, version, bdate)
|
||||
except TypeError:
|
||||
pass
|
||||
return pkg_store.get_feed(pkglist.split(',')).rss_str()
|
||||
|
||||
|
||||
@app.route('/rss/<branch>/<arch>/<pkglist>')
|
||||
def handle_params(branch, arch, pkglist):
|
||||
for pkg in pkglist.split(','):
|
||||
try:
|
||||
version, bdate = get_release(pkg, branch=branch, arch=arch)
|
||||
pkg_store.add_version(pkg, version, bdate, branch, arch)
|
||||
except TypeError:
|
||||
pass
|
||||
return pkg_store.get_feed(pkglist.split(','), branch, arch).rss_str()
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
import markdown
|
||||
return markdown.markdown("""
|
||||
# alprss
|
||||
|
||||
Provide alpine package search results as RSS feed.
|
||||
|
||||
## Usage:
|
||||
|
||||
GET /rss/your,package,list
|
||||
|
||||
This will combine results for the packages `your`, `package` and `list`.
|
||||
Requesting information on non-existant packages will result in empty output.
|
||||
Search is restricted to alpines latest stable branch, and arch x86_64 by default.
|
||||
|
||||
GET /rss/branch/arch/your,package,list
|
||||
|
||||
Same as above, but queries supplied alpine branch and arch.
|
||||
|
||||
### Example:
|
||||
|
||||
curl https://alprss.zknt.org/rss/vim,emacs
|
||||
""")
|
6
requirements.txt
Normal file
6
requirements.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
beautifulsoup4==4.6.3
|
||||
feedgen==0.7.0
|
||||
requests==2.20.1
|
||||
python-slugify==1.2.6
|
||||
Flask==1.0.2
|
||||
Markdown==3.0.1
|
Loading…
Reference in a new issue