Home
lawn-mower.py - gopher-lawn - The gopher lawn gopher directory project. HTML git clone git://bitreich.org/gopher-lawn/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/gopher-lawn/ DIR Log DIR Files DIR Refs DIR 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