#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-


# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
#     Romain Chantereau <rchantereau@entrouvert.com>
#     Nicolas Clapiès <nclapies@easter-eggs.org>
#     Pierre-Antoine Dejace <padejace@entrouvert.be>
#     Thierry Dulieu <tdulieu@easter-eggs.com>
#     Florent Monnier <monnier@codelutin.com>
#     Cédric Musso <cmusso@easter-eggs.org>
#     Frédéric Péters <fpeters@entrouvert.be>
#     Benjamin Poussin <poussin@codelutin.com>
#     Emmanuel Raviart <eraviart@entrouvert.com>
#     Sébastien Régnier <regnier@codelutin.com>
#     Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
#     Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
#     Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
#     Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
#     Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


__doc__ = """Glasnost Controller"""

__version__ = '$Revision$'[11:-2]


import __builtin__
import ConfigParser
import locale
import marshal
import os
import signal
import sys
import time

glasnostPythonDir = '/usr/local/lib/glasnost-devel' # changed on make install
sys.path.insert(0, glasnostPythonDir)

import glasnost
import glasnost.common.context as context
from glasnost.common.tools import *
import glasnost.common.tools_new as commonTools

verbose = 0

config = ConfigParser.ConfigParser()
config.readfp(open(commonTools.configDir + '/config'))

servers = ['Dispatcher',]
if 'Gateway' in config.sections():
    servers += ['Gateway',]
if 'Cache' in config.sections():
    servers += ['Cache',]

servers += [x for x in config.sections() if x.endswith('Server')]

def doStart():
    if len(sys.argv) > 2 and sys.argv[2] == '--simulate':
        print 'Would start Glasnost (%d servers):' % len(servers)
        for server in servers:
            print ' ', server
        return
        
    print 'Starting Glasnost (%d servers) ' % len(servers),
    sys.stdout.flush()
    for server in servers:
        rc = doStartOne(server)
        if rc == 0:
            sys.stdout.write('.')
            sys.stdout.flush()
        else:
            sys.stdout.write('F')
            sys.stdout.flush()
            if verbose:
                logDir = config.get('Misc', 'LogFilesDir')
                if not logDir:
                    continue
                fileName = os.path.join(logDir, '%s.log' % server)
                try:
                    fileInstance = open(fileName,'r')
                except IOError:
                    continue
                print ''.join(fileInstance.readlines()[-10:])
                fileInstance.close()
    print ' done.'

def doStartMissing():
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        processes = [int(x.split()[0]) for x in os.popen('ps ax').readlines() \
            if x.endswith(serverFileName + '\n')]
        if len(processes) == 0:
            if verbose:
                print 'Was missing:', server
            doStartOne(server)


def doStartOne(server):
    serverFileName = '%s/servers/%s/%s.py' % (
            glasnostPythonDir, server, server)
    L = [serverFileName]
    return os.spawnvpe(os.P_WAIT, serverFileName, L, os.environ)

def doStop():
    print 'Stopping Glasnost...',
    sys.stdout.flush()
    for server in servers:
        doStopOne(server)
    print 'done.'

def doStopOne(server):
    serverFileName = '%s/servers/%s/%s.py' % (
            glasnostPythonDir, server, server)
    processes = [int(x.split()[0]) for x in os.popen('ps ax').readlines() \
            if x.endswith(serverFileName + '\n')]
    for process in processes:
        os.kill(process, signal.SIGTERM)

def doRestartOne(server):
    doStopOne(server)
    time.sleep(1)
    doStartOne(server)

def doLogRotate():
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        processes = [int(x.split()[0]) for x in os.popen('ps ax').readlines() \
                if x.endswith(serverFileName + '\n')]
        for process in processes:
            os.kill(process, signal.SIGHUP)


def doMakeHelp(sourceDispatcher):
    helpServers = ['articles', 'atoms', 'cards', 'pagenames',
            'groups', 'rubrics', 'translations', 'uploadfiles']
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        L = [serverFileName, '-s', 'glasnost://%s' % sourceDispatcher,
             '-d', 'glasnost://help', '-y', repr(helpServers)]
        rc = os.spawnvpe(os.P_WAIT, serverFileName, L, os.environ)


def doMakeSystem(sourceDispatcher):
    systemServers = ['articles', 'atoms', 'cards', 'pagenames',
            'groups', 'rubrics', 'translations', 'uploadfiles']
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        L = [serverFileName, '-s', 'glasnost://%s' % sourceDispatcher,
             '-d', 'glasnost://system', '-y', repr(systemServers)]
        rc = os.spawnvpe(os.P_WAIT, serverFileName, L, os.environ)


def doExport(sourceDispatcher):
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        cmdLine = '%s -s glasnost://%s -x "%s"' % (
                serverFileName, sourceDispatcher, os.getcwd())
        rc = os.system(cmdLine)


def doImport(destDispatcher):
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        cmdLine = '%s -i "%s" -d %s' % (
                serverFileName, os.getcwd(), destDispatcher)
        rc = os.system(cmdLine)

def doConvertIds(sourceDispatcher, destDispatcher):
    for server in servers:
        serverFileName = '%s/servers/%s/%s.py' % (
                glasnostPythonDir, server, server)
        L = [serverFileName, '-s', 'glasnost://%s' % sourceDispatcher, \
                '-d','glasnost://%s' % destDispatcher]
        rc = os.spawnvpe(os.P_WAIT, serverFileName, L, os.environ)

def doCompileTal(directory):
    for lang in ['en', 'fr']:
        print 'Compiling templates for %s ' % lang,
        context.push(
                readLanguages = [lang],
                localeDirectoryPath = commonTools.getConfig(
                        'Misc', 'LocaleDir', '/usr/share/locale'),
            )
        try:
            locale.setlocale(locale.LC_COLLATE, (lang, None))
        except locale.Error:
            if lang != 'en':
                continue
        translation = commonTools.translation(
                ['%s-web' % glasnost.applicationName,
                 'glasnost-lyon2003', 'glasnost-weblog', 'glasnost-metis'],
                [lang] )
        __builtin__.__dict__['_'] = translation.gettext

        from glasnost.web.GlasnostTALGenerator import GlasnostTALGenerator
        from TAL.HTMLTALParser import HTMLTALParser
        failures = []
        for root, dir, files in osWalk(directory):
            for file in files:
                if not file.endswith('.tal') and not file.endswith('.html'):
                    continue
                file = os.path.join(root, file)
                p = HTMLTALParser(gen = GlasnostTALGenerator(xml=0))
                try:
                    p.parseFile(file)
                except faults.StringNotAvailableThroughGettext:
                    failures.append(file)
                    sys.stdout.write('-')
                    sys.stdout.flush()
                    continue
                except:
                    failures.append(file)
                    sys.stdout.write('F')
                    sys.stdout.flush()
                    continue
                code = p.getCode()
                marshal.dump(code, open('%sc.%s' % (file, lang), 'w'))
                sys.stdout.write('.')
                sys.stdout.flush()
        print ''
        if verbose and failures:
            print 'Failures:\n  ' + '\n  '.join(failures)

def doCleanTal(directory):
    for lang in ['en', 'fr']:
        for root, dir, files in osWalk(directory):
            files = [os.path.join(root, x) for x in files if \
                     x.endswith('.htmlc.%s' % lang) or \
                     x.endswith('.talc.%s' % lang) ]
            for file in files:
                os.remove(file)

def doUsage():
    print """usage: %s [-v] (start|stop|make-help|make-system|export|import|convert-ids)""" % \
            sys.argv[0]
    print """
 start                start Glasnost servers
 stop                 stop Glasnost servers
 make-help $1         create glasnost://help from glasnost://$1
 make-system $1       create glasnost://system from glasnost://$1
 export $1            export glasnost://$1
 import $1            import glasnost://$1
 convert-ids $1 $2    convert ids from glasnost://$1 to glasnost://$2
 compile-tal $1       compile TAL templates in directory $1 (and its leafs)
 clean-tal $1         remove compiled TAL templates from directory $1
 start-one $1         start Glasnost server named $1
 stop-one $1          stop Glasnost server named $1
 restart-one $1       restart Glasnost server named $1
 start-missing        start Glasnost servers defined but not running
 logrotate            send a signal to servers so that they reopen log files

 -v                   verbose mode (if applicable)
"""
    sys.exit(0)

if hasattr(os, 'walk'):
    osWalk = os.walk
else:
    # Python < 2.3.
    # Directly copied from Python2.3 os.walk function, but without yield.

    def osWalk(top, topdown=1, onerror=None):
        """Directory tree generator."""

        paths = []

        from os.path import join, isdir, islink

        try:
            names = os.listdir(top)
        except os.error, err:
            if onerror is not None:
                onerror(err)
            return

        dirs, nondirs = [], []
        for name in names:
            if isdir(join(top, name)):
                dirs.append(name)
            else:
                nondirs.append(name)

        if topdown:
            paths.append((top, dirs, nondirs))
        for name in dirs:
            path = join(top, name)
            if not islink(path):
                for x in osWalk(path, topdown, onerror):
                    paths.append(x)
        if not topdown:
            paths.append((top, dirs, nondirs))
        return paths


if len(sys.argv) > 1 and sys.argv[1] == '-v':
    verbose = 1
    sys.argv = sys.argv[1:]

if len(sys.argv) == 1:
    doUsage()
elif sys.argv[1] == 'start':
    doStart()
elif sys.argv[1] == 'stop':
    doStop()
elif sys.argv[1] == 'start-one':
    doStartOne(sys.argv[2])
elif sys.argv[1] == 'stop-one':
    doStopOne(sys.argv[2])
elif sys.argv[1] == 'restart-one':
    doRestartOne(sys.argv[2])
elif sys.argv[1] == 'make-help':
    doMakeHelp(sys.argv[2])
elif sys.argv[1] == 'make-system':
    doMakeSystem(sys.argv[2])
elif sys.argv[1] == 'export':
    doExport(sys.argv[2])
elif sys.argv[1] == 'import':
    doImport(sys.argv[2])
elif sys.argv[1] == 'convert-ids':
    doConvertIds(sys.argv[2], sys.argv[3])
elif sys.argv[1] == 'compile-tal':
    doCompileTal(sys.argv[2])
elif sys.argv[1] == 'clean-tal':
    doCleanTal(sys.argv[2])
elif sys.argv[1] == 'logrotate':
    doLogRotate()
elif sys.argv[1] == 'start-missing':
    doStartMissing()
else:
    doUsage()

