chiark / gitweb /
Merge branch 'ceb'
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 17 May 2009 01:12:28 +0000 (02:12 +0100)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 17 May 2009 01:12:28 +0000 (02:12 +0100)
Conflicts:
yoweb-scrape

1  2 
yoweb-scrape

diff --combined yoweb-scrape
index 1eeb8a36e0dace67cd9bfb08d3e110a627c691ae,5e24e57e749fb6f5657f19963cd518a109e7389a..517d5e1912a06d3dfb368ec217924b9337673b9e
@@@ -13,7 -13,6 +13,7 @@@ import errn
  import sys
  import re as regexp
  import random
 +import curses
  from optparse import OptionParser
  
  from BeautifulSoup import BeautifulSoup
@@@ -41,12 -40,6 +41,12 @@@ def debug(m)
        if opts.debug > 0:
                print m
  
 +def format_time_interval(ti):
 +      if ti < 120: return '%d:%02d' % (ti / 60, ti % 60)
 +      if ti < 7200: return '%2dm' % (ti / 60)
 +      if ti < 86400: return '%dh' % (ti / 3600)
 +      return '%dd' % (ti / 86400)
 +
  #---------- caching and rate-limiting data fetcher ----------
  
  class Fetcher:
@@@ -59,9 -52,9 +59,9 @@@
                        if oe.errno != errno.EEXIST: raise
                self._cache_scan(time.time())
  
 -      def _default_ocean(self):
 +      def default_ocean(self, ocean='ice'):
                if self.ocean is None:
 -                      self.ocean = 'ice'
 +                      self.ocean = ocean
  
        def _cache_scan(self, now):
                # returns list of ages, unsorted
                return data
  
        def yoweb(self, kind, tail, max_age):
 -              self._default_ocean()
 +              self.default_ocean()
                url = 'http://%s.puzzlepirates.com/yoweb/%s%s' % (
                        self.ocean, kind, tail)
                return self.fetch(url, max_age)
@@@ -649,6 -642,6 +649,7 @@@ class ChatLogTracker
                return self._vessel
        def aboard(self):
                # returns a list of PirateAboard sorted by name
++              if self._v is None: return []
                return [ self._v[pn]
                         for pn in sorted(self._v.keys())
                         if not pn.startswith('#') ]
@@@ -685,16 -678,10 +686,16 @@@ def do_standings_crew_of(args, bu)
        print tab.results()
  
  class ProgressPrintPercentage:
 -      def __init__(self, f=sys.stdout): self._f = f
 -      def progress(self,done,total):
 -              self._f.write("scan chat logs %3d%%\r" % ((done*100) / total))
 +      def __init__(self, f=sys.stdout):
 +              self._f = f
 +      def progress_string(self,done,total):
 +              return "scan chat logs %3d%%\r" % ((done*100) / total)
 +      def progress(self,*a):
 +              self._f.write(self.progress_string(*a))
                self._f.flush()
 +      def show_init(self, pirate, ocean):
 +              print >>self._f, 'Starting up, %s on the %s ocean' % (
 +                      pirate, ocean)
        def caughtup(self):
                self._f.write('                   \r')
                self._f.flush()
@@@ -706,14 -693,12 +707,14 @@@ def prep_chat_log(args, bu
                max_myself_age=3600):
        if len(args) != 1: bu('this action takes only chat log filename')
        logfn = args[0]
-       logfn_re = '(?:.*/)?([A-Z][a-z]+)_([a-z]+)_chat-log-\\w+$'
+       logfn_re = '(?:.*/)?([A-Z][a-z]+)_([a-z]+)_'
        match = regexp.match(logfn_re, logfn)
-       if not match: bu('chat log filename is not in default format')
+       if not match: bu('chat log filename is not in expected format')
 -      (pirate, fetcher.ocean) = match.groups()
 +      (pirate, ocean) = match.groups()
 +      fetcher.default_ocean(ocean)
        
        myself = PirateInfo(pirate,max_myself_age)
 +      progress.show_init(pirate, fetcher.ocean)
        track = ChatLogTracker(myself, logfn)
  
        opts.debug -= 1
@@@ -730,84 -715,23 +731,84 @@@ def do_track_chat_log(args, bu)
                        print track
                time.sleep(1)
  
 -def format_time_interval(ti):
 -      if ti < 120: return '%d:%02d' % (ti / 60, ti % 60)
 -      if ti < 7200: return '%2dm' % (ti / 60)
 -      if ti < 86400: return '%dh' % (ti / 3600)
 -      return '%dd' % (ti / 86400)
 +#----- ship management aid -----
 +
 +class Display_dumb(ProgressPrintPercentage):
 +      def __init__(self):
 +              ProgressPrintPercentage.__init__(self)
 +      def show(self, s):
 +              print '\n\n', s;
 +      def realstart(self):
 +              pass
 +
 +class Display_overwrite(ProgressPrintPercentage):
 +      def __init__(self):
 +              ProgressPrintPercentage.__init__(self)
 +
 +              null = file('/dev/null','w')
 +              curses.setupterm(fd=null.fileno())
 +
 +              self._clear = curses.tigetstr('clear')
 +              if not self._clear:
 +                      self._debug('missing clear!')
 +                      self.show = Display_dumb.show
 +                      return
 +
 +              self._t = {'el':'', 'ed':''}
 +              if not self._init_sophisticated():
 +                      for k in self._t.keys(): self._t[k] = ''
 +                      self._t['ho'] = self._clear
 +
 +      def _debug(self,m): debug('display overwrite: '+m)
 +
 +      def _init_sophisticated(self):
 +              for k in self._t.keys():
 +                      s = curses.tigetstr(k)
 +                      self._t[k] = s
 +              self._t['ho'] = curses.tigetstr('ho')
 +              if not self._t['ho']:
 +                      cup = curses.tigetstr('cup')
 +                      self._t['ho'] = curses.tparm(cup,0,0)
 +              missing = [k for k in self._t.keys() if not self._t[k]]
 +              if missing:
 +                      self.debug('missing '+(' '.join(missing)))
 +                      return 0
 +              return 1
 +
 +      def show(self, s):
 +              w = sys.stdout.write
 +              def wti(k): w(self._t[k])
 +
 +              wti('ho')
 +              nl = ''
 +              for l in s.rstrip().split('\n'):
 +                      w(nl)
 +                      w(l)
 +                      wti('el')
 +                      nl = '\r\n'
 +              wti('ed')
 +              w(' ')
 +              sys.stdout.flush()
 +
 +      def realstart(self):
 +              sys.stdout.write(self._clear)
 +              sys.stdout.flush()
 +                      
  
  def do_ship_aid(args, bu):
        if opts.ship_duty is None: opts.ship_duty = True
  
 -      (myself, track) = prep_chat_log(args, bu)
 -
 +      displayer = globals()['Display_'+opts.display]()
        rotate_nya = '/-\\'
  
 +      (myself, track) = prep_chat_log(args, bu, progress=displayer)
 +
        def timeevent(t,e):
                if t is None: return ' ' * 22
                return " %-4s %-16s" % (format_time_interval(now - t),e)
  
 +      displayer.realstart()
 +
        while True:
                track.catchup()
                now = time.time()
                s = "%s" % track.myname()
  
                vn = track.vessel()
--              if vn is None:
-                       s += " not on a vessel?!"
-               else:
-                       s += " on board the %s at %s\n" % (
-                               vn, time.strftime("%Y-%m-%d %H:%M:%S"))
 -                      print s + " ...?"
 -                      time.sleep(1)
 -                      continue
 -
 -              s += " on board the %s at %s\n" % (
 -                      vn, time.strftime("%Y-%m-%d %H:%M:%S"))
++              if vn is None: s += " not on a vessel?!"
++              else: s += " on board the %s" % vn
++              s += " at %s\n" % time.strftime("%Y-%m-%d %H:%M:%S")
  
                tbl = StandingsTable()
                tbl.headings()
  
                s += tbl.results()
  
 -              print '\n\n', s;
 -
 +              displayer.show(s)
                time.sleep(1)
                rotate_nya = rotate_nya[1:2] + rotate_nya[0]
  
@@@ -856,11 -783,7 +855,11 @@@ actions
   yoweb-scrape [--ocean OCEAN ...] crew-of PIRATE
   yoweb-scrape [--ocean OCEAN ...] standings-crew-of PIRATE
   yoweb-scrape [--ocean OCEAN ...] track-chat-log CHAT-LOG
 - yoweb-scrape [--ocean OCEAN ...] ship-aid CHAT-LOG
 + yoweb-scrape [options] ship-aid CHAT-LOG  (must be .../PIRATE_OCEAN_chat-log*)
 +
 +display modes (for --display) apply to ship-aid:
 + --display=dumb       just print new information, scrolling the screen
 + --display=overwrite  use cursor motion, selective clear, etc. to redraw at top
  ''')
        ao = pa.add_option
        ao('-O','--ocean',dest='ocean', metavar='OCEAN', default=None,
                help='cache yoweb pages in DIR')
        ao('-D','--debug', action='count', dest='debug', default=0,
                help='enable debugging output')
 +      ao('--debug-fd', action='count', dest='debug_fd',
 +              help='write any debugging output to specified fd')
        ao('-q','--quiet', action='store_true', dest='quiet',
                help='suppress warning output')
 +      ao('--display', action='store', dest='display',
 +              type='choice', choices=['dumb','overwrite'],
 +              help='how to display ship aid')
  
        ao('--ship-duty', action='store_true', dest='ship_duty',
                help='show ship duty station puzzles')
        if len(args) < 1:
                pa.error('need a mode argument')
  
 +      if opts.debug_fd is not None:
 +              opts.debug_file = fdopen(opts.debug_fd, 'w')
 +
        mode = args[0]
        mode_fn_name = 'do_' + mode.replace('_','#').replace('-','_')
        try: mode_fn = globals()[mode_fn_name]
        if opts.cache_dir.startswith('~/'):
                opts.cache_dir = os.getenv('HOME') + opts.cache_dir[1:]
  
 +      if opts.display is None:
 +              if ((opts.debug > 0 and opts.debug_fd is None)
 +                  or not os.isatty(sys.stdout.fileno())):
 +                      opts.display = 'dumb'
 +              else:
 +                      opts.display = 'overwrite'
 +
        fetcher = Fetcher(opts.ocean, opts.cache_dir)
  
        mode_fn(args[1:], pa.error)