PageRenderTime 23ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/Prophet/Debian/__init__.py

https://github.com/bvtrach/menumaker-awesome
Python | 338 lines | 291 code | 42 blank | 5 comment | 38 complexity | 3c01fb47fa5428cc24ee4f680b7817c6 MD5 | raw file
  1. import re, os.path, glob, fnmatch, Prophet
  2. from Paths import ValidPathSet as PS
  3. from Keywords import Keyword as Kw, Set as KwS
  4. from Prophet import NotSet
  5. from Prophet.Categories import *
  6. from Prophet import msg, verbose
  7. class DebianSet(PS) :
  8. def adopt(self, path) :
  9. path = super(DebianSet, self).adopt(path)
  10. if len(glob.glob(os.path.join(path, "*"))) :
  11. return path # Directory should not be empty
  12. raise ValueError
  13. dirs = DebianSet(("/etc/menu", "/usr/lib/menu", "/usr/share/menu", "/usr/share/menu/default", "~/.menu"))
  14. # If dirs isn't empty then assume we're running Debian and therefore it's reasonable
  15. # to use local menu entries instead of cached ones
  16. if not len(dirs) :
  17. dirs = DebianSet((os.path.join(__path__[0], "menu"),))
  18. runDebian = False
  19. else :
  20. runDebian = True
  21. def scan() :
  22. """Scan through all containers and return a list of found valid entries"""
  23. result = []
  24. msg(" debian...", newline = False)
  25. for d in dirs :
  26. for f in glob.glob(os.path.join(d, "*")) :
  27. if verbose > 1 : msg("\nparsing " + f)
  28. try :
  29. entries = _parse(f)
  30. except NotSet, e :
  31. if verbose > 1 : msg("REJECTED : " + str(e))
  32. else :
  33. for e in entries :
  34. try :
  35. result.append(App(e))
  36. except Prophet.NotSet, e :
  37. if verbose > 1 : msg("REJECTED : " + str(e))
  38. msg(" %d apps found" % len(result))
  39. return result
  40. def _parse(debmenu) :
  41. try :
  42. file = open(debmenu)
  43. except IOError :
  44. raise NotSet("couldn't read the file " + debmenu)
  45. entry = ""
  46. entries = []
  47. next = False
  48. try :
  49. for x in file :
  50. x = x.strip()
  51. if next :
  52. if not len(x) :
  53. next = False
  54. continue
  55. if not x.startswith("#") :
  56. if x.endswith("\\") :
  57. entry += " " + x.rstrip("\\")
  58. next = True
  59. else :
  60. entry += " " + x
  61. next = False
  62. else :
  63. if not len(x) :
  64. continue
  65. if not x.startswith("#") and x.startswith("?") :
  66. if len(entry) :
  67. entries += _parseEntry(entry)
  68. if x.endswith("\\") :
  69. entry = x.rstrip("\\")
  70. next = True
  71. else :
  72. entry = x
  73. next = False
  74. except IOError :
  75. raise NotSet("i/o error while reading the file " + debmenu)
  76. except StopIteration :
  77. pass
  78. if len(entry) :
  79. entries += _parseEntry(entry)
  80. return entries
  81. _package = re.compile('^\?\s*?package\s*?\((.*?)\)\s*?\:')
  82. _key = re.compile('(\w+)\s*=\s*(".*?"|\S+)')
  83. def _parseEntry(s) :
  84. entry = {}
  85. x = _package.match(s)
  86. if x :
  87. entry["package"] = x.group(1)
  88. for x in re.findall(_key, s) :
  89. entry[ x[0] ] = x[1].strip('"')
  90. return [entry]
  91. class App(Prophet.App) :
  92. pref = 10
  93. def __new__(cls, entry) :
  94. self = object.__new__(cls)
  95. self.__setup__(entry)
  96. return self
  97. def __setup__(self, entry) :
  98. self.entry = entry
  99. super(App, self).__setup__()
  100. del self.entry
  101. # TODO : filter out GNOME/KDE apps since they should be picked up by the .desktop scanner anyways
  102. # To accomplish this scan title/longtitle/description/whatever for the clues (gnome-*, "Calculator for GNOME", etc.)
  103. def setName(self) :
  104. try :
  105. self.name = self.entry["title"]
  106. except KeyError :
  107. super(App, self).setName()
  108. def setComment(self) :
  109. try :
  110. self.comment = self.entry["longtitle"]
  111. except KeyError :
  112. try :
  113. self.comment = self.entry["description"]
  114. except KeyError :
  115. super(App, self).setComment()
  116. def setKeywords(self) :
  117. try :
  118. sect = self.entry["section"]
  119. except KeyError :
  120. sect = ""
  121. try :
  122. hint = self.entry["hints"]
  123. except KeyError :
  124. hint = ""
  125. kws = _deb2kws(sect, hint)
  126. if not len(kws) :
  127. raise Prophet.NotSet("no keywords guessed")
  128. self.keywords = kws
  129. def setTerminal(self) :
  130. try :
  131. needs = Kw(self.entry["needs"])
  132. if needs == Kw("X11") :
  133. self.terminal = False
  134. elif needs == Kw("text") :
  135. self.terminal = True
  136. else :
  137. raise Prophet.NotSet("unsupported needs entry (%s)" % needs)
  138. except KeyError :
  139. super(App, self).setTerminal()
  140. def setExename(self) :
  141. try :
  142. cmd = self.entry["command"]
  143. except KeyError :
  144. raise Prophet.NotSet("no command entry found")
  145. self.testGoodness(cmd)
  146. scmd = cmd.split(" ", 1)
  147. if len(scmd) >= 2 :
  148. cmd = scmd[0].strip()
  149. args = scmd[1].strip()
  150. for x in args.split() :
  151. if fnmatch.fnmatch(x, "*/*/*") and not os.path.exists(x) :
  152. # An argument specified in the command line looks like a path. If it
  153. # doesn't exist, the entire command is likely to be worthless, so throw it off
  154. raise Prophet.NotSet("nonexistent path %s as command argument")
  155. self.exeargs = args
  156. if not runDebian :
  157. # If we're not running Debian specified command may be located
  158. # elsewhere therefore we have to scan PATH for it
  159. cmd = os.path.basename(cmd)
  160. if cmd in ("sh", "bash", "csh", "tcsh", "zsh", "ls", "killall", "echo", "nice", "xmessage", "xlock") : # List of globs of unwanted commands
  161. # Debian seems to have lots of shell commands. While it would be nice
  162. # to try to analyze them, this isn't a priority since they're often
  163. # too Debian-specific.
  164. raise Prophet.NotSet("%s blacklisted" % cmd)
  165. self.exename = cmd
  166. _secs = {
  167. Kw("Appearance") : (Settings, DesktopSettings),
  168. Kw("AI") : (Science,),
  169. Kw("Databases") : (Database, Office),
  170. Kw("Editors") : (TextEditor, Utility),
  171. Kw("Educational") : (Education,),
  172. Kw("Emulators") : (Emulator,),
  173. Kw("Games") : (Game,),
  174. Kw("Adventure") : (AdventureGame, Game),
  175. Kw("Arcade") : (ArcadeGame, Game),
  176. Kw("Board") : (BoardGame, Game),
  177. Kw("Card") : (CardGame, Game),
  178. Kw("Puzzles") : (LogicGame, Game),
  179. Kw("Simulation") : (Simulation, Game),
  180. Kw("Sports") : (SportsGame, Game),
  181. Kw("Strategy") : (StrategyGame, Game),
  182. Kw("Tetris-like") : (BlocksGame, Game),
  183. Kw("Graphics") : (Graphics,),
  184. Kw("Hamradio") : (HamRadio, Network),
  185. Kw("Math") : (Math, Science),
  186. Kw("Misc") : (Utility,), # ???
  187. Kw("Net") : (Network,),
  188. Kw("Analog") : (Engineering, Network),
  189. Kw("Headlines") : (News, Network),
  190. Kw("Programming") : (Development,),
  191. Kw("Shells") : (Shell, ConsoleOnly), # ???
  192. Kw("Sound") : (Audio, AudioVideo),
  193. Kw("System") : (System,),
  194. Kw("Admin") : (Settings, System),
  195. # Kw("GNOME") : (GNOME, GTK),
  196. Kw("Technical") : (Engineering,),
  197. Kw("Text") : (TextEditor, Utility),
  198. Kw("Tools") : (Utility,),
  199. Kw("Viewers") : (Viewer, Graphics),
  200. Kw("XawTV") : (TV, Viewer, Video, AudioVideo),
  201. Kw("Toys") : (Amusement,),
  202. Kw("Help") : (Utility, Kw("X-Help")),
  203. Kw("Screen") : (Utility,), # ???
  204. # Kw("Lock") : (Utility, Kw("X-Lock")),
  205. Kw("Saver") : (Screensaver, Utility),
  206. Kw("System") : (System,),
  207. Kw("XShells") : (Shell,)
  208. }
  209. _hints = {
  210. Kw("3D") : (ActionGame, Game), # ???
  211. Kw("Bitmap") : (RasterGraphics, x2DGraphics, Graphics),
  212. Kw("Boot") : (System, Utility),
  213. Kw("Bug reporting") : (Development,),
  214. Kw("Calculators") : (Calculator, Utility),
  215. Kw("Clocks") : (Clock, Utility),
  216. Kw("Config") : (Settings,),
  217. Kw("Debuggers") : (Debugger, Development),
  218. Kw("Documents") : (Office,),
  219. Kw("Doom") : (ActionGame, Game),
  220. Kw("Drawing") : (RasterGraphics, x2DGraphics, Graphics),
  221. Kw("Vector") : (VectorGraphics, Graphics),
  222. Kw("Equation") : (Math, Science),
  223. Kw("Editor") : (WordProcessor, Office),
  224. Kw("Formula") : (Presentation, Office),
  225. Kw("Fonts") : (DesktopSettings, Settings),
  226. Kw("Mail") : (Email, Office, Network),
  227. Kw("Calendar") : (Calendar, Office),
  228. Kw("Monitoring") : (Monitor, System),
  229. Kw("IRC") : (IRCClient, Network),
  230. Kw("ISDN") : (Telephony, Dialup, Network), # ???
  231. Kw("Images") : (x2DGraphics, Graphics),
  232. Kw("Internet") : (Network,),
  233. Kw("HTML") : (Network,),
  234. Kw("Mahjongg") : (LogicGame, Game),
  235. Kw("Mines") : (LogicGame, Game),
  236. Kw("Mixers") : (Mixer, Audio),
  237. Kw("Real-time") : (StrategyGame, Game),
  238. Kw("Parallel") : (Math, Science, Network),
  239. Kw("Distributed") : (Math, Science, Network),
  240. Kw("PostScript") : (Presentation, Office),
  241. Kw("Presentation") : (Presentation, Office),
  242. Kw("SameGame") : (LogicGame, Game),
  243. Kw("Screenshot") : (Graphics, Utility),
  244. Kw("Setup") : (System,),
  245. Kw("Install") : (System,),
  246. Kw("Config") : (Settings,),
  247. Kw("Spreadsheets") : (Spreadsheet, Office),
  248. Kw("Terminal") : (TerminalEmulator),
  249. Kw("Translation") : (Languages, Education),
  250. Kw("Dictionary") : (Languages, Education),
  251. Kw("Time") : (Clock, Utility),
  252. Kw("Users") : (System, Settings),
  253. Kw("VNC") : (Network,),
  254. Kw("Video") : (Video, AudioVideo),
  255. Kw("Web Browsers") : (WebBrowser, Network),
  256. Kw("Word Processors") : (WordProcessor, Office)
  257. }
  258. _rejs = (
  259. Kw("Modules"), Kw("WindowManagers"), Kw("WorkSpace"), Kw("Lock"), Kw("GNOME")
  260. )
  261. def _deb2kws(sec, hint) :
  262. """Convert Debian style section/hints entries to an equivalent keyword set"""
  263. kws = []
  264. for x in sec.split("/") :
  265. x = Kw(x)
  266. if x in _rejs :
  267. raise Prophet.NotSet("section %s rejected" % x)
  268. try :
  269. kws += _secs[x]
  270. except KeyError :
  271. pass
  272. for x in hint.split(",") :
  273. x = Kw(x)
  274. try :
  275. kws += _hints[x]
  276. except KeyError :
  277. pass
  278. return KwS(*kws)