Blame


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