|
|
lawn-mower.py - gopher-lawn - The gopher lawn gopher directory project. |
|
|
 |
git clone git://bitreich.org/gopher-lawn/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/gopher-lawn/ (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
|
--- |
|
|
|
lawn-mower.py (6722B) |
|
|
|
--- |
|
|
|
1 #!/usr/bin/env python |
|
|
|
2 # coding=utf-8 |
|
|
|
3 # |
|
|
|
4 # © 2020 Christoph Lohmann <20h@r-36.net> |
|
|
|
5 # |
|
|
|
6 # This file is published under the terms of the GPLv3. |
|
|
|
7 # |
|
|
|
8 |
|
|
|
9 import os |
|
|
|
10 import sys |
|
|
|
11 import getopt |
|
|
|
12 |
|
|
|
13 def usage(app): |
|
|
|
14 app = os.path.basename(app) |
|
|
|
15 print("usage: %s [-h] [-b basedir] [-c categorydir] " \ |
|
|
|
16 "[-s selectorbase]" \ |
|
|
|
17 % (app), file=sys.stderr) |
|
|
|
18 sys.exit(1) |
|
|
|
19 |
|
|
|
20 def main(args): |
|
|
|
21 try: |
|
|
|
22 opts, largs = getopt.getopt(args[1:], "hc:s:") |
|
|
|
23 except getopt.GetoptError as err: |
|
|
|
24 print(str(err)) |
|
|
|
25 usage(args[0]) |
|
|
|
26 |
|
|
|
27 basedir = "./" |
|
|
|
28 categorysubdir = "/c" |
|
|
|
29 selectorbase = "/lawn" |
|
|
|
30 for o, a in opts: |
|
|
|
31 if o == "-h": |
|
|
|
32 usage(args[0]) |
|
|
|
33 elif o == "-b": |
|
|
|
34 basedir = a |
|
|
|
35 elif o == "-c": |
|
|
|
36 categorysubdir = a |
|
|
|
37 elif o == "-s": |
|
|
|
38 selectorbase = a |
|
|
|
39 else: |
|
|
|
40 assert False, "unhandled option" |
|
|
|
41 |
|
|
|
42 categorydir = "%s%s" % (basedir, categorysubdir) |
|
|
|
43 categoryselector = "%s%s" % (selectorbase, categorysubdir) |
|
|
|
44 |
|
|
|
45 filelist = largs |
|
|
|
46 if len(largs) == 0: |
|
|
|
47 filelist = ["/dev/stdin"] |
|
|
|
48 |
|
|
|
49 dbobjs = [] |
|
|
|
50 dbobj = {} |
|
|
|
51 for f in filelist: |
|
|
|
52 dbobj = {} |
|
|
|
53 dbkey = None |
|
|
|
54 dbval = None |
|
|
|
55 with open(f, "r") as fd: |
|
|
|
56 while True: |
|
|
|
57 line = fd.readline() |
|
|
|
58 # EOF |
|
|
|
59 if line == "": |
|
|
|
60 #print("EOF") |
|
|
|
61 if dbobj != {}: |
|
|
|
62 dbobjs.append(dbobj) |
|
|
|
63 dbobj = {} |
|
|
|
64 break |
|
|
|
65 |
|
|
|
66 if line[0] == "#": |
|
|
|
67 continue |
|
|
|
68 |
|
|
|
69 line = line.rstrip() |
|
|
|
70 #print("line = '%s'" % (line)) |
|
|
|
71 if line == "": |
|
|
|
72 #print("line empty") |
|
|
|
73 if dbobj != {}: |
|
|
|
74 dbobjs.append(dbobj) |
|
|
|
75 dbobj = {} |
|
|
|
76 continue |
|
|
|
77 |
|
|
|
78 # Multi line value. |
|
|
|
79 if line[0] in ["\f", "\t", "\v", " "]: |
|
|
|
80 #print("multi-line") |
|
|
|
81 if dbkey != None: |
|
|
|
82 dbobj[dbkey] += " %s" % (line.lstrip()) |
|
|
|
83 continue |
|
|
|
84 |
|
|
|
85 try: |
|
|
|
86 (dbkey, dbval) = line.split(":", 1) |
|
|
|
87 except ValueError: |
|
|
|
88 sys.write(sys.stderr, "'%s' is invalid line at %s.\n" \ |
|
|
|
89 % (line, f)) |
|
|
|
90 continue |
|
|
|
91 |
|
|
|
92 #print("dbkey = %s; dbval = %s" % (dbkey, dbval)) |
|
|
|
93 |
|
|
|
94 dbkey = dbkey.strip().lower() |
|
|
|
95 dbval = dbval.lstrip() |
|
|
|
96 dbobj[dbkey] = dbval |
|
|
|
97 |
|
|
|
98 rootcategory = None |
|
|
|
99 categories = {} |
|
|
|
100 wantedcategories = {} |
|
|
|
101 wantedkeywords = {} |
|
|
|
102 keywords = {} |
|
|
|
103 links = [] |
|
|
|
104 noncategories = [] |
|
|
|
105 nonkeywords = [] |
|
|
|
106 for obj in dbobjs: |
|
|
|
107 if "category" in obj: |
|
|
|
108 ocats = obj["category"].split(", ") |
|
|
|
109 if len(ocats) == 0 or ocats[0] == '': |
|
|
|
110 noncategories.append(obj) |
|
|
|
111 obj["category"] = ocats |
|
|
|
112 for ocat in ocats: |
|
|
|
113 if ocat in wantedcategories: |
|
|
|
114 wantedcategories[ocat].append(obj) |
|
|
|
115 else: |
|
|
|
116 wantedcategories[ocat] = [obj] |
|
|
|
117 if "keywords" in obj: |
|
|
|
118 okeyws = obj["keywords"].split(", ") |
|
|
|
119 if len(okeyws) == 0 or okeyws[0] == '': |
|
|
|
120 nonkeywords.append(obj) |
|
|
|
121 for okeyw in okeyws: |
|
|
|
122 if okeyw in wantedkeywords: |
|
|
|
123 wantedkeywords[okeyw].append(obj) |
|
|
|
124 else: |
|
|
|
125 wantedkeywords[okeyw] = [obj] |
|
|
|
126 if obj["type"] == "category": |
|
|
|
127 if obj["parent"] == "none": |
|
|
|
128 rootcategory = obj |
|
|
|
129 if obj["name"] in categories: |
|
|
|
130 print("Duplication of category '%s'." \ |
|
|
|
131 % (obj["name"])) |
|
|
|
132 sys.exit(1) |
|
|
|
133 obj["links"] = [] |
|
|
|
134 obj["children"] = [] |
|
|
|
135 categories[obj["name"]] = obj |
|
|
|
136 else: |
|
|
|
137 links.append(obj) |
|
|
|
138 |
|
|
|
139 #print(categories.keys()) |
|
|
|
140 keywords = wantedkeywords |
|
|
|
141 #print(wantedkeywords.keys()) |
|
|
|
142 #print(keywords.keys()) |
|
|
|
143 #print(wantedcategories.keys()) |
|
|
|
144 #print(noncategories) |
|
|
|
145 #print(nonkeywords) |
|
|
|
146 |
|
|
|
147 for link in links: |
|
|
|
148 if "category" in link: |
|
|
|
149 for cate in link["category"]: |
|
|
|
150 categories[cate]["links"].append(link) |
|
|
|
151 |
|
|
|
152 for key in categories.keys(): |
|
|
|
153 parent = categories[key]["parent"] |
|
|
|
154 if parent in categories.keys(): |
|
|
|
155 categories[parent]["children"].append(key) |
|
|
|
156 else: |
|
|
|
157 if parent != "none": |
|
|
|
158 print("Undefined parent '%s' used in category '%s'." \ |
|
|
|
159 % (parent, key)) |
|
|
|
160 |
|
|
|
161 for obj in noncategories: |
|
|
|
162 print("'%s' has no categories defined." \ |
|
|
|
163 % (obj["linkname"])) |
|
|
|
164 for obj in nonkeywords: |
|
|
|
165 print("'%s' has no keywords defined." \ |
|
|
|
166 % (obj["linkname"])) |
|
|
|
167 |
|
|
|
168 def linktype2gopher(link): |
|
|
|
169 linktype = link["type"] |
|
|
|
170 if linktype == "link": |
|
|
|
171 if link["selector"].startswith("URL:"): |
|
|
|
172 return "h" |
|
|
|
173 return "1" |
|
|
|
174 elif linktype == "text": |
|
|
|
175 return "0" |
|
|
|
176 elif linktype == "cso": |
|
|
|
177 return "2" |
|
|
|
178 elif linktype == "error": |
|
|
|
179 return "3" |
|
|
|
180 elif linktype == "uuencoded": |
|
|
|
181 return "6" |
|
|
|
182 elif linktype == "search": |
|
|
|
183 return "7" |
|
|
|
184 elif linktype == "telnet": |
|
|
|
185 return "8" |
|
|
|
186 else: |
|
|
|
187 return "9" |
|
|
|
188 |
|
|
|
189 def printdescription(desc): |
|
|
|
190 maxlinelen = 70 |
|
|
|
191 if len(desc) <= maxlinelen: |
|
|
|
192 return "%s\n" % (desc) |
|
|
|
193 |
|
|
|
194 rtext = "" |
|
|
|
195 adesc = desc |
|
|
|
196 while len(adesc) > maxlinelen: |
|
|
|
197 pline = "" |
|
|
|
198 i = 70 |
|
|
|
199 while i > maxlinelen-20: |
|
|
|
200 if adesc[i] in [" ", "\t", "\v", "\f", "-"]: |
|
|
|
201 rtext += "%s\n" % (adesc[:i]) |
|
|
|
202 adesc = adesc[i+1:] |
|
|
|
203 break |
|
|
|
204 i -= 1 |
|
|
|
205 if i <= maxlinelen-20: |
|
|
|
206 rtext += "%s\n" % (adesc[:maxlinelen]) |
|
|
|
207 adesc = adesc[maxlinelen:] |
|
|
|
208 rtext += "%s\n" % (adesc) |
|
|
|
209 |
|
|
|
210 return rtext |
|
|
|
211 |
|
|
|
212 def printlink(link): |
|
|
|
213 try: |
|
|
|
214 rtext = "[%s|%s|%s|%s|%s]\n" \ |
|
|
|
215 % (linktype2gopher(link),\ |
|
|
|
216 link["linkname"],\ |
|
|
|
217 link["selector"],\ |
|
|
|
218 link["host"],\ |
|
|
|
219 link["port"]) |
|
|
|
220 except KeyError: |
|
|
|
221 print("Error printing link in: %s" % (link)) |
|
|
|
222 return "" |
|
|
|
223 |
|
|
|
224 if "description" in link: |
|
|
|
225 rtext += printdescription(link["description"]) |
|
|
|
226 rtext += "\n" |
|
|
|
227 |
|
|
|
228 return rtext |
|
|
|
229 |
|
|
|
230 def printcategory(category, basedir): |
|
|
|
231 if "description" in category: |
|
|
|
232 name = "%s - %s" \ |
|
|
|
233 % (category["linkname"], \ |
|
|
|
234 category["description"]) |
|
|
|
235 else: |
|
|
|
236 name = category["linkname"] |
|
|
|
237 return "[1|%s|%s|%s|%s]\n" \ |
|
|
|
238 % (name,\ |
|
|
|
239 "%s/%s.gph" % (basedir, category["name"]),\ |
|
|
|
240 "server",\ |
|
|
|
241 "port") |
|
|
|
242 |
|
|
|
243 def mkcategory(category, cdir, csdir, tmplfile="category.gph.tmpl"): |
|
|
|
244 outfilename = tmplfile.replace(".tmpl", "") |
|
|
|
245 if "category" in tmplfile: |
|
|
|
246 outfilename = outfilename.replace("category",\ |
|
|
|
247 category["name"]) |
|
|
|
248 |
|
|
|
249 tmplfd = open(tmplfile, "r") |
|
|
|
250 try: |
|
|
|
251 outfd = open("%s/%s" % (cdir, outfilename), "x") |
|
|
|
252 except FileExistsError: |
|
|
|
253 outfd = open("%s/%s" % (cdir, outfilename), "w") |
|
|
|
254 |
|
|
|
255 line = "a" |
|
|
|
256 while len(line) > 0: |
|
|
|
257 line = tmplfd.readline() |
|
|
|
258 if "C_A_T_E_G_O_R_Y" in line: |
|
|
|
259 if len(category["links"]) > 0: |
|
|
|
260 line = line.replace("C_A_T_E_G_O_R_Y", \ |
|
|
|
261 category["title"]) |
|
|
|
262 outfd.write(line) |
|
|
|
263 if "description" in category: |
|
|
|
264 outfd.write(printdescription(\ |
|
|
|
265 category["description"])) |
|
|
|
266 outfd.write("\n") |
|
|
|
267 for link in category["links"]: |
|
|
|
268 outfd.write(printlink(link)) |
|
|
|
269 elif "C_A_T_E_G_O_R_I_E_S" in line: |
|
|
|
270 if len(category["children"]) > 0: |
|
|
|
271 outfd.write(line) |
|
|
|
272 for cate in category["children"]: |
|
|
|
273 outfd.write(\ |
|
|
|
274 printcategory(\ |
|
|
|
275 categories[cate],\ |
|
|
|
276 csdir)) |
|
|
|
277 else: |
|
|
|
278 outfd.write(line) |
|
|
|
279 |
|
|
|
280 tmplfd.close() |
|
|
|
281 outfd.close() |
|
|
|
282 |
|
|
|
283 mkcategory(rootcategory, basedir, categoryselector, "index.gph.tmpl") |
|
|
|
284 for c in categories.keys(): |
|
|
|
285 mkcategory(categories[c], categorydir, categoryselector,\ |
|
|
|
286 "category.gph.tmpl") |
|
|
|
287 return 0 |
|
|
|
288 |
|
|
|
289 if __name__ == "__main__": |
|
|
|
290 sys.exit(main(sys.argv)) |
|
|
|
291 |
|