A modest string writer

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # -*- coding: utf-8 -*-
  2. import imp
  3. import os
  4. import sys
  5. class PluginError(Exception):
  6. pass
  7. class PluginUsageError(PluginError):
  8. pass
  9. class XGPRenderer(object):
  10. def __init__(self, txt=None):
  11. self.txt = txt
  12. self.img = None
  13. self.tool = txt
  14. self.bar = None
  15. self.click = None
  16. self._fields = ['txt', 'img', 'tool', 'bar', 'click']
  17. def __str__(self):
  18. out = ""
  19. for field in self._fields:
  20. value = getattr(self, field, None)
  21. if value is not None:
  22. out += "<%(f)s>%(v)s</%(f)s>" % {'f': field, 'v': value}
  23. return out
  24. class BasePlugin(object):
  25. def __init__(self, data):
  26. self.data = data
  27. def render(self):
  28. method_n = "render_" + self.data.fmt
  29. def ex(__):
  30. raise PluginError("plugin method not defined: " + method_n)
  31. render_fn = getattr(self, method_n, ex)
  32. return render_fn()
  33. def render_xgp(self):
  34. return XGPRenderer(self.render_plain())
  35. class PluginData(object):
  36. def __init__(self, cmdargs):
  37. self.args = []
  38. self.fmt = "plain"
  39. self.maxlen = 40
  40. self.name = ""
  41. self._load(cmdargs)
  42. def _load(self, cmdargs):
  43. if cmdargs['--plain']:
  44. self.fmt = "plain"
  45. elif cmdargs['--xgp']:
  46. self.fmt = "xgp"
  47. self.name = cmdargs['COMMAND']
  48. self.args = cmdargs['ARGS']
  49. if cmdargs['--chars']:
  50. self.maxlen = int(cmdargs['--chars'])
  51. class Subcommand(object):
  52. def __init__(self, cmdargs, pluginpath):
  53. self.plugindata = PluginData(cmdargs)
  54. self.name = cmdargs['COMMAND']
  55. self._load_plugin(pluginpath)
  56. def _load_plugin(self, pluginpath):
  57. modpath = "%s/%s.py" % (pluginpath, self.name)
  58. try:
  59. with open(modpath) as fh:
  60. module = imp.load_module(self.name, fh, modpath,
  61. (".py", "r", imp.PY_SOURCE))
  62. except IOError:
  63. raise PluginError("no such plugin: %s" % self.name)
  64. self.plugin = module.Plugin(self.plugindata)
  65. def _format_output(self, raw):
  66. suffix = "…"
  67. cooked = raw
  68. if self.plugindata.fmt == "plain":
  69. if len(raw) > self.plugindata.maxlen:
  70. newlen = self.plugindata.maxlen - len(suffix)
  71. cooked = raw[:newlen] + suffix
  72. return cooked
  73. def get_output(self):
  74. return self._format_output(self.plugin.render())
  75. class App:
  76. name = "sardine"
  77. def __init__(self, cmdargs):
  78. self.cmdargs = cmdargs
  79. self._set_pluginpath()
  80. def _set_pluginpath(self):
  81. mypath = os.path.dirname(os.path.realpath(sys.argv[0]))
  82. path = mypath + "/plugins"
  83. path = os.environ.get("SARDINE_PLUGINS", path)
  84. self.pluginpath = path
  85. def die(self, msg, rv=9):
  86. sys.stderr.write("%s\n" % msg)
  87. self.exit(rv)
  88. def exit(self, rv=0):
  89. sys.exit(rv)
  90. def run(self):
  91. try:
  92. self.subcommand = Subcommand(self.cmdargs, self.pluginpath)
  93. print self.subcommand.get_output()
  94. except PluginUsageError as e:
  95. msg = ("plugin usage: %s %s %s"
  96. % (self.name, self.subcommand.name, e))
  97. self.die(msg, 11)
  98. except PluginError as e:
  99. self.die(e, 10)