This commit is contained in:
chris 2018-12-12 19:57:03 +01:00
commit d43d0646cd
3 changed files with 145 additions and 0 deletions

11
Dockerfile Normal file
View 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
View 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
View 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