#! /usr/bin/env python

#############################################################
#                                                           #
#   Author: Sandrine Larroude                               #
#   Organization:'Biological Software and Databases' Group, #
#                Institut Pasteur, Paris.                   #
#   Distributed under GPLv2 Licence. Please refer to the    #
#   COPYING.LIB document.                                   #
#                                                           #
#############################################################

import os, sys, time, shutil, getopt
from datetime import datetime

#append Mobyle Home to the search modules path
MOBYLEHOME = None
if os.environ.has_key('MOBYLEHOME'):
    MOBYLEHOME = os.environ['MOBYLEHOME']
if not MOBYLEHOME:
    sys.exit('MOBYLEHOME must be defined in your environment')

if ( MOBYLEHOME ) not in sys.path:
    sys.path.append( MOBYLEHOME )
if ( os.path.join( MOBYLEHOME , 'Src' ) ) not in sys.path:
    sys.path.append( os.path.join( MOBYLEHOME , 'Src' ) )


import Mobyle.ConfigManager
import Mobyle.Session
import Mobyle.Utils


""" Cleaner of jobs and anonymous sessions """

def cleanjob(config, delay, quiet, ctime, log= None):
    
    listofstat = ["finished", "error", "killed"]
    path = config.results_path()
    er = 0
    
    if os.path.isdir(path):
        
        jobres = os.listdir(path)
        # ADMINDIR is excluded of the directory list because it is not concerned by the cleaning
        if os.path.isdir(os.path.join(path,"ADMINDIR")):
            jobres.remove("ADMINDIR")
        for p in jobres:
            pp = os.path.join(path, p)
            # to exclude the possible files existing in the directory
            if not os.path.isdir(pp):	continue
            jobdir = os.listdir(pp)
            for q in jobdir:
                qp = os.path.join(pp, q)
                # to exclude the possible files existing in the directory
                if not os.path.isdir(qp): 	continue
                # extraction of the job status
                jobstatus = Mobyle.Utils.Admin(qp).getStatus()
                # to retrieve the last modification time
                mtime = os.path.getmtime(qp)
                # test if the job is erasable or not
                if jobstatus[0] in listofstat and int( ctime - mtime ) > delay:
                    try:
                        shutil.rmtree(qp)
                    except OSError, e:
                        er = 1
                        msg = "Error with this job directory which cannot be cleaned %s --> %s" % (q, e)
                        logguer(msg, log)
                        if not quiet:
                            print >>sys.stderr, msg
                        continue
    else:
        er = 1
        msg = "The job result path does not exist. Please check your RESULTS_PATH in the conf file."
        logguer(msg, log)
        if not quiet:
            print >>sys.stderr, msg
        
    return er
	
def cleansession(config, delay, quiet, ctime, log= None):
    
    path = config.user_sessions_path()
    er = 0
    
    if os.path.isdir(path):
        
        if config.anonymousSession() != "no":
            path = os.path.join(path, "anonymous")
            session_a = os.listdir(path)
            if session_a:
                for s in session_a:
                    sp = os.path.join(path, s)
                    # to exclude the possible files existing in the directory
                    if not os.path.isdir(sp):	continue  
                    mtime = os.path.getmtime(sp)
                    # To get the jobs attached to this session
                    j = Mobyle.Session.Session(sp, s, config)
                    try:
                        jobs = j.getAllJobs()
                        # test if the anonymous session is erasable or not
                        if not jobs and int(ctime - mtime) > delay:
                            try:
                                shutil.rmtree(sp)
                            except OSError, e:
                                er = 1
                                msg = "Error with this anonymous session directory which cannot be cleaned %s --> %s" % (s, e)
                                logguer(msg, log)
                                if not quiet:
                                    print >>sys.stderr, msg
                                continue
                    except Mobyle.MobyleError.SessionError, m:
                        
                        spc = os.listdir(sp)
                        # remove a session directory without ".session.xml"
                        if '.session.xml' not in spc:
                            logguer("There is no .session.xml in this anonymous session %s" %  s,log) 
                            shutil.rmtree(sp)
                        else:
                            er = 1
                            msg = "Mobyle error with this anonymous session %s --> %s" % (s, m)
                            logguer(msg, log)
                            if not quiet:    
                                print >>sys.stderr, msg
                        continue
                    
    else:
        er = 1
        msg = "The session path does not exist. Please check your USER_SESSIONS_PATH in the conf file."
        logguer(msg, log)
        if not quiet:
            print >>sys.stderr, msg

    
    return er 

def logguer(msg, log= None):
    
    if log:
        print >>log, "[%s]: " % datetime.now().strftime("%Y-%m-%d %H:%M:%S") + msg


if __name__ == "__main__":
    
    config = Mobyle.ConfigManager.Config()
    ct = time.time() # current time
    
    # Part to configure the function call by command line
    opts, args = None, None
    message = """
    Usage : mobclean [OPTION]
    Clean Result or Anonymous sessions of Mobyle (Result by default)

    options:
        -J          Clean Job Results.
        -S          Clean anonymous sessions.
        -d <val>    Delete directories older than <val> days ( positive integer value ).
        -h          Display this help and exit.
        -q          Without error messages (verbose).
        -l <val>    path to the Logfile where put the logs
        
    examples:
        mobclean 	--> By default, the cleaning of jobs & sessions is done
        mobclean -S -d 2
        mobclean -J -S
        mobclean --help
    """
    # By default, delay is the one of the config file
    d = config.remainResults()
   
    try:
        opts, args = getopt.getopt(sys.argv[1:], "JShqd:l:", ["job", "session", "help", "quiet", "delay=", "logfile="])
    except getopt.GetoptError:
        print message
        sys.exit(1)
    
    session, job, q, er = False , False , False, 0

    for opt, val in opts:
        if opt in ( "-h","--help"):
            print message
            sys.exit(0)
        if opt in ( "-d", "--delay" ):
            d = val
        elif opt in ( "-J" , "--job"):
            job = True
        elif opt in ( "-S", "--session" ):
            session = True
        elif opt in ( "-q", "--quiet" ):
            q = True
        elif opt in ( "-l", "--logfile" ):
            try:
                logfile = open (os.path.abspath(val) , "a")
            except:
                print >>sys.stderr,"No logs available for this run.Error trying to open %s \n"% l
                logfile = None         

    try:
        d = int(d)
        if d < 0:
            print message
            sys.exit(1)
        else:
            d = d * 24 * 60 * 60  # conversion from day to second
    except ValueError:
        print >>sys.stderr,"The number of days is invalid. Check that it is an integer.\n" + message
        sys.exit(1)
        
    try:      
        # By default, the cleaning of jobs & sessions is done
        if not opts or not (job and session):
            erj = cleanjob(config, delay=d, quiet=q, ctime=ct, log = logfile)
            ers = cleansession(config, delay=d, quiet=q, ctime=ct, log = logfile)
            er = erj or ers
        elif job:
            er = cleanjob(config, delay=d, quiet=q, ctime=ct, log = logfile)
        elif session:
            er = cleansession(config, delay=d, quiet=q, ctime=ct, log = logfile)
    finally:
        if logfile:
            logfile.close()
        
    sys.exit (er)
    
