Blob


1 #!/usr/bin/env python3.8
3 import os
4 import re
5 import sqlite3
6 import traceback
7 from urllib.parse import unquote
9 sqlports = os.environ.get("SQLPORTS")
11 query = os.environ.get("QUERY_STRING")
12 script_path = os.environ.get("SCRIPT_NAME")
13 path = os.environ.get("PATH_INFO")
15 query_search = """
16 select webpkg_fts.pkgstem,
17 webpkg_fts.comment,
18 paths.fullpkgpath
19 from webpkg_fts
20 join _ports p on p.fullpkgpath = webpkg_fts.id
21 join _paths paths on paths.id = webpkg_fts.id
22 where webpkg_fts match ?
23 order by bm25(webpkg_fts)
24 """
26 query_by_fullpkgpath = """
27 select p.fullpkgpath,
28 pp.pkgstem,
29 pp.comment,
30 pp.pkgname,
31 d.value,
32 replace(replace(e.value, '@', ' at '), '.', ' dot '),
33 r.value,
34 pp.homepage
35 from _paths p
36 join _descr d on d.fullpkgpath = p.id
37 join _ports pp on pp.fullpkgpath = p.id
38 join _email e on e.keyref = pp.maintainer
39 left join _readme r on r.fullpkgpath = p.id
40 where p.fullpkgpath = ?
41 """
43 query_all_categories = """
44 select distinct value from categories order by value
45 """
47 query_all_in_category = """
48 select fullpkgpath from categories where value = ? order by fullpkgpath
49 """
52 def verbatim(alt, text):
53 print("```", alt)
54 for line in text.splitlines():
55 if line.startswith("```"):
56 print(" ", line)
57 else:
58 print(line)
59 print("```")
62 def printraw(text):
63 for line in text.splitlines():
64 if line.startswith(">") \
65 or line.startswith("```") \
66 or line.startswith(">") \
67 or line.startswith("#") \
68 or line.startswith("*"):
69 print(" ", line)
70 else:
71 print(line)
74 def reply(code, meta):
75 print(f"{code} {meta}\r")
78 def homepage():
79 reply(20, "text/gemini;lang=en")
80 print("# GemPKG")
81 print("")
82 print("Welcome to GemPKG,",
83 "the gemini interface for the OpenBSD ports collection.")
84 print("")
85 print(f"=> {script_path}/search/ Search for a package")
86 print(f"=> {script_path}/all/ All categories")
87 print("")
88 print(
89 "What you search will be matched against the package name (pkgstem),",
90 "comment, DESCR and maintainer.")
91 foot()
94 def nav():
95 print(f"=> {script_path}/ GemPKG")
96 print(f"=> {script_path}/search/ Search for a package")
97 print(f"=> {script_path}/all/ All Categories")
98 print("")
101 def foot():
102 print()
103 print()
104 print("---")
105 print(
106 "All the data is provided by sqlports",
107 "and is relative to OpenBSD-CURRENT."
111 def fts_escape_word(s):
112 return '"' + s.replace('"', '""') + '"'
115 def fts_escape(s):
116 return ' '.join(fts_escape_word(i) for i in s.split())
119 def searchpage():
120 global query
122 if not query:
123 reply(10, "search for a package")
124 return
126 query = unquote(query)
128 # try the raw query. If it isn't a valid fts string (i.e. "c++"),
129 # escape it and retry
130 try:
131 cursor = conn.execute(query_search, (query, ))
132 except BaseException:
133 cursor = conn.execute(query_search, (fts_escape(query), ))
135 reply(20, "text/gemini;lang=en")
136 nav()
137 print(f"# packages matching {query}\n")
138 for row in cursor:
139 stem, comment, fullpkgpath = row
140 print(f"=> {script_path}/{fullpkgpath}/ {stem}: {comment}")
141 foot()
144 def allcatspage():
145 cursor = conn.execute(query_all_categories)
146 reply(20, "text/gemini;lang=en")
147 nav()
148 print("# All categories")
149 for row in cursor:
150 (fullpkgpath, ) = row
151 print(f"=> {script_path}/{fullpkgpath}/ {fullpkgpath}")
152 foot()
155 def bycatpage():
156 cursor = conn.execute(query_all_in_category, (path, ))
157 reply(20, "text/gemini;lang=en")
158 nav()
159 print(f"# All ports in category {path}")
160 for row in cursor:
161 (fullpkgpath, ) = row
162 if fullpkgpath.find(",") != -1: # skip flavors
163 continue
164 print(f"=> {script_path}/{fullpkgpath}/ {fullpkgpath}")
165 foot()
168 def portpage(row):
169 fullpkgpath, stem, comment, pkgname, descr, maintainer, readme, www = row
170 reply(20, "text/gemini;lang=en")
171 nav()
172 print(f"# {path}", "v" + re.sub(r".*-", "", pkgname))
173 print(f"``` Command to execute in order to install the package {stem}")
174 print(f"# pkg_add {stem}")
175 print("```")
176 print("")
177 print(f"> {comment}")
178 print("")
179 print(f"=> https://cvsweb.openbsd.org/ports/{fullpkgpath} CVS web")
180 if www:
181 print(f"=> {www} WWW")
182 print("")
183 print("Maintainer:", maintainer)
184 print("")
185 print("## Description")
186 verbatim(f"{stem} description", descr)
187 print("")
188 if readme:
189 print("## Readme")
190 verbatim(f"README for {stem}", readme)
191 foot()
194 if not path or path == '/':
195 homepage()
196 exit(0)
198 if not path.endswith("/"):
199 reply(31, f"{script_path}{path}/")
200 exit(0)
201 # drop the leading and trailing /
202 path = path.strip("/")
204 try:
205 conn = sqlite3.connect(sqlports)
207 if path == 'search':
208 searchpage()
209 elif path == 'all':
210 allcatspage()
211 else:
212 cursor = conn.execute(query_by_fullpkgpath, (path, ))
213 row = cursor.fetchone()
214 if not row:
215 bycatpage()
216 else:
217 portpage(row)
218 except SystemExit:
219 pass
220 except BaseException:
221 reply(50, "internal server error")
222 traceback.print_exc()
223 finally:
224 conn.close()