lawn-mower.py - gopher-lawn - The gopher lawn gopher directory project. | |
git clone git://bitreich.org/gopher-lawn/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhf… | |
Log | |
Files | |
Refs | |
Tags | |
--- | |
lawn-mower.py (6722B) | |
--- | |
1 #!/usr/bin/env python | |
2 # coding=utf-8 | |
3 # | |
4 # © 2020 Christoph Lohmann <[email protected]> | |
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" % … | |
83 continue | |
84 | |
85 try: | |
86 (dbkey, dbval) = line.split(":",… | |
87 except ValueError: | |
88 sys.write(sys.stderr, "'%s' is i… | |
89 % (line, f)) | |
90 continue | |
91 | |
92 #print("dbkey = %s; dbval = %s" % (dbkey… | |
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(ob… | |
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 cat… | |
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.tmp… | |
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… | |
261 category["title"… | |
262 outfd.write(line) | |
263 if "description" in category: | |
264 outfd.write(printdescrip… | |
265 category["descri… | |
266 outfd.write("\n") | |
267 for link in category["links"]: | |
268 outfd.write(printlink(li… | |
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.t… | |
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 |