lawn-mower.py - gopher-lawn - The gopher lawn gopher directory project.
 (HTM) 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