<s> import datetime <EOL> import functools <EOL> from twisted . web import resource <EOL> from twisted . internet import reactor , task <EOL> from harold . plugins . http import ProtectedResource <EOL> from harold . conf import PluginConfig , Option <EOL> from harold . utils import pretty_and_accurate_time_span <EOL> class DeployConfig ( PluginConfig ) : <EOL> channel = Option ( str ) <EOL> deploy_ttl = Option ( int ) <EOL> conch_emoji = Option ( str , default = "<STR_LIT>" ) <EOL> class DeployListener ( ProtectedResource ) : <EOL> def __init__ ( self , http , monitor ) : <EOL> ProtectedResource . __init__ ( self , http ) <EOL> self . monitor = monitor <EOL> class DeployBeganListener ( DeployListener ) : <EOL> isLeaf = True <EOL> def _handle_request ( self , request ) : <EOL> id = unicode ( request . args [ '<STR_LIT:id>' ] [ <NUM_LIT:0> ] , '<STR_LIT:utf-8>' ) <EOL> who = request . args [ '<STR_LIT>' ] [ <NUM_LIT:0> ] <EOL> args = request . args [ '<STR_LIT:args>' ] [ <NUM_LIT:0> ] <EOL> log_path = unicode ( request . args [ '<STR_LIT>' ] [ <NUM_LIT:0> ] , '<STR_LIT:utf-8>' ) <EOL> count = int ( request . args [ '<STR_LIT:count>' ] [ <NUM_LIT:0> ] ) <EOL> self . monitor . onPushBegan ( id , who , args , log_path , count ) <EOL> class DeployEndedListener ( DeployListener ) : <EOL> isLeaf = True <EOL> def _handle_request ( self , request ) : <EOL> id = unicode ( request . args [ '<STR_LIT:id>' ] [ <NUM_LIT:0> ] , '<STR_LIT:utf-8>' ) <EOL> self . monitor . onPushEnded ( id ) <EOL> class DeployErrorListener ( DeployListener ) : <EOL> isLeaf = True <EOL> def _handle_request ( self , request ) : <EOL> id = unicode ( request . args [ '<STR_LIT:id>' ] [ <NUM_LIT:0> ] , '<STR_LIT:utf-8>' ) <EOL> error = request . args [ '<STR_LIT:error>' ] [ <NUM_LIT:0> ] <EOL> self . monitor . onPushError ( id , error ) <EOL> class DeployAbortedListener ( DeployListener ) : <EOL> isLeaf = True <EOL> def _handle_request ( self , request ) : <EOL> id = unicode ( request . args [ '<STR_LIT:id>' ] [ <NUM_LIT:0> ] , '<STR_LIT:utf-8>' ) <EOL> reason = request . args [ '<STR_LIT>' ] [ <NUM_LIT:0> ] <EOL> self . monitor . onPushAborted ( id , reason ) <EOL> class DeployProgressListener ( DeployListener ) : <EOL> isLeaf = True <EOL> def _handle_request ( self , request ) : <EOL> id = unicode ( request . args [ '<STR_LIT:id>' ] [ <NUM_LIT:0> ] , '<STR_LIT:utf-8>' ) <EOL> host = request . args [ '<STR_LIT:host>' ] [ <NUM_LIT:0> ] <EOL> index = float ( request . args [ '<STR_LIT:index>' ] [ <NUM_LIT:0> ] ) <EOL> self . monitor . onPushProgress ( id , host , index ) <EOL> class OngoingDeploy ( object ) : <EOL> pass <EOL> class DeployMonitor ( object ) : <EOL> def __init__ ( self , config , irc ) : <EOL> self . config = config <EOL> self . irc = irc <EOL> self . deploys = { } <EOL> self . current_hold = None <EOL> self . current_conch = "<STR_LIT>" <EOL> self . queue = [ ] <EOL> self . current_topic = self . _make_topic ( ) <EOL> looper = task . LoopingCall ( self . _update_topic ) <EOL> looper . start ( <NUM_LIT:10> ) <EOL> def help ( self , irc , sender , channel , * args ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> irc . send_message ( channel , "<STR_LIT>" ) <EOL> def status ( self , irc , sender , channel ) : <EOL> "<STR_LIT>" <EOL> if channel != self . config . channel : <EOL> return <EOL> reply = functools . partial ( self . irc . bot . send_message , channel ) <EOL> if not self . deploys : <EOL> reply ( "<STR_LIT>" % sender ) <EOL> deploys = sorted ( self . deploys . values ( ) , key = lambda d : d . when ) <EOL> for d in deploys : <EOL> status = "<STR_LIT>" <EOL> if d . where : <EOL> percent = ( float ( d . completion ) / d . host_count ) * <NUM_LIT> <EOL> status = "<STR_LIT>" % ( d . where , percent ) <EOL> reply ( '<STR_LIT>' % <EOL> ( sender , d . who , d . id , status , d . when . strftime ( "<STR_LIT>" ) , <EOL> d . args , d . log_path ) ) <EOL> def hold ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> if self . current_hold : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % sender ) <EOL> return <EOL> self . current_hold = sender <EOL> self . _update_topic ( ) <EOL> def unhold ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> if not self . current_hold : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % sender ) <EOL> return <EOL> self . current_hold = None <EOL> self . _update_topic ( ) <EOL> def acquire ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> if sender in self . queue : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % sender ) <EOL> return <EOL> elif self . queue : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % sender ) <EOL> self . queue . append ( sender ) <EOL> self . _update_topic ( ) <EOL> self . _update_conch ( ) <EOL> def aquire ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> self . irc . bot . send_message ( channel , "<STR_LIT>" ) <EOL> self . acquire ( irc , sender , channel ) <EOL> def _update_conch ( self ) : <EOL> if self . queue : <EOL> new_conch = self . queue [ <NUM_LIT:0> ] <EOL> if new_conch != self . current_conch : <EOL> self . irc . bot . send_message ( self . config . channel , <EOL> "<STR_LIT>" % ( new_conch , self . config . conch_emoji ) ) <EOL> else : <EOL> new_conch = None <EOL> self . current_conch = new_conch <EOL> def release ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> if sender not in self . queue : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % sender ) <EOL> return <EOL> self . queue . remove ( sender ) <EOL> self . _update_conch ( ) <EOL> self . _update_topic ( ) <EOL> def jump ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> if self . queue and self . queue [ <NUM_LIT:0> ] == sender : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % ( sender , self . config . conch_emoji ) ) <EOL> return <EOL> if sender in self . queue : <EOL> self . queue . remove ( sender ) <EOL> self . queue . insert ( <NUM_LIT:0> , sender ) <EOL> self . _update_conch ( ) <EOL> self . _update_topic ( ) <EOL> def kick ( self , irc , sender , channel , user ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> if user not in self . queue : <EOL> self . irc . bot . send_message ( <EOL> channel , "<STR_LIT>" % ( sender , user ) ) <EOL> return <EOL> self . queue . remove ( user ) <EOL> self . _update_conch ( ) <EOL> self . _update_topic ( ) <EOL> def refresh ( self , irc , sender , channel ) : <EOL> if channel != self . config . channel : <EOL> return <EOL> self . _update_topic ( force = True ) <EOL> def current_time_status ( self ) : <EOL> date = datetime . date . today ( ) <EOL> time = datetime . datetime . now ( ) . time ( ) <EOL> if time < datetime . time ( <NUM_LIT:9> , <NUM_LIT:0> ) : <EOL> return "<STR_LIT>" <EOL> if date . weekday ( ) in ( <NUM_LIT:0> , <NUM_LIT:1> , <NUM_LIT:2> , <NUM_LIT:3> ) : <EOL> if time < datetime . time ( <NUM_LIT:16> , <NUM_LIT:0> ) : <EOL> return "<STR_LIT>" <EOL> elif time < datetime . time ( <NUM_LIT> , <NUM_LIT:0> ) : <EOL> return "<STR_LIT>" <EOL> else : <EOL> return "<STR_LIT>" <EOL> else : <EOL> return "<STR_LIT>" <EOL> def _make_topic ( self ) : <EOL> deploy_count = len ( self . deploys ) <EOL> if deploy_count == <NUM_LIT:0> : <EOL> if self . current_hold : <EOL> status = "<STR_LIT>" % self . current_hold <EOL> else : <EOL> time_status = self . current_time_status ( ) <EOL> if time_status == "<STR_LIT>" : <EOL> status = "<STR_LIT>" <EOL> elif time_status == "<STR_LIT>" : <EOL> status = "<STR_LIT>" <EOL> else : <EOL> status = "<STR_LIT>" <EOL> elif deploy_count == <NUM_LIT:1> : <EOL> deploy = self . deploys . values ( ) [ <NUM_LIT:0> ] <EOL> status = "<STR_LIT>" % deploy . who <EOL> else : <EOL> status = "<STR_LIT>" % deploy_count <EOL> return "<STR_LIT>" . join ( ( <EOL> status , <EOL> "<STR_LIT>" % ( self . queue [ <NUM_LIT:0> ] if self . queue else "<STR_LIT>" , self . config . conch_emoji ) , <EOL> "<STR_LIT>" % ( "<STR_LIT:U+002CU+0020>" . join ( self . queue [ <NUM_LIT:1> : ] ) or "<STR_LIT>" ) , <EOL> ) ) <EOL> def _update_topic ( self , force = False ) : <EOL> new_topic = self . _make_topic ( ) <EOL> if force or new_topic != self . current_topic : <EOL> self . irc . bot . set_topic ( self . config . channel , new_topic ) <EOL> self . current_topic = new_topic <EOL> def _remove_deploy ( self , id ) : <EOL> deploy = self . deploys . get ( id ) <EOL> if not deploy : <EOL> return None , None <EOL> if deploy . expirator . active ( ) : <EOL> deploy . expirator . cancel ( ) <EOL> del self . deploys [ id ] <EOL> return deploy . who , datetime . datetime . now ( ) - deploy . when <EOL> def onPushBegan ( self , id , who , args , log_path , count ) : <EOL> deploy = OngoingDeploy ( ) <EOL> deploy . id = id <EOL> deploy . when = datetime . datetime . now ( ) <EOL> deploy . who = who <EOL> deploy . args = args <EOL> deploy . log_path = log_path <EOL> deploy . quadrant = <NUM_LIT:1> <EOL> deploy . where = None <EOL> deploy . completion = None <EOL> deploy . host_count = count <EOL> deploy . expirator = reactor . callLater ( self . config . deploy_ttl , <EOL> self . _remove_deploy , id ) <EOL> self . deploys [ id ] = deploy <EOL> self . _update_topic ( ) <EOL> self . irc . bot . send_message ( self . config . channel , <EOL> '<STR_LIT>' <EOL> "<STR_LIT>" % ( who , id , args ) ) <EOL> def onPushProgress ( self , id , host , index ) : <EOL> deploy = self . deploys . get ( id ) <EOL> if not deploy : <EOL> return <EOL> deploy . expirator . delay ( self . config . deploy_ttl ) <EOL> deploy . completion = index <EOL> deploy . where = host <EOL> if deploy . host_count < <NUM_LIT:8> : <EOL> return <EOL> if deploy . quadrant > <NUM_LIT:3> : <EOL> return <EOL> percent = float ( index ) / deploy . host_count <EOL> if percent < ( deploy . quadrant * <NUM_LIT> ) : <EOL> return <EOL> self . irc . bot . send_message ( self . config . channel , <EOL> """<STR_LIT>""" % <EOL> ( deploy . who , id , deploy . quadrant * <NUM_LIT> ) ) <EOL> deploy . quadrant += <NUM_LIT:1> <EOL> def onPushEnded ( self , id ) : <EOL> who , duration = self . _remove_deploy ( id ) <EOL> if not who : <EOL> return <EOL> self . irc . bot . send_message ( <EOL> self . config . channel , <EOL> """<STR_LIT>""" <EOL> "<STR_LIT>" % ( who , id , pretty_and_accurate_time_span ( duration ) ) <EOL> ) <EOL> self . _update_topic ( ) <EOL> def onPushError ( self , id , error ) : <EOL> deploy = self . deploys . get ( id ) <EOL> if not deploy : <EOL> return <EOL> deploy . expirator . delay ( self . config . deploy_ttl ) <EOL> self . irc . bot . send_message ( self . config . channel , <EOL> ( """<STR_LIT>""" <EOL> "<STR_LIT>" ) % <EOL> ( deploy . who , id , error ) ) <EOL> def onPushAborted ( self , id , reason ) : <EOL> who , duration = self . _remove_deploy ( id ) <EOL> if not who : <EOL> return <EOL> self . irc . bot . send_message ( self . config . channel , <EOL> """<STR_LIT>""" % <EOL> ( who , id , reason ) ) <EOL> self . _update_topic ( ) <EOL> def make_plugin ( config , http , irc ) : <EOL> deploy_config = DeployConfig ( config ) <EOL> monitor = DeployMonitor ( deploy_config , irc ) <EOL> irc . channels . add ( deploy_config . channel ) <EOL> deploy_root = resource . Resource ( ) <EOL> http . root . putChild ( '<STR_LIT>' , deploy_root ) <EOL> deploy_root . putChild ( '<STR_LIT>' , DeployBeganListener ( http , monitor ) ) <EOL> deploy_root . putChild ( '<STR_LIT:end>' , DeployEndedListener ( http , monitor ) ) <EOL> deploy_root . putChild ( '<STR_LIT>' , DeployAbortedListener ( http , monitor ) ) <EOL> deploy_root . putChild ( '<STR_LIT:error>' , DeployErrorListener ( http , monitor ) ) <EOL> deploy_root . putChild ( '<STR_LIT>' , DeployProgressListener ( http , monitor ) ) <EOL> irc . register_command ( monitor . status ) <EOL> irc . register_command ( monitor . hold ) <EOL> irc . register_command ( monitor . unhold ) <EOL> irc . register_command ( monitor . acquire ) <EOL> irc . register_command ( monitor . aquire ) <EOL> irc . register_command ( monitor . release ) <EOL> irc . register_command ( monitor . jump ) <EOL> irc . register_command ( monitor . kick ) <EOL> irc . register_command ( monitor . refresh ) <EOL> irc . register_command ( monitor . help ) </s>
