control.py :  » Wiki » Cloud-Wiki » cloudwiki-2.1 » cloud_wiki » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Wiki » Cloud Wiki 
Cloud Wiki » cloudwiki 2.1 » cloud_wiki » control.py
#!/usr/bin/env python

import os, sys, time

from glob import glob
from optparse import OptionParser
from exceptions import ImportError,ValueError
from sets import Set

from html import normalize
from database import Database,DatabaseError
from server import Server
from wiki import Wiki
from exed import external_edit

def get_pid( db ):
    try:
        return int( db.getConfig( 'pid' ) )or None
    except:
        return None

def stop_server_posix( db, signal=None ):
    from signal import SIGTERM
    
    if signal == None: signal = SIGTERM

    pid = get_pid( db )

    if pid is not None:
        try: os.kill( pid, signal )
        except:
            print "The server appears to have been terminated abnormally.  Removing"
            print "pid entry from database."
        else:
            print "Done."
    else:
        print "There does not appear to be a server associated with this"
        print "database."

def kill_server_posix( db, signal=None ):
    from signal import SIGKILL

    if signal == None: signal = SIGKILL

    pid = get_pid( db )

    if pid is not None:
        print "Killing server.."
        try: os.kill( pid, signal )
        except: pass
    else:
        print "There does not appear to be a server associated with this"
        print "database."

    db.delConfig( "pid" )

def kill_server_win32( db ):
    pid = get_pid( db )

    if pid is not None:
        print "Killing server.."
        import win32api
        handle = win32api.OpenProcess(1, 0, pid)
        win32api.TerminateProcess(handle, 0)
    else:
        print "There does not appear to be a server associated with this"
        print "database."

    db.delConfig( "pid" )

def stop_server( db, signal=None ):
    if sys.platform == 'win32':
        kill_server_win32( db )
    else:
        stop_server_posix( db, signal )

def kill_server( db, signal=None ):
    if sys.platform == 'win32':
        kill_server_win32( db )
    else:
        kill_server_posix( db, signal )

def start_server( wiki ):
    pid = get_pid( wiki.getDatabase() )

    if pid:
        print "There is already a cloud wiki server running on this database."
        print "Try cloud-wiki stop, first, to terminate the old server.  If"
        print "the server will not respond to the stop command, use cloud-wiki"
        print "kill."
    else:
        print "Starting server.."
        run_server( wiki )

def restart_server( wiki ):
    stop_server( wiki.getDatabase() )
    time.sleep(2)
    start_server( wiki )

def get_list( db ):
    return db.getNodeKeys( )
    
def get_node( db, key ):
    key = normalize( key )
    node = db.fetchNode( key )
    content = node.getContent() 
    if content is not None:
        return content
    else:
        print "  Node not found."
        return None
        
def put_node( db, key, content, user ):
    key = normalize( key )
    node = db.fetchNode( key )
    node.setContent( content, user ) 

def edit_node( db, key, user ):
    key = normalize( key )
    node = db.fetchNode( key )
    content = node.getContent() 

    print "Launching editor for '%s'" % (key,)

    content = external_edit( content )

    if content is not None:
        print "Updating content for '%s'" % (key,)
        node.setContent( content, user )

def node_html( db, key ):
    key = normalize( key )
    node = db.fetchNode( key )
    content = node.getStaticPage()
    if content is not None:
        return content
    else:
        return None

def rm_node( db, key ):
    node = db.fetchNode( key )
    
    if node.getContent() is not None:
        db.removeNode( key )
    else:
        print "  Node not found."

def halt_server( db, server ):
    db.delConfig( "pid" )
    sys.exit( 0 )

def run_server_posix( wiki ):
    from signal import signal,SIGHUP,SIGTERM,SIG_IGN
    
    pid = os.fork()

    if pid > 0: 
        return ( 0 )
    else:
        os.setsid()
        pid = os.getpid()
        wiki.getDatabase().setConfig( "pid", pid )

        signal( SIGHUP, SIG_IGN )
        signal(
            SIGTERM,
            lambda sig, frame: halt_server( 
                wiki.getDatabase(), wiki.getServer() 
            )
        )

        wiki.genInterfaces() # It's important to do this before abandoning cwd
        os.chdir( "/" ) # Prevent ourselves from locking the cwd.
        wiki.runForever()

def run_server_win32( wiki ):
    pid = os.getpid()
    wiki.getDatabase().setConfig( "pid", pid )
    wiki.genInterfaces() # It's important to do this before abandoning cwd
    os.chdir( "/" ) # Prevent ourselves from locking the cwd.
    wiki.runForever()
    
def run_server( wiki ):
    if sys.platform == 'win32':
        return run_server_win32( wiki )
    else:
        return run_server_posix( wiki )
        
def get_config( db, key ):
    return db.getConfig( key )
    
def set_config( db, key, value ):
    db.setConfig( key, value )

def rm_config( db, key ):
    db.delConfig( key )

def ls_config( db ):
    for key in db.getConfigKeys():
        yield key
    
def set_passwd( db, key, value, cook = True ):
    if cook and ( db.getConfig( "site-auth" ) == "md5" ): 
        from md5 import md5
        db.setPassword( key, md5( value ).hexdigest() )
    else:
        db.setPassword( key, value )
        
def rm_passwd( db, key ):
    db.delPassword( key )

def ls_users( db ):
    for username in db.getUsernames():
        yield username

def migrate( wiki ):
    db = wiki.getDatabase()
    
    dbMajor, dbMinor = db.getVersion()
    svMajor, svMinor = wiki.getVersion()
    
    if( dbMajor != svMajor )or( dbMinor != svMinor ):
        from migration import migrate_database
        migrate_database( db, svMajor, svMinor )
    else:
        print "No migration is required at this time."

def check_version( wiki ):
    return wiki.getVersion() == wiki.getDatabase().getVersion()

def ls_refs( db, key ):
    for ref in db.fetchReferencesTo( key ):
        yield ref

def ls_links( db, key ):
    for ref in db.fetchReferencesFrom( key ):
        yield ref

topical_help = {
    'summary':(
        'Usage: cloud-wiki <option>* <command> <argument>*',
        '',
        'To view a list of global cloud-wiki options, see:',
        '   cloud-wiki help options.',
        'To view a list of cloud-wiki commands, see:',
        '   cloud-wiki help commands.',
        'For more information, visit http://cloudwiki.sourceforge.net for',
        'up to date information.'
    ),
    'commands':(
        'Commands understood by cloud-wiki:',
        '',
        'backup     Backs up all nodes in the database to the specified path.',
        'config     Manipulates wiki configuration settings.',
        'edit       Launches an external editor, specified by the EDIT ',
        '           environment variable.',
        'get        Retrieves listed nodes from the database.',
        'links      Returns a set of local links in the listed nodes.',
        'ls         Lists the titles of all the nodes in the database.',
        'help       Provides documentation for the cloud-wiki utility.',
        'kill       Forces a nonresponsive wiki server to terminate.',
        'passwd     Manipulates passwords in the wiki user table.',
        'rawpasswd  As passwd, but does not hash the password prior to storage.',
        'refs       Returns a set of references to the listed nodes.',
        'restart    Restarts the wiki server in the background.',
        'restore    Restores a list of previously backed up nodes.',
        'rm         Removes a node from the wiki database.',
        'start      Starts the wiki server in the background.',
        'stop       Stops the wiki server.',
        '',
        'For more information about a given command, see:',
        '    cloud-wiki help <command>',
        'For information about other cloud-wiki topics, see:',
        '    cloud-wiki help'
    ),
    'options':(
        "Global options understood by cloud-wiki:",
        "",
        "-d, --database <path>   Specifies a path to the wiki database.",
        "-i, --initialize        If database file does not exist, create one.",
        "-l, --logfile <path>    Specified the path to the logfile.",
        "-p, --port <port>       Overrides the wiki's default port.  Usually",
        "                        used with the start and restart commands.",
        "-u, --user <user>       Attribute all changes made to nodes in the",
        "                        database to the specified user.",
        "-v, --verbose           Causes all logging output to be diverted to",
        "                        the console.",
        "",
        'For information about other cloud-wiki topics, see:',
        '    cloud-wiki help'
    ),
    'backup':(
        'Usage: cloud-wiki <option>* backup <path>',
        '',
        'Backs up all nodes in the database in the specified directory.  Node',
        'files will be given a name equivalent to their title.  This function',
        'is intended for periodic full backups of the wiki as insurance',
        'catastrophic failure, or hostile editor problems.'
    ),
    'edit':(
        'Usage: cloud-wiki <option>* edit <title>+',
        '',
        'Opens an external editor for each node in turn, permitting you to',
        'use your favorite text editor to edit node content.  The EDITOR  ',
        'environment variable is used to determine what editor to use. ',
        '',
        'On Mac OS X, the author recommends EDITOR=see -w, for example.',
        '',
        'When the editor process exits successfully, the node is updated with',
        'the new content.'
    ),
    'ls':(
        'Usage: cloud-wiki <option>* ls',
        '',
        'Lists the titles of nodes in the wiki database, one per line.'
    ),

    'get':(
        'Usage: cloud-wiki <option>* get <path>+',
        '',
        'Gets each node specified by the last path component of path from ',
        'the database, and stores its contents at the specified path.',
    ),

    'restore':(
        'Usage: cloud-wiki <option>* restore <path>+',
        '',
        'Loads each node specified by the last path component of path from ',
        'from the filesystem and updates the database with it.  Useful for ',
        'restoring backed up nodes.'
    ),

    'rm':(
        'Usage: cloud-wiki <option>* rm <title>+',
        '',
        'Deletes each specified node from the database, and all change ',
        'information corresponding with the node.'
    ),

    'start':(
        'Usage: cloud-wiki <option>* start',
        '',
        'Starts the wiki server, associating the process with the wiki ',
        'database, then returns to the command prompt.'
    ),

    'stop':(
        'Usage: cloud-wiki <option>* stop',
        '',
        'Stops the wiki server associated with the database, or clears a ',
        'stale PID from the database.'
    ),

    'restart':(
        'Usage: cloud-wiki <option>* restart',
        '',
        'Equivalent to invoking cloud-wiki stop, then cloud-wiki start'
    ),

    'kill':(
        'Usage: cloud-wiki <option>* kill',
        '',
        'Similar to stop, but instead of politely instructing the process to',
        'terminate, sends a SIGKILL which will halt the process immediately.',
        '',
        'Only use this as a last resort -- cloud-wiki stop should be',
        'sufficient for most situations.'
    ),

    'config':(
        'Usage: cloud-wiki <option>* config <key>(:(<value>?)?)*',
        '',
        'Manipulates configuration settings stored in the database.  Cloud ',
        'wiki uses a key:value system to handle site configuration, and ',
        'stores the information in a table in the database.  Documentation ',
        'about configuration settings should be available at: ',
        '    http://cloudwiki.sourceforge.net',
        '',
        'Examples:',
        '',
        'cloud-wiki config',
        '    Returns a list of all non-default configuration settings in',
        '    the database.',
        'cloud-wiki config site-title',
        '    Returns the current configuration setting of "site-title"',
        'cloud-wiki config site-title:\'Cloud Wiki\'',
        '    Configures the title of the wiki site to "Cloud Wiki"'
    ),

    'passwd':(
        'Usage: cloud-wiki <option>* passwd <user-name>(:(<password>?)?)*',
        '',
        'Manipulates password entries in the database.  This is only valid',
        'on servers that use authentication modules that use the wiki\'s',
        'user database, like "md5" and "cloud" authenicators."',
        '',
        'If Cloud Wiki is configured to use MD5 authentication, it will',
        'automatically hash the supplied password.',
        '',
        'Examples:',
        '',
        'cloud-wiki passwd',
        '    Returns a list of all non-default configuration settings in',
        '    the database.',
        'cloud-wiki passwd \'Joe User\'',
        '    Exits nonzero if Joe User is not in the database."',
        'cloud-wiki passwd \'Joe User\':obvious-password',
        '    Assigns "obvious-password" as Joe User\'s password.'
    ),
    
    'rawpasswd':(
        'Usage: cloud-wiki <option>* rawpasswd <user-name>(:(<password>?)?)*',
        '',
        'Manipulates password entries in the database.  This is only valid',
        'on servers that use authentication modules that use the wiki\'s',
        'user database, like "md5" and "cloud" authenicators."',
        '',
        'Unlike passwd, this command actually enters the supplied password',
        'directly, instead of an MD5 hash.  This is useful if you are',
        'simply copying the password from another password table that uses',
        'MD5, like PHPBB',
        '',
        'Examples:',
        '',
        'cloud-wiki passwd',
        '    Returns a list of all non-default configuration settings in',
        '    the database.',
        'cloud-wiki passwd \'Joe User\'',
        '    Exits nonzero if Joe User is not in the database."',
        'cloud-wiki passwd \'Joe User\':obvious-password',
        '    Assigns "obvious-password" as Joe User\'s password.'
    ),
    
    'migrate':(
        'Usage: cloud-wiki <option>* migrate',
        '',
        'Updates a Cloud Wiki database to match the current version of the',
        'server.  Normally invoked after an upgrade to regenerate node html.',
    ),

    'refs':(
        'Usage: cloud-wiki <option>* refs <key>+',
        '',
        'Produces a list of node keys that refer to the specified keys.'
    ),
    
    'links':(
        'Usage: cloud-wiki <option>* links <key>+',
        '',
        'Produces a list of local links contained by the listed nodes.'
    )
}

topic_aliases = {
    'command':'commands',
    'option':'options'
}

def display_help( topic=None ):
    if topic is None: topic = 'summary'
   
    try:
        print '\n'.join( topical_help[ topic_aliases.get( topic, topic ) ] )
    except:
        print 'Information on that topic is not available.  Try cloud-wiki help'

def main( args ):
    parser = OptionParser()
    parser.add_option( 
        "-d", "--database", dest="database",
        help="wiki database file path",
        default="wiki.db",
        metavar="FILE"
    )
    parser.add_option(
        "-i", "--initialize", dest="initialize",
        action='store_true',
        help="if database file does not exist, create one",
        default=False
    )
    parser.add_option(
        "-l", "--logfile", dest="logfile",
        help="use the specified logfile, instead of the default",
        metavar="FILE",
        default=None
    )
    parser.add_option(
        "-p", "--port", dest="port",
        type='int',
        help="use the specified port, instead of the default",
        metavar="PORT",
        default=None
    )
    parser.add_option(
        "-v", "--verbose", dest="verbose",
        action='store_true',
        help="output all SQL transactions to stdout.",
        default=False
    )
    parser.add_option(
        "-u", "--user", dest="user",
        default="",
        metavar="USER"
    )

    options, args = parser.parse_args( args )
    
    if len(args) == 0:
        print "Try cloud-wiki help to view a list of commands."
        return ( 3 )
    
    cmd = args[0].lower()
    
    if options.verbose:
        options.logfile = sys.stdout

    try:
        wiki = Wiki( 
            options.database, 
            options.logfile, 
            options.port, 
            options.initialize 
        ) 
    except DatabaseError:
        print "Could not access your wiki database. Aborting."
        return (4)

    user = options.user;

    if cmd == 'migrate':
        migrate( wiki )        
        return (0)
    elif not check_version( wiki ):
        print "Your database's version is out of sync with this server's version. You must use 'cloud-wiki migrate' to migrate the database."
        return (5)
        
    db = wiki.getDatabase()

    if cmd == 'backup':
        dest = args[1]
        
        for key in get_list( db ):
            print "Getting %s.." % (key,)

            data = get_node( db, key )
            if data is not None: open( dest + "/" + key, "w" ).write( data )
        print "Done."
    elif cmd == 'get-html':
        #TODO: Does not support get-html with an extension..
        for fn in args[1:]:
            key = normalize( os.path.basename( fn ) )
            
            print "Getting %s to %s.." % ( key, fn )
            data = node_html( db, key )
            if data is not None:
                open( fn, "w" ).write( data )

        print "Done."
    elif cmd == 'backup-html':
        dest = args[1]
        
        for key in get_list( db ):
            print "Getting %s.." % (key,)

            data = node_html( db, key )
            if data is not None: 
                open( dest + "/" + key + ".html", "w" ).write( data )

        print "Copying Stylesheet.." 
        data = wiki.getStylesheet()
        if data is not None: open( dest + "/style.css", "w" ).write( data )

        print "Done."
    elif cmd ==  'ls':
        for key in get_list( db ):
            print key
    elif cmd == 'get':
        for fn in args[1:]:
            key = normalize( os.path.basename( fn ) )
            
            print "Getting %s to %s.." % ( key, fn )
            data = get_node( db, key )
            if data is not None:
                open( fn, "w" ).write( data )

    elif cmd ==  'restore':
        for pattern in args[1:]:
            for fn in glob( pattern ):
                key = normalize( os.path.basename( fn ) )

                print "Putting %s in %s.." % ( fn, key )
                put_node( 
                    db, key, ''.join( open( fn, "r" ).readlines() ), user 
                )
        print "Done."
    elif cmd == 'edit':
        for fn in args[1:]:
            edit_node( db, fn, user )
    elif cmd ==  'rm':
        for key in args[1:]:
            print "Removing %s.." % (key,)
            rm_node( db, normalize( key ) )
        print "Done."
    elif cmd == 'start':
        start_server( wiki )
    elif cmd == 'stop':
        stop_server( db )
    elif cmd == 'restart':
        restart_server( wiki )
    elif cmd == 'kill':
        kill_server( db )
    elif cmd ==  'config':
        ops = args[1:]
        if ops:
            for op in args[1:]:
                op = op.strip()
                try:
                    key, value = op.split( ':', 1 )
                except ValueError:
                    value = get_config(db, op)
                    if value is None:
                        print '%s is not set.' % (op,)
                    else:
                        print '%s:%s' % (op, value)
                    continue
                
                if value:
                    set_config( db, key, value )
                    print "%s:%s" % (key, value)
                else:
                    rm_config( db, key )
                    print "Removed %s." % (key,)
        else:
            for key in ls_config( db ):
                print "%s:%s" % (key, get_config( db, key ))
    elif cmd ==  'passwd':
        ops = args[1:]
        if ops:
            for op in args[1:]:
                op = op.strip()
                key, value = op.split( ':', 1 )
                
                if value:
                    set_passwd( db, key, value )
                    print key
                else:
                    rm_passwd( db, key )
                    print "Removed %s." % (key,)
        else:
            for username in ls_users( db ):
                print username
    elif cmd ==  'rawpasswd':
        ops = args[1:]
        if ops:
            for op in args[1:]:
                op = op.strip()
                key, value = op.split( ':', 1 )
                
                if value:
                    set_passwd( db, key, value, False )
                    print key
                else:
                    rm_passwd( db, key )
                    print "Removed %s." % (key,)
        else:
            for username in ls_users( db ):
                print username
    elif cmd == 'refs':
        results = Set()

        for fn in args[1:]:
            for ref in ls_refs( db, normalize( os.path.basename( fn ) ) ):
                results.add( ref )

        for ref in results:
            print ref
    elif cmd == 'links':
        results = Set()

        for fn in args[1:]:
            for ref in ls_links( db, normalize( os.path.basename( fn ) ) ):
                results.add( ref )

        for ref in results:
            print ref
    elif cmd == 'help':
        if len(args) > 1:
            display_help( args[1].lower() )
        else:
            display_help( )
    else:
        print "Unrecognized command or option \"%s\"" % (cmd,)
        return( 3 )

    return( 0 )
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.