# HG changeset patch # User Tero Marttila # Date 1252861696 -10800 # Node ID 154d2d8ae9c00cb0535b653fd2b9bec234d815d9 # Parent e163794ccf543b2ebc7655f5b7fdf4e2bf9b5f26 kill version magic from setup.py, rename scripts to global names and move package data into the package diff -r e163794ccf54 -r 154d2d8ae9c0 bin/index.cgi --- a/bin/index.cgi Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -#!/usr/bin/python2.5 - -""" - CGI mode using qmsk.web.cgi -""" - -def error () : - """ - Dumps out a raw traceback of the current exception to stdout, call from except. - - Used for low-level ImportError's - """ - - import sys - - # if this import fails, we're doomed - from qmsk.irclogs import error - - # format info - status, content_type, body = error.build_error() - - # HTTP headers+body - sys.stdout.write('Status: %s\r\n' % status) - sys.stdout.write('Content-type: %s\r\n' % content_type) - sys.stdout.write('\r\n') - sys.stdout.write(body) - -def main () : - """ - Build our wsgi.Application and run - """ - - try : - from qmsk.web import cgi_main - from qmsk.irclogs import wsgi - - # create app - app = wsgi.Application() - - # run once - cgi_main.run(app) - - except : - # display error on stdout - error() - -if __name__ == '__main__' : - main() - diff -r e163794ccf54 -r 154d2d8ae9c0 bin/index.fcgi --- a/bin/index.fcgi Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -#!/usr/bin/python2.5 -# :set filetype=py - -""" - FastCGI mode using qmsk.web.fastcgi_main -""" - -from qmsk.web import fastcgi_main - -# XXX: error handling for imports? Lighttp sucks hard at this -from qmsk.irclogs import wsgi - -def main () : - """ - Build our WSGIApplication and run - """ - - # create app - app = wsgi.Application() - - # run once - fastcgi_main.run(app) - -if __name__ == '__main__' : - main() - diff -r e163794ccf54 -r 154d2d8ae9c0 bin/qmsk-irclogs-search-index --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/qmsk-irclogs-search-index Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,640 @@ +#!/usr/bin/env python2.5 + +""" + Tool for accessing the search index +""" + +# XXX: fix path +import sys; sys.path.insert(0, '.'); sys.path.insert(0, '..') + +import os, os.path, fcntl +import datetime, pytz +import optparse + +# configuration and the LogSearchIndex module +from qmsk.irclogs import config, utils, log_search, channels + +def _open_index (options, open_mode) : + """ + Opens the LogSearchIndex + """ + + return log_search.LogSearchIndex(config.LOG_CHANNELS, options.index_path, open_mode) + + +def _open_index_and_channel (options, channel_name, open_mode) : + """ + Opens+returns a LogSearchIndex and a LogChannel + """ + + # open the LogSearchIndex + index = _open_index(options, open_mode) + + # open the channel + channel = config.LOG_CHANNELS.lookup(channel_name) + + # return + return index, channel + +def _iter_insert_stats (index, channel, lines) : + """ + Insert the given lines into the index. + + Assumes the lines will be in time-order, and yields a series of (date, count) tuples for every date that lines + are inserted for + """ + + # last date + date = None + + # count + count = 0 + + # iter lines + for line in lines : + # next day? + if not date or line.timestamp.date() != date : + if date : + # yield stats + yield date, count + + # reset count + count = 0 + + # timestamp's date + date = line.timestamp.date() + + # insert + index.insert_line(channel, line) + + # count + count += 1 + + # final count? + if date and count : + yield date, count + +def _insert_lines (index, options, channel, lines) : + """ + Insert the given lines into the index. + + Assumes the lines will be in time-order, and prints out as status messages the date and count for the inserted lines + """ + + # iterate insert stats + for date, count in _iter_insert_stats(index, channel, lines) : + # output date header? + if not options.quiet : + print "%s: %s" % (date.strftime('%Y-%m-%d'), count), + +def _load_channel_date (index, options, channel, date) : + """ + Loads the logs for the given date from the channel's LogSource into the given LogSearchIndex + """ + + if not options.quiet : + print "Loading date for channel %s" % channel.id + + try : + # load lines for date + lines = channel.source.get_date(date) + + except Exception, e : + if not options.skip_missing : + raise + + if not options.quiet : + print "\tSkipped: %s" % (e, ) + + else : + # insert + _insert_lines(index, options, channel, lines) + +def _parse_date (options, date_str, tz=None, fmt='%Y-%m-%d') : + """ + Parse the given datetime, using the given timezone(defaults to options.tz) and format + """ + + # default tz + if not tz : + tz = options.timezone + + try : + # parse + return datetime.datetime.strptime(date_str, fmt).replace(tzinfo=tz) + + except Exception, e : + raise CommandError("[ERROR] Invalid date: %s: %s" % (date_str, e)) + +def _output_lines (options, lines) : + """ + Display the formatted LogLines + """ + + # display as plaintext + for line, txt_data in options.formatter.format_txt(lines, full_timestamps=True) : + print txt_data + +class CommandError (Exception) : + """ + Error with command-line arguments + """ + + pass + +def cmd_create (options) : + """ + Creates a new index + """ + + # open index + index = _open_index(options, 'ctrunc' if options.force else 'c') + + # that's all + pass + +def cmd_load (options, channel_name, *dates) : + """ + Loads the logs for a specific channel for the given dates (in terms of the channe logs' timezone) into the index + """ + + # open index/channel + index, channel = _open_index_and_channel(options, channel_name, 'c' if options.create else 'a') + + # handle each date + for date_str in dates : + # prase date + try : + date = _parse_date(options, date_str, channel.source.tz) + + # handle errors + except CommandError, e : + if options.skip_missing : + print "[ERROR] %s" % (date_name, e) + + else : + raise + + # otherwise, load + else : + _load_channel_date(index, options, channel, date) + +def cmd_load_month (options, channel_name, *months) : + """ + Loads the logs for a specific channel for the given months (in terms of the channel's timezone) into the index + """ + + # open index/channel + index, channel = _open_index_and_channel(options, channel_name, 'c' if options.create else 'a') + + # handle each date + for month_str in months : + # prase date + try : + month = _parse_date(options, month_str, channel.source.tz, '%Y-%m') + + # handle errors + except CommandError, e : + # skip? + if options.skip_missing : + if not options.quiet : + print "[ERROR] %s" % (date_name, e) + continue + + else : + raise + + # get the set of days + days = list(channel.source.get_month_days(month)) + + if not options.quiet : + print "Loading %d days of logs:" % (len(days)) + + # load each day + for date in days : + # convert to datetime + dt = datetime.datetime.combine(date, datetime.time(0)).replace(tzinfo=channel.source.tz) + + # load + _load_channel_date(index, options, channel, dt) + +def cmd_search (options, channel_name, query) : + """ + Search the index for events on a specific channel with the given query + """ + + # sanity-check + if options.create : + raise Exception("--create doesn't make sense for 'search'") + + # open index/channel + index, channel = _open_index_and_channel(options, channel_name, 'r') + + # search + lines = index.search_simple(channel, query) + + # display + _output_lines(options, lines) + +def cmd_list (options, channel_name, *dates) : + """ + List the indexed events for a specific date + """ + + # sanity-check + if options.create : + raise Exception("--create doesn't make sense for 'search'") + + # open index/channel + index, channel = _open_index_and_channel(options, channel_name, 'r') + + # ...for each date + for date_str in dates : + # parse date + date = _parse_date(options, date_str) + + # list + lines = index.list(channel, date) + + # display + _output_lines(options, lines) + +def _autoload_reset (options, channels) : + """ + Reset old autoload state + """ + + # warn + if not options.quiet : + print "[WARN] Resetting autoload state for: %s" % ', '.join(channel.id for channel in channels) + + # iter + for channel in channels : + # statefile path + statefile_path = os.path.join(options.autoload_state_path, 'chan-%s' % channel.id) + + # is it present? + if not os.path.exists(statefile_path) : + if not options.quiet : + print "[WARN] No statefile found at %s" % statefile_path + + else : + if not options.quiet : + print "\t%s: " % channel.id, + + # remove the statefile + os.remove(statefile_path) + + if not options.quiet : + print "OK" + +def cmd_autoload (options, *channel_names) : + """ + Automatically loads all channel logs that have not been indexed yet (by logfile mtime) + """ + + # open index, nonblocking + index = _open_index(options, 'c?' if options.create else 'a?') + + # default to all channels + if not channel_names : + channels = config.LOG_CHANNELS + + else : + channels = [config.LOG_CHANNELS.lookup(channel_name) for channel_name in channel_names] + + # reset autoload state? + if options.reset : + _autoload_reset(options, channels) + if not options.quiet : + print + + # iterate channels + for channel in channels : + if not options.quiet : + print "Channel %s:" % channel.id + + # no 'from' by default + after = None + + # path to our state file + statefile_path = os.path.join(options.autoload_state_path, 'chan-%s' % channel.id) + statefile_tmppath = statefile_path + '.tmp' + + # does it exist? + have_tmpfile = os.path.exists(statefile_tmppath) + + # do we have a tempfile from a previous crash? + if have_tmpfile and not options.ignore_resume : + # first, open it... + statefile_tmp = open(statefile_tmppath, 'r+') + + # ... then lock it + fcntl.lockf(statefile_tmp, fcntl.LOCK_EX | fcntl.LOCK_NB) + + # read after timestamp + after_str = statefile_tmp.read().rstrip() + + if after_str : + # parse timestamp + after = utils.from_utc_timestamp(int(after_str)) + + if not options.quiet : + print "\tContinuing earlier progress from %s" % after + + else : + # ignore + if not options.quiet : + print "\t[WARN] Ignoring empty temporary statefile" + + else : + # warn about old tmpfile that was ignored + if have_tmpfile and not options.quiet : + print "\t[WARN] Ignoring old tmpfile state" + + # open new tempfile + statefile_tmp = open(statefile_tmppath, 'w') + + # lock + fcntl.lockf(statefile_tmp, fcntl.LOCK_EX | fcntl.LOCK_NB) + + # override? + if options.reload : + # load all + mtime = None + + if not options.quiet : + print "\tForcing reload!" + + # stat for mtime + else : + # stat for mtime, None if unknown + mtime = utils.mtime(statefile_path, ignore_missing=True) + + if mtime and not options.quiet : + print "\tLast load time was %s" % mtime + + elif not options.quiet : + print "\t[WARN] No previous load state! Loading full logs" + + # only after some specific date? + if options.after : + # use unless read from tempfile + if not after : + after = options.after + + if not options.quiet : + print "\tOnly including dates from %s onwards" % after + + else : + if not options.quiet : + print "\t[WARN] Ignoring --from because we found a tempfile" + + # only up to some specific date? + if options.until : + until = options.until + + if not options.quiet : + print "\tOnly including dates up to (and including) %s" % until + else : + # default to now + until = None + + # get lines + lines = channel.source.get_modified(mtime, after, until) + + # insert + if not options.quiet : + print "\tLoading and inserting..." + print + + # iterate insert() per day to display info and update progress + for date, count in _iter_insert_stats(index, channel, lines) : + # output date header? + if not options.quiet : + print "\t%10s: %d" % (date.strftime('%Y-%m-%d'), count) + + # write temp state + statefile_tmp.seek(0) + statefile_tmp.write(str(utils.to_utc_timestamp(datetime.datetime.combine(date, datetime.time(0))))) + statefile_tmp.flush() + + # write autoload state + open(statefile_path, 'w').close() + + # close+delete tempfile + statefile_tmp.close() + os.remove(statefile_tmppath) + + if not options.quiet : + print + + # done + return + +def cmd_help (options, *args) : + """ + Help about commands + """ + + import inspect + + # general help stuff + options._parser.print_help() + + # specific command? + if args : + # the command name + command, = args + + # XXX: display info about specific command + xxx + + # general + else : + print + print "Available commands:" + + # build list of all cmd_* objects + cmd_objects = [(name, obj) for name, obj in globals().iteritems() if name.startswith('cmd_') and inspect.isfunction(obj)] + + # sort alphabetically + cmd_objects.sort() + + # iterate through all cmd_* objects + for cmd_func_name, cmd_func in cmd_objects : + # remove cmd_ prefix + cmd_name = cmd_func_name[4:] + + # inspect + cmd_args, cmd_varargs, cmd_varkw, cmd_default = inspect.getargspec(cmd_func) + cmd_doc = inspect.getdoc(cmd_func) + + # remove the "options" arg + cmd_args = cmd_args[1:] + + # display + print "\t%10s %-30s : %s" % (cmd_name, inspect.formatargspec(cmd_args, cmd_varargs, None, cmd_default), cmd_doc) + +class MyOption (optparse.Option) : + """ + Our custom types for optparse + """ + + def check_date (option, opt, value) : + """ + Parse a date + """ + + try : + # parse + return datetime.datetime.strptime(value, '%Y-%m-%d') + + # trap -> OptionValueError + except Exception, e : + raise optparse.OptionValueError("option %s: invalid date value: %r" % (opt, value)) + + def check_timezone (option, opt, value) : + """ + Parse a timezone + """ + + try : + # parse + return pytz.timezone(value) + + # trap -> OptionValueError + except Exception, e : + raise optparse.OptionValueError("option %s: invalid timezone: %r" % (opt, value)) + + def take_action (self, action, dest, opt, value, values, parser) : + """ + Override take_action to handle date + """ + + if action == "parse_date" : + # get timezone + tz = values.timezone + + # set timezone + value = value.replace(tzinfo=tz) + + # store + return optparse.Option.take_action(self, 'store', dest, opt, value, values, parser) + + else : + # default + return optparse.Option.take_action(self, action, dest, opt, value, values, parser) + + TYPES = optparse.Option.TYPES + ('date', 'timezone') + TYPE_CHECKER = optparse.Option.TYPE_CHECKER.copy() + TYPE_CHECKER['date'] = check_date + TYPE_CHECKER['timezone'] = check_timezone + ACTIONS = optparse.Option.ACTIONS + ('parse_date', ) + STORE_ACTIONS = optparse.Option.STORE_ACTIONS + ('parse_date', ) + TYPED_ACTIONS = optparse.Option.TYPED_ACTIONS + ('parse_date', ) + ACTIONS = optparse.Option.ACTIONS + ('parse_date', ) + +def main (argv) : + """ + Command-line main, with given argv + """ + + # define parser + parser = optparse.OptionParser( + usage = "%prog [options] [ ... ]", + add_help_option = False, + option_class = MyOption, + ) + + # general options # # # # + general = optparse.OptionGroup(parser, "General Options") + general.add_option('-h', "--help", dest="help", help="Show this help message and exit", + action="store_true" ) + + general.add_option( "--formatter", dest="formatter_name", help="LogFormatter to use", + metavar="FMT", type="choice", default=config.PREF_FORMATTER_DEFAULT.name, + choices=[fmt_name for fmt_name in config.LOG_FORMATTERS.iterkeys()] ) + + general.add_option( "--index", dest="index_path", help="Index database path", + metavar="PATH", default=config.SEARCH_INDEX_PATH ) + + general.add_option( "--timezone", dest="timezone", help="Timezone for output", + metavar="TZ", type="timezone", default=pytz.utc ) + + general.add_option( "--force", dest="force", help="Force dangerous operation", + action="store_true" ) + + general.add_option( "--quiet", dest="quiet", help="Supress status messages", + action="store_true" ) + parser.add_option_group(general) + + + # cmd_load options # # # # + load = optparse.OptionGroup(parser, "Load Options") + load.add_option( "--skip-missing", dest="skip_missing", help="Skip missing logfiles", + action="store_true" ) + + load.add_option( "--create", dest="create", help="Create index database", + action="store_true" ) + parser.add_option_group(load) + + + # cmd_autoload options # # # # + autoload = optparse.OptionGroup(parser, "Autoload Options") + autoload.add_option( "--autoload-state", dest="autoload_state_path", help="Path to autoload state dir", + metavar="PATH", default=config.SEARCH_AUTOINDEX_PATH) + + autoload.add_option( "--from", dest="after", help="Only autoload logfiles from the given date on", + metavar="DATE", type="date", action="parse_date", default=None ) + + autoload.add_option( "--until", dest="until", help="Only autoload logfiles up to (and including) the given date", + metavar="DATE", type="date", action="parse_date", default=None ) + + autoload.add_option( "--reload", dest="reload", help="Force reload lines", + action="store_true" ) + + autoload.add_option( "--reset", dest="reset", help="Reset old autload state", + action="store_true" ) + + autoload.add_option( "--ignore-resume", dest="ignore_resume", help="Do not try and resume interrupted autoload", + action="store_true" ) + parser.add_option_group(autoload) + + # parse + options, args = parser.parse_args(argv[1:]) + + # postprocess stuff + options._parser = parser + options.formatter = config.LOG_FORMATTERS[options.formatter_name](options.timezone, "%H:%M:%S", None, None) + + # special-case --help + if options.help : + return cmd_help(options, *args) + + # must have at least the command argument + if not args : + raise CommandError("Missing command") + + # pop command + command = args.pop(0) + + # get func + func = globals().get('cmd_%s' % command) + + # unknown command? + if not func : + raise CommandError("Unknown command: %s" % command) + + # call + func(options, *args) + +if __name__ == '__main__' : + try : + main(sys.argv) + sys.exit(0) + + except CommandError, e : + print e + sys.exit(1) + diff -r e163794ccf54 -r 154d2d8ae9c0 bin/qmsk-irclogs.cgi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/qmsk-irclogs.cgi Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,49 @@ +#!/usr/bin/python2.5 + +""" + CGI mode using qmsk.web.cgi +""" + +def error () : + """ + Dumps out a raw traceback of the current exception to stdout, call from except. + + Used for low-level ImportError's + """ + + import sys + + # if this import fails, we're doomed + from qmsk.irclogs import error + + # format info + status, content_type, body = error.build_error() + + # HTTP headers+body + sys.stdout.write('Status: %s\r\n' % status) + sys.stdout.write('Content-type: %s\r\n' % content_type) + sys.stdout.write('\r\n') + sys.stdout.write(body) + +def main () : + """ + Build our wsgi.Application and run + """ + + try : + from qmsk.web import cgi_main + from qmsk.irclogs import wsgi + + # create app + app = wsgi.Application() + + # run once + cgi_main.run(app) + + except : + # display error on stdout + error() + +if __name__ == '__main__' : + main() + diff -r e163794ccf54 -r 154d2d8ae9c0 bin/qmsk-irclogs.fcgi --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/qmsk-irclogs.fcgi Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,26 @@ +#!/usr/bin/python2.5 +# :set filetype=py + +""" + FastCGI mode using qmsk.web.fastcgi_main +""" + +from qmsk.web import fastcgi_main + +# XXX: error handling for imports? Lighttp sucks hard at this +from qmsk.irclogs import wsgi + +def main () : + """ + Build our WSGIApplication and run + """ + + # create app + app = wsgi.Application() + + # run once + fastcgi_main.run(app) + +if __name__ == '__main__' : + main() + diff -r e163794ccf54 -r 154d2d8ae9c0 bin/search-index --- a/bin/search-index Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,640 +0,0 @@ -#!/usr/bin/env python2.5 - -""" - Tool for accessing the search index -""" - -# XXX: fix path -import sys; sys.path.insert(0, '.'); sys.path.insert(0, '..') - -import os, os.path, fcntl -import datetime, pytz -import optparse - -# configuration and the LogSearchIndex module -from qmsk.irclogs import config, utils, log_search, channels - -def _open_index (options, open_mode) : - """ - Opens the LogSearchIndex - """ - - return log_search.LogSearchIndex(config.LOG_CHANNELS, options.index_path, open_mode) - - -def _open_index_and_channel (options, channel_name, open_mode) : - """ - Opens+returns a LogSearchIndex and a LogChannel - """ - - # open the LogSearchIndex - index = _open_index(options, open_mode) - - # open the channel - channel = config.LOG_CHANNELS.lookup(channel_name) - - # return - return index, channel - -def _iter_insert_stats (index, channel, lines) : - """ - Insert the given lines into the index. - - Assumes the lines will be in time-order, and yields a series of (date, count) tuples for every date that lines - are inserted for - """ - - # last date - date = None - - # count - count = 0 - - # iter lines - for line in lines : - # next day? - if not date or line.timestamp.date() != date : - if date : - # yield stats - yield date, count - - # reset count - count = 0 - - # timestamp's date - date = line.timestamp.date() - - # insert - index.insert_line(channel, line) - - # count - count += 1 - - # final count? - if date and count : - yield date, count - -def _insert_lines (index, options, channel, lines) : - """ - Insert the given lines into the index. - - Assumes the lines will be in time-order, and prints out as status messages the date and count for the inserted lines - """ - - # iterate insert stats - for date, count in _iter_insert_stats(index, channel, lines) : - # output date header? - if not options.quiet : - print "%s: %s" % (date.strftime('%Y-%m-%d'), count), - -def _load_channel_date (index, options, channel, date) : - """ - Loads the logs for the given date from the channel's LogSource into the given LogSearchIndex - """ - - if not options.quiet : - print "Loading date for channel %s" % channel.id - - try : - # load lines for date - lines = channel.source.get_date(date) - - except Exception, e : - if not options.skip_missing : - raise - - if not options.quiet : - print "\tSkipped: %s" % (e, ) - - else : - # insert - _insert_lines(index, options, channel, lines) - -def _parse_date (options, date_str, tz=None, fmt='%Y-%m-%d') : - """ - Parse the given datetime, using the given timezone(defaults to options.tz) and format - """ - - # default tz - if not tz : - tz = options.timezone - - try : - # parse - return datetime.datetime.strptime(date_str, fmt).replace(tzinfo=tz) - - except Exception, e : - raise CommandError("[ERROR] Invalid date: %s: %s" % (date_str, e)) - -def _output_lines (options, lines) : - """ - Display the formatted LogLines - """ - - # display as plaintext - for line, txt_data in options.formatter.format_txt(lines, full_timestamps=True) : - print txt_data - -class CommandError (Exception) : - """ - Error with command-line arguments - """ - - pass - -def cmd_create (options) : - """ - Creates a new index - """ - - # open index - index = _open_index(options, 'ctrunc' if options.force else 'c') - - # that's all - pass - -def cmd_load (options, channel_name, *dates) : - """ - Loads the logs for a specific channel for the given dates (in terms of the channe logs' timezone) into the index - """ - - # open index/channel - index, channel = _open_index_and_channel(options, channel_name, 'c' if options.create else 'a') - - # handle each date - for date_str in dates : - # prase date - try : - date = _parse_date(options, date_str, channel.source.tz) - - # handle errors - except CommandError, e : - if options.skip_missing : - print "[ERROR] %s" % (date_name, e) - - else : - raise - - # otherwise, load - else : - _load_channel_date(index, options, channel, date) - -def cmd_load_month (options, channel_name, *months) : - """ - Loads the logs for a specific channel for the given months (in terms of the channel's timezone) into the index - """ - - # open index/channel - index, channel = _open_index_and_channel(options, channel_name, 'c' if options.create else 'a') - - # handle each date - for month_str in months : - # prase date - try : - month = _parse_date(options, month_str, channel.source.tz, '%Y-%m') - - # handle errors - except CommandError, e : - # skip? - if options.skip_missing : - if not options.quiet : - print "[ERROR] %s" % (date_name, e) - continue - - else : - raise - - # get the set of days - days = list(channel.source.get_month_days(month)) - - if not options.quiet : - print "Loading %d days of logs:" % (len(days)) - - # load each day - for date in days : - # convert to datetime - dt = datetime.datetime.combine(date, datetime.time(0)).replace(tzinfo=channel.source.tz) - - # load - _load_channel_date(index, options, channel, dt) - -def cmd_search (options, channel_name, query) : - """ - Search the index for events on a specific channel with the given query - """ - - # sanity-check - if options.create : - raise Exception("--create doesn't make sense for 'search'") - - # open index/channel - index, channel = _open_index_and_channel(options, channel_name, 'r') - - # search - lines = index.search_simple(channel, query) - - # display - _output_lines(options, lines) - -def cmd_list (options, channel_name, *dates) : - """ - List the indexed events for a specific date - """ - - # sanity-check - if options.create : - raise Exception("--create doesn't make sense for 'search'") - - # open index/channel - index, channel = _open_index_and_channel(options, channel_name, 'r') - - # ...for each date - for date_str in dates : - # parse date - date = _parse_date(options, date_str) - - # list - lines = index.list(channel, date) - - # display - _output_lines(options, lines) - -def _autoload_reset (options, channels) : - """ - Reset old autoload state - """ - - # warn - if not options.quiet : - print "[WARN] Resetting autoload state for: %s" % ', '.join(channel.id for channel in channels) - - # iter - for channel in channels : - # statefile path - statefile_path = os.path.join(options.autoload_state_path, 'chan-%s' % channel.id) - - # is it present? - if not os.path.exists(statefile_path) : - if not options.quiet : - print "[WARN] No statefile found at %s" % statefile_path - - else : - if not options.quiet : - print "\t%s: " % channel.id, - - # remove the statefile - os.remove(statefile_path) - - if not options.quiet : - print "OK" - -def cmd_autoload (options, *channel_names) : - """ - Automatically loads all channel logs that have not been indexed yet (by logfile mtime) - """ - - # open index, nonblocking - index = _open_index(options, 'c?' if options.create else 'a?') - - # default to all channels - if not channel_names : - channels = config.LOG_CHANNELS - - else : - channels = [config.LOG_CHANNELS.lookup(channel_name) for channel_name in channel_names] - - # reset autoload state? - if options.reset : - _autoload_reset(options, channels) - if not options.quiet : - print - - # iterate channels - for channel in channels : - if not options.quiet : - print "Channel %s:" % channel.id - - # no 'from' by default - after = None - - # path to our state file - statefile_path = os.path.join(options.autoload_state_path, 'chan-%s' % channel.id) - statefile_tmppath = statefile_path + '.tmp' - - # does it exist? - have_tmpfile = os.path.exists(statefile_tmppath) - - # do we have a tempfile from a previous crash? - if have_tmpfile and not options.ignore_resume : - # first, open it... - statefile_tmp = open(statefile_tmppath, 'r+') - - # ... then lock it - fcntl.lockf(statefile_tmp, fcntl.LOCK_EX | fcntl.LOCK_NB) - - # read after timestamp - after_str = statefile_tmp.read().rstrip() - - if after_str : - # parse timestamp - after = utils.from_utc_timestamp(int(after_str)) - - if not options.quiet : - print "\tContinuing earlier progress from %s" % after - - else : - # ignore - if not options.quiet : - print "\t[WARN] Ignoring empty temporary statefile" - - else : - # warn about old tmpfile that was ignored - if have_tmpfile and not options.quiet : - print "\t[WARN] Ignoring old tmpfile state" - - # open new tempfile - statefile_tmp = open(statefile_tmppath, 'w') - - # lock - fcntl.lockf(statefile_tmp, fcntl.LOCK_EX | fcntl.LOCK_NB) - - # override? - if options.reload : - # load all - mtime = None - - if not options.quiet : - print "\tForcing reload!" - - # stat for mtime - else : - # stat for mtime, None if unknown - mtime = utils.mtime(statefile_path, ignore_missing=True) - - if mtime and not options.quiet : - print "\tLast load time was %s" % mtime - - elif not options.quiet : - print "\t[WARN] No previous load state! Loading full logs" - - # only after some specific date? - if options.after : - # use unless read from tempfile - if not after : - after = options.after - - if not options.quiet : - print "\tOnly including dates from %s onwards" % after - - else : - if not options.quiet : - print "\t[WARN] Ignoring --from because we found a tempfile" - - # only up to some specific date? - if options.until : - until = options.until - - if not options.quiet : - print "\tOnly including dates up to (and including) %s" % until - else : - # default to now - until = None - - # get lines - lines = channel.source.get_modified(mtime, after, until) - - # insert - if not options.quiet : - print "\tLoading and inserting..." - print - - # iterate insert() per day to display info and update progress - for date, count in _iter_insert_stats(index, channel, lines) : - # output date header? - if not options.quiet : - print "\t%10s: %d" % (date.strftime('%Y-%m-%d'), count) - - # write temp state - statefile_tmp.seek(0) - statefile_tmp.write(str(utils.to_utc_timestamp(datetime.datetime.combine(date, datetime.time(0))))) - statefile_tmp.flush() - - # write autoload state - open(statefile_path, 'w').close() - - # close+delete tempfile - statefile_tmp.close() - os.remove(statefile_tmppath) - - if not options.quiet : - print - - # done - return - -def cmd_help (options, *args) : - """ - Help about commands - """ - - import inspect - - # general help stuff - options._parser.print_help() - - # specific command? - if args : - # the command name - command, = args - - # XXX: display info about specific command - xxx - - # general - else : - print - print "Available commands:" - - # build list of all cmd_* objects - cmd_objects = [(name, obj) for name, obj in globals().iteritems() if name.startswith('cmd_') and inspect.isfunction(obj)] - - # sort alphabetically - cmd_objects.sort() - - # iterate through all cmd_* objects - for cmd_func_name, cmd_func in cmd_objects : - # remove cmd_ prefix - cmd_name = cmd_func_name[4:] - - # inspect - cmd_args, cmd_varargs, cmd_varkw, cmd_default = inspect.getargspec(cmd_func) - cmd_doc = inspect.getdoc(cmd_func) - - # remove the "options" arg - cmd_args = cmd_args[1:] - - # display - print "\t%10s %-30s : %s" % (cmd_name, inspect.formatargspec(cmd_args, cmd_varargs, None, cmd_default), cmd_doc) - -class MyOption (optparse.Option) : - """ - Our custom types for optparse - """ - - def check_date (option, opt, value) : - """ - Parse a date - """ - - try : - # parse - return datetime.datetime.strptime(value, '%Y-%m-%d') - - # trap -> OptionValueError - except Exception, e : - raise optparse.OptionValueError("option %s: invalid date value: %r" % (opt, value)) - - def check_timezone (option, opt, value) : - """ - Parse a timezone - """ - - try : - # parse - return pytz.timezone(value) - - # trap -> OptionValueError - except Exception, e : - raise optparse.OptionValueError("option %s: invalid timezone: %r" % (opt, value)) - - def take_action (self, action, dest, opt, value, values, parser) : - """ - Override take_action to handle date - """ - - if action == "parse_date" : - # get timezone - tz = values.timezone - - # set timezone - value = value.replace(tzinfo=tz) - - # store - return optparse.Option.take_action(self, 'store', dest, opt, value, values, parser) - - else : - # default - return optparse.Option.take_action(self, action, dest, opt, value, values, parser) - - TYPES = optparse.Option.TYPES + ('date', 'timezone') - TYPE_CHECKER = optparse.Option.TYPE_CHECKER.copy() - TYPE_CHECKER['date'] = check_date - TYPE_CHECKER['timezone'] = check_timezone - ACTIONS = optparse.Option.ACTIONS + ('parse_date', ) - STORE_ACTIONS = optparse.Option.STORE_ACTIONS + ('parse_date', ) - TYPED_ACTIONS = optparse.Option.TYPED_ACTIONS + ('parse_date', ) - ACTIONS = optparse.Option.ACTIONS + ('parse_date', ) - -def main (argv) : - """ - Command-line main, with given argv - """ - - # define parser - parser = optparse.OptionParser( - usage = "%prog [options] [ ... ]", - add_help_option = False, - option_class = MyOption, - ) - - # general options # # # # - general = optparse.OptionGroup(parser, "General Options") - general.add_option('-h', "--help", dest="help", help="Show this help message and exit", - action="store_true" ) - - general.add_option( "--formatter", dest="formatter_name", help="LogFormatter to use", - metavar="FMT", type="choice", default=config.PREF_FORMATTER_DEFAULT.name, - choices=[fmt_name for fmt_name in config.LOG_FORMATTERS.iterkeys()] ) - - general.add_option( "--index", dest="index_path", help="Index database path", - metavar="PATH", default=config.SEARCH_INDEX_PATH ) - - general.add_option( "--timezone", dest="timezone", help="Timezone for output", - metavar="TZ", type="timezone", default=pytz.utc ) - - general.add_option( "--force", dest="force", help="Force dangerous operation", - action="store_true" ) - - general.add_option( "--quiet", dest="quiet", help="Supress status messages", - action="store_true" ) - parser.add_option_group(general) - - - # cmd_load options # # # # - load = optparse.OptionGroup(parser, "Load Options") - load.add_option( "--skip-missing", dest="skip_missing", help="Skip missing logfiles", - action="store_true" ) - - load.add_option( "--create", dest="create", help="Create index database", - action="store_true" ) - parser.add_option_group(load) - - - # cmd_autoload options # # # # - autoload = optparse.OptionGroup(parser, "Autoload Options") - autoload.add_option( "--autoload-state", dest="autoload_state_path", help="Path to autoload state dir", - metavar="PATH", default=config.SEARCH_AUTOINDEX_PATH) - - autoload.add_option( "--from", dest="after", help="Only autoload logfiles from the given date on", - metavar="DATE", type="date", action="parse_date", default=None ) - - autoload.add_option( "--until", dest="until", help="Only autoload logfiles up to (and including) the given date", - metavar="DATE", type="date", action="parse_date", default=None ) - - autoload.add_option( "--reload", dest="reload", help="Force reload lines", - action="store_true" ) - - autoload.add_option( "--reset", dest="reset", help="Reset old autload state", - action="store_true" ) - - autoload.add_option( "--ignore-resume", dest="ignore_resume", help="Do not try and resume interrupted autoload", - action="store_true" ) - parser.add_option_group(autoload) - - # parse - options, args = parser.parse_args(argv[1:]) - - # postprocess stuff - options._parser = parser - options.formatter = config.LOG_FORMATTERS[options.formatter_name](options.timezone, "%H:%M:%S", None, None) - - # special-case --help - if options.help : - return cmd_help(options, *args) - - # must have at least the command argument - if not args : - raise CommandError("Missing command") - - # pop command - command = args.pop(0) - - # get func - func = globals().get('cmd_%s' % command) - - # unknown command? - if not func : - raise CommandError("Unknown command: %s" % command) - - # call - func(options, *args) - -if __name__ == '__main__' : - try : - main(sys.argv) - sys.exit(0) - - except CommandError, e : - print e - sys.exit(1) - diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/static/irclogs.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/static/irclogs.css Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,393 @@ +/* + * Global styles + */ +body { + padding: 0px; + margin: 0px; + + background-color: #ffffff; + color: #000000; +} + +a { + color: #454545; +} + +/* + * Menu + */ +#menu { + padding: 0px; + margin: 0px; +} + +#menu ul { + display: table; + list-style-type: none; + + width: 100%; + + padding: 0px; + margin: 0px; + + background-color: #f0f0f0; + border-bottom: 1px dashed #a5a5a5; + + text-align: center; + white-space: nowrap; +} + +#menu li { + display: table-cell; + + height: 1.5em; + + padding: 0px; + margin: 0px; + + border-left: 1px solid #b0b0b0; + + font-weight: bold; +} + +#menu li.join-left { + border-left: none; +} + +#menu li a, +#menu li form { + height: 1.5em; +} + +#menu li:first-child { + border-left: none; +} + +#menu li a { + display: block; + + padding: 6px; + margin: 0px; + + height: 100%; + + color: #494949; + text-decoration: none; +} + +#menu li a:hover { + background-color: #d0d0d0; + text-decoration: none; +} + +#menu form { + display: block; + + padding: 0px; + margin: 0px; +} + +#menu form input[type=submit] { + padding: 9px; + margin: 0px; + + border: none; + background-color: inherit; + + cursor: pointer; +} + +#menu form input[type=submit]:hover { + background-color: #d0d0d0; +} + +/* + * Content + */ +div#content { + padding: 25px; +} + +/* + * Footer + */ +div#footer { + padding: 10px; + + border-top: 1px dashed #a5a5a5; + + font-size: x-small; + font-style: italic; +} + +div#footer-left { + float: left; +} + +div#footer-right { + float: right; + text-align: right; +} + +div#footer-center { + text-align: center; +} + +/* + * General + */ +/* Channel view */ +div#title { + text-align: center; + font-size: x-large; + font-weight: bold; + + margin-bottom: 20px; +} + +/* Calendar */ +div.calendar-list { + text-align: center; +} + +table.calendar { + display: inline-table; +} + +table.calendar th { + background-color: #c8c8c8; +} + +/* month header */ +table.calendar tr.month-header th { + +} + +table.calendar tr.month-header form { + padding: 5px; +} + +table.calendar tr.month-header a, +table.calendar span.prev-month, +table.calendar span.next-month { + display: block; + + color: inherit; + text-decoration: none; + + padding: 3px; + padding-left: 8px; + padding-right: 8px; + + font-size: x-large; +} + +table.calendar th.this-month a.next-month, +table.calendar span.prev-month, +table.calendar span.next-month { + color: #d5d5d5; +} + +table.calendar tr.month-header a:hover { + background-color: #b5b5b5; +} + +table.calendar tr.month-header span { + margin-top: 5px; +} + +table.calendar .prev-month { + float: left; +} + +table.calendar .next-month { + float: right; +} + +/* week header */ +table.calendar tr.week-header th { + width: 14% +} + +/* cells */ +table.calendar td { + padding: 2px; + margin: 1px; + text-align: center; +} + +table.calendar td a { + display: block; + padding: 2px; + + background-color: #e0e0e0; + text-decoration: none; + + color: inherit; +} + +table.calendar td.empty { + color: #d0d0d0; +} + +table.calendar td a:hover { + background-color: #d0d0d0; +} + +table.calendar td#today { + font-weight: bold; +} + +/* Preferences form */ +fieldset { + background-color: #e8e8e8; + + margin-bottom: 1em; +} + +legend { + padding: 0.2em 0.5em; + + background-color: inherit; + border: inherit; +} + +label { + display: block; + float: left; + + width: 8em; + margin-right: 0.5em; + + text-align: right; +} + +fieldset input, +fieldset select { + width: 15em; +} + +fieldset input[type=submit] { + width: 8em; +} + +fieldset input.wide { + width: 30em; +} + +fieldset span.example { + font-size: x-small; + + margin-left: 1em; +} + +/* Search form */ +div#search-form { + padding: 25px; + + text-align: center; +} + +/* +div#search input[type=text] { + display: block; + + width: 40%; + margin: 0px auto 5px auto; +} + +div#search div.indent { + margin-left: 8.5em; +} +*/ + +div#search-help { + +} + +div#search-error { + margin: 50px; + + text-align: center; + font-size: x-large; + font-style: italic; +} + +/* Log lines */ +a.more-link { + color: black; + text-decoration: none; +} + +a.more-link:hover { + text-decoration: underline; +} + +div#lines a { + color: black; +} + +div#lines a[id] { + color: #ffffff; + text-decoration: none; +} + +div#lines a[id]:hover, +div#lines a[id]:target { + color: #000000; +} + +/* Pagination */ +div.paginate { + height: 50px; + + text-align: center; +} + +div.paginate ul { + margin: 0px; + padding: 0px; + + line-height: 30px; + + border: 1px solid #aaa; + + white-space: nowrap; +} + +div.paginate li { + list-style-type: none; + display: inline; +} + +div.paginate li * { + padding: 7px 10px; +} + +div.paginate li a { + color: black; + text-decoration: none; +} + +div.paginate li span { + color: #d5d5d5; +} + +div.paginate li a:hover { + background-color: #d0d0d0; +} + +li.paginate-left { + float: left; +} + +li.paginate-right { + float: right; +} + +/* Lastlog */ +div#other-formats { + font-size: small; + text-align: center; + font-style: italic; +} diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/channel.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/channel.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,39 @@ +<%inherit file="layout.tmpl" /> + +<%def name="menu()"> + + + +${next.body()} + +<%def name="footer_right()"> + All times are in ${h.tz_name(prefs['timezone'])} + diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/channel_calendar.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/channel_calendar.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,69 @@ +<%inherit file="channel.tmpl" /> + +<%def name="month_table(month, is_center=True)"> +## the set of available days +<% log_dates = h.set(channel.source.get_month_days(month)) %> +## the calendar table + +## table header - month name + + + +## month header - weekday names + + % for weekday in h.calendar.iterweekdays() : + + % endfor + +## iterate over the weeks +% for week in h.calendar.monthdays2calendar(month.year, month.month) : + + ## iterate over the week's days + % for day, weekday in week : + ## is it an empty cell? + % if not day : + + % else : + ## build date + <% date = h.build_date(month, day) %>\ + ## render cell + \ + ## link to logs for this day? + % if date.date() in log_dates : +${day}\ + % else : +${day}\ + % endif + + % endif + % endfor + +% endfor +
+ % if is_center : + » + « + +
+ + + +
+ % else : + ${h.fmt_month(month)} + % endif +
${h.fmt_weekday(weekday)}
 
+ + +
${channel.title} :: Calendar for ${h.fmt_month(month)}
+ +
+## three months +${month_table(h.prev_month(month), is_center=False )} +${month_table(month, is_center=True )} +${month_table(h.next_month(month), is_center=False )} +
diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/channel_date.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/channel_date.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,29 @@ +<%inherit file="channel.tmpl" /> +<%namespace file="inc_paginate.tmpl" name="paginate" /> + +## special pagination stuff +<%def name="paginate_date()"> + <%call expr="paginate.paginate(urls.channel_date, count, page, max, channel=channel, date=date)"> + <%def name="left()"> + % if date_prev : + « ${h.fmt_date(date_prev)} + % endif + + <%def name="right()"> + % if date_next : + ${h.fmt_date(date_next)} » + % endif + + + + +
${channel.title} :: Logs for ${h.fmt_date(date)}
+ +% if page : +${paginate_date()} +% endif +<%include file="lines.tmpl" /> +% if page : +${paginate_date()} +% endif + diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/channel_last.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/channel_last.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,18 @@ +<%inherit file="channel.tmpl" /> + +
${channel.title} :: Last ${count} lines
+ +
+ View last lines: +
+ +<%include file="lines.tmpl" /> + +
+ Other formats available:
+ Plaintext + | PNG + | RSS +
diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/channel_search.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/channel_search.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,62 @@ +<%inherit file="channel.tmpl" /> +<%namespace file="inc_paginate.tmpl" import="paginate" /> + +% if not show_results : +
${channel.title} :: Search
+ + + +% else : +
${channel.title} :: Results\ +% if search_query : + With '${search_query}'\ +% endif +% if search_nick : + By ${search_nick}\ +% endif +
+ +${paginate(urls.channel_search, count, page, max, channel=channel, q=search_query, t=search_targets, _more=True, _last=not(bool(lines)))} +% if lines : +<%include file="lines.tmpl" /> +% else : +
No results found
+% endif +${paginate(urls.channel_search, count, page, max, channel=channel, q=search_query, t=search_targets, _more=True, _last=not(bool(lines)))} +% endif diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/inc_paginate.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/inc_paginate.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,60 @@ +## special overrides... +<%def name="paginate_left()"> + + + +<%def name="paginate(url, count, page_cur, page_max, _more=None, _last=False, **args)"> + <%doc> + Pagination works using page numbers, with a specific number of maximum pages displayed. If _more is True, + then instead of a "Next" button, we have a "More" button, which goes to the max+1'th page, unless _last is + True, whereupon it's not displayed. + + Can be called using <%call>, whereupon caller.left/caller.right can define additional data to display at the + left/right of the pagination ul. + +
+
    + % if caller and caller.right : +
  • + ${caller.right()} +
  • + % endif + % if caller and caller.left : +
  • + ${caller.left()} +
  • + % endif +
  • + % if page_cur > 1 : + « Prev + % else : + « Prev + %endif +
  • + % for page in xrange(1, page_max + 1) : +
  • + % if page == page_cur : + ${page} + % else : + ${page} + % endif +
  • + % endfor + % if _more and not _last : +
  • + % endif +
  • + % if _more and _last : + More » + % elif _more : + More » + % elif page_cur == page_max : ## last page + Next » + % else : + Next » + % endif +
  • +
+
+ + diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/index.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/index.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,10 @@ +<%inherit file="layout.tmpl" /> + +
Available Channels
+ + + diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/layout.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/layout.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,84 @@ + + +<%def name="menu()"> +
    +
  • Home
  • +
  • Preferences
  • + +
  • + Channel: +
  • +
    + +
    +
  • +
+ + +<%def name="footer_right()"> + + + + + + irclogs.qmsk.net${(' :: ' + channel.title) if channel else ''} + + ## timezone-autodetect + % if prefs and prefs.is_default('timezone') : + + % endif + + + + +
+ ${next.body()} +
+ + + + + diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/lines.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/lines.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,13 @@ +<% formatter = prefs['formatter'] %> + +
+% if formatter.html_fixedwidth : +
+% endif
+% for line, html in lines:
+»» ${html}
+% endfor
+% if formatter.html_fixedwidth :
+
+% endif +
diff -r e163794ccf54 -r 154d2d8ae9c0 qmsk/irclogs/templates/preferences.tmpl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/templates/preferences.tmpl Sun Sep 13 20:08:16 2009 +0300 @@ -0,0 +1,67 @@ +<%inherit file="layout.tmpl" /> + +
Edit Preferences
+ +
+
+ Dates / Times + +

+ + + (${h.tz_name(prefs['timezone'])}) +

+ +

+ + + (${h.fmt_date()}) +

+ +

+ + + (${h.fmt_time()}) +

+ +
+ +
+ Log Output + +

+ + +

+ +

+ + + +

+
+ +
+ Image Options + +

+ + +

+ +

+ + + pt +

+
+ + +
+ diff -r e163794ccf54 -r 154d2d8ae9c0 setup.py --- a/setup.py Sun Sep 13 18:57:48 2009 +0300 +++ b/setup.py Sun Sep 13 20:08:16 2009 +0300 @@ -2,16 +2,16 @@ from distutils.core import setup -from qmsk.irclogs.version import version_string - # version magic... -import os.path -version = version_string(os.path.dirname(__file__)) +#from qmsk.irclogs.version import version_string +#import os.path +#version = version_string(os.path.dirname(__file__)) setup( name = "qmsk.irclogs", - version = version, + # version = version, + version = '0.2.0-rc1', description = "Irclogs2", author = "Tero Marttila", author_email= "terom@fixme.fi", @@ -22,9 +22,13 @@ ], scripts = [ - 'bin/index.cgi', - 'bin/index.fcgi', - 'bin/search-index' + 'bin/qmsk-irclogs.cgi', + 'bin/qmsk-irclogs.fcgi', + 'bin/qmsk-irclogs-search-index' ], + + package_data = { + 'qmsk.irclogs': ['templates/*.tmpl', 'static/*'], + }, ) diff -r e163794ccf54 -r 154d2d8ae9c0 static/irclogs.css --- a/static/irclogs.css Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* - * Global styles - */ -body { - padding: 0px; - margin: 0px; - - background-color: #ffffff; - color: #000000; -} - -a { - color: #454545; -} - -/* - * Menu - */ -#menu { - padding: 0px; - margin: 0px; -} - -#menu ul { - display: table; - list-style-type: none; - - width: 100%; - - padding: 0px; - margin: 0px; - - background-color: #f0f0f0; - border-bottom: 1px dashed #a5a5a5; - - text-align: center; - white-space: nowrap; -} - -#menu li { - display: table-cell; - - height: 1.5em; - - padding: 0px; - margin: 0px; - - border-left: 1px solid #b0b0b0; - - font-weight: bold; -} - -#menu li.join-left { - border-left: none; -} - -#menu li a, -#menu li form { - height: 1.5em; -} - -#menu li:first-child { - border-left: none; -} - -#menu li a { - display: block; - - padding: 6px; - margin: 0px; - - height: 100%; - - color: #494949; - text-decoration: none; -} - -#menu li a:hover { - background-color: #d0d0d0; - text-decoration: none; -} - -#menu form { - display: block; - - padding: 0px; - margin: 0px; -} - -#menu form input[type=submit] { - padding: 9px; - margin: 0px; - - border: none; - background-color: inherit; - - cursor: pointer; -} - -#menu form input[type=submit]:hover { - background-color: #d0d0d0; -} - -/* - * Content - */ -div#content { - padding: 25px; -} - -/* - * Footer - */ -div#footer { - padding: 10px; - - border-top: 1px dashed #a5a5a5; - - font-size: x-small; - font-style: italic; -} - -div#footer-left { - float: left; -} - -div#footer-right { - float: right; - text-align: right; -} - -div#footer-center { - text-align: center; -} - -/* - * General - */ -/* Channel view */ -div#title { - text-align: center; - font-size: x-large; - font-weight: bold; - - margin-bottom: 20px; -} - -/* Calendar */ -div.calendar-list { - text-align: center; -} - -table.calendar { - display: inline-table; -} - -table.calendar th { - background-color: #c8c8c8; -} - -/* month header */ -table.calendar tr.month-header th { - -} - -table.calendar tr.month-header form { - padding: 5px; -} - -table.calendar tr.month-header a, -table.calendar span.prev-month, -table.calendar span.next-month { - display: block; - - color: inherit; - text-decoration: none; - - padding: 3px; - padding-left: 8px; - padding-right: 8px; - - font-size: x-large; -} - -table.calendar th.this-month a.next-month, -table.calendar span.prev-month, -table.calendar span.next-month { - color: #d5d5d5; -} - -table.calendar tr.month-header a:hover { - background-color: #b5b5b5; -} - -table.calendar tr.month-header span { - margin-top: 5px; -} - -table.calendar .prev-month { - float: left; -} - -table.calendar .next-month { - float: right; -} - -/* week header */ -table.calendar tr.week-header th { - width: 14% -} - -/* cells */ -table.calendar td { - padding: 2px; - margin: 1px; - text-align: center; -} - -table.calendar td a { - display: block; - padding: 2px; - - background-color: #e0e0e0; - text-decoration: none; - - color: inherit; -} - -table.calendar td.empty { - color: #d0d0d0; -} - -table.calendar td a:hover { - background-color: #d0d0d0; -} - -table.calendar td#today { - font-weight: bold; -} - -/* Preferences form */ -fieldset { - background-color: #e8e8e8; - - margin-bottom: 1em; -} - -legend { - padding: 0.2em 0.5em; - - background-color: inherit; - border: inherit; -} - -label { - display: block; - float: left; - - width: 8em; - margin-right: 0.5em; - - text-align: right; -} - -fieldset input, -fieldset select { - width: 15em; -} - -fieldset input[type=submit] { - width: 8em; -} - -fieldset input.wide { - width: 30em; -} - -fieldset span.example { - font-size: x-small; - - margin-left: 1em; -} - -/* Search form */ -div#search-form { - padding: 25px; - - text-align: center; -} - -/* -div#search input[type=text] { - display: block; - - width: 40%; - margin: 0px auto 5px auto; -} - -div#search div.indent { - margin-left: 8.5em; -} -*/ - -div#search-help { - -} - -div#search-error { - margin: 50px; - - text-align: center; - font-size: x-large; - font-style: italic; -} - -/* Log lines */ -a.more-link { - color: black; - text-decoration: none; -} - -a.more-link:hover { - text-decoration: underline; -} - -div#lines a { - color: black; -} - -div#lines a[id] { - color: #ffffff; - text-decoration: none; -} - -div#lines a[id]:hover, -div#lines a[id]:target { - color: #000000; -} - -/* Pagination */ -div.paginate { - height: 50px; - - text-align: center; -} - -div.paginate ul { - margin: 0px; - padding: 0px; - - line-height: 30px; - - border: 1px solid #aaa; - - white-space: nowrap; -} - -div.paginate li { - list-style-type: none; - display: inline; -} - -div.paginate li * { - padding: 7px 10px; -} - -div.paginate li a { - color: black; - text-decoration: none; -} - -div.paginate li span { - color: #d5d5d5; -} - -div.paginate li a:hover { - background-color: #d0d0d0; -} - -li.paginate-left { - float: left; -} - -li.paginate-right { - float: right; -} - -/* Lastlog */ -div#other-formats { - font-size: small; - text-align: center; - font-style: italic; -} diff -r e163794ccf54 -r 154d2d8ae9c0 templates/channel.tmpl --- a/templates/channel.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -<%inherit file="layout.tmpl" /> - -<%def name="menu()"> - - - -${next.body()} - -<%def name="footer_right()"> - All times are in ${h.tz_name(prefs['timezone'])} - diff -r e163794ccf54 -r 154d2d8ae9c0 templates/channel_calendar.tmpl --- a/templates/channel_calendar.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -<%inherit file="channel.tmpl" /> - -<%def name="month_table(month, is_center=True)"> -## the set of available days -<% log_dates = h.set(channel.source.get_month_days(month)) %> -## the calendar table - -## table header - month name - - - -## month header - weekday names - - % for weekday in h.calendar.iterweekdays() : - - % endfor - -## iterate over the weeks -% for week in h.calendar.monthdays2calendar(month.year, month.month) : - - ## iterate over the week's days - % for day, weekday in week : - ## is it an empty cell? - % if not day : - - % else : - ## build date - <% date = h.build_date(month, day) %>\ - ## render cell - \ - ## link to logs for this day? - % if date.date() in log_dates : -${day}\ - % else : -${day}\ - % endif - - % endif - % endfor - -% endfor -
- % if is_center : - » - « - -
- - - -
- % else : - ${h.fmt_month(month)} - % endif -
${h.fmt_weekday(weekday)}
 
- - -
${channel.title} :: Calendar for ${h.fmt_month(month)}
- -
-## three months -${month_table(h.prev_month(month), is_center=False )} -${month_table(month, is_center=True )} -${month_table(h.next_month(month), is_center=False )} -
diff -r e163794ccf54 -r 154d2d8ae9c0 templates/channel_date.tmpl --- a/templates/channel_date.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -<%inherit file="channel.tmpl" /> -<%namespace file="inc_paginate.tmpl" name="paginate" /> - -## special pagination stuff -<%def name="paginate_date()"> - <%call expr="paginate.paginate(urls.channel_date, count, page, max, channel=channel, date=date)"> - <%def name="left()"> - % if date_prev : - « ${h.fmt_date(date_prev)} - % endif - - <%def name="right()"> - % if date_next : - ${h.fmt_date(date_next)} » - % endif - - - - -
${channel.title} :: Logs for ${h.fmt_date(date)}
- -% if page : -${paginate_date()} -% endif -<%include file="lines.tmpl" /> -% if page : -${paginate_date()} -% endif - diff -r e163794ccf54 -r 154d2d8ae9c0 templates/channel_last.tmpl --- a/templates/channel_last.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -<%inherit file="channel.tmpl" /> - -
${channel.title} :: Last ${count} lines
- -
- View last lines: -
- -<%include file="lines.tmpl" /> - -
- Other formats available:
- Plaintext - | PNG - | RSS -
diff -r e163794ccf54 -r 154d2d8ae9c0 templates/channel_search.tmpl --- a/templates/channel_search.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -<%inherit file="channel.tmpl" /> -<%namespace file="inc_paginate.tmpl" import="paginate" /> - -% if not show_results : -
${channel.title} :: Search
- - - -% else : -
${channel.title} :: Results\ -% if search_query : - With '${search_query}'\ -% endif -% if search_nick : - By ${search_nick}\ -% endif -
- -${paginate(urls.channel_search, count, page, max, channel=channel, q=search_query, t=search_targets, _more=True, _last=not(bool(lines)))} -% if lines : -<%include file="lines.tmpl" /> -% else : -
No results found
-% endif -${paginate(urls.channel_search, count, page, max, channel=channel, q=search_query, t=search_targets, _more=True, _last=not(bool(lines)))} -% endif diff -r e163794ccf54 -r 154d2d8ae9c0 templates/inc_paginate.tmpl --- a/templates/inc_paginate.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -## special overrides... -<%def name="paginate_left()"> - - - -<%def name="paginate(url, count, page_cur, page_max, _more=None, _last=False, **args)"> - <%doc> - Pagination works using page numbers, with a specific number of maximum pages displayed. If _more is True, - then instead of a "Next" button, we have a "More" button, which goes to the max+1'th page, unless _last is - True, whereupon it's not displayed. - - Can be called using <%call>, whereupon caller.left/caller.right can define additional data to display at the - left/right of the pagination ul. - -
-
    - % if caller and caller.right : -
  • - ${caller.right()} -
  • - % endif - % if caller and caller.left : -
  • - ${caller.left()} -
  • - % endif -
  • - % if page_cur > 1 : - « Prev - % else : - « Prev - %endif -
  • - % for page in xrange(1, page_max + 1) : -
  • - % if page == page_cur : - ${page} - % else : - ${page} - % endif -
  • - % endfor - % if _more and not _last : -
  • - % endif -
  • - % if _more and _last : - More » - % elif _more : - More » - % elif page_cur == page_max : ## last page - Next » - % else : - Next » - % endif -
  • -
-
- - diff -r e163794ccf54 -r 154d2d8ae9c0 templates/index.tmpl --- a/templates/index.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -<%inherit file="layout.tmpl" /> - -
Available Channels
- - - diff -r e163794ccf54 -r 154d2d8ae9c0 templates/layout.tmpl --- a/templates/layout.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ - - -<%def name="menu()"> -
    -
  • Home
  • -
  • Preferences
  • - -
  • - Channel: -
  • -
    - -
    -
  • -
- - -<%def name="footer_right()"> - - - - - - irclogs.qmsk.net${(' :: ' + channel.title) if channel else ''} - - ## timezone-autodetect - % if prefs and prefs.is_default('timezone') : - - % endif - - - - -
- ${next.body()} -
- - - - - diff -r e163794ccf54 -r 154d2d8ae9c0 templates/lines.tmpl --- a/templates/lines.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -<% formatter = prefs['formatter'] %> - -
-% if formatter.html_fixedwidth : -
-% endif
-% for line, html in lines:
-»» ${html}
-% endfor
-% if formatter.html_fixedwidth :
-
-% endif -
diff -r e163794ccf54 -r 154d2d8ae9c0 templates/preferences.tmpl --- a/templates/preferences.tmpl Sun Sep 13 18:57:48 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -<%inherit file="layout.tmpl" /> - -
Edit Preferences
- -
-
- Dates / Times - -

- - - (${h.tz_name(prefs['timezone'])}) -

- -

- - - (${h.fmt_date()}) -

- -

- - - (${h.fmt_time()}) -

- -
- -
- Log Output - -

- - -

- -

- - - -

-
- -
- Image Options - -

- - -

- -

- - - pt -

-
- - -
-