ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/COMP/WEBTOOLS/cmsWeb.py
(Generate patch)

Comparing COMP/WEBTOOLS/cmsWeb.py (file contents):
Revision 1.4 by eulisse, Fri May 18 08:47:48 2007 UTC vs.
Revision 1.10 by eulisse, Thu May 29 07:33:21 2008 UTC

# Line 1 | Line 1
1   #!/usr/bin/env python
2   from Framework import BonsaiServer
3   from Framework import Context
4 + from Framework.Logger import Logger
5 + from Framework.Logger import g_Logger
6   from optparse import OptionParser
7   from Framework import CmdLineArgs
8 + import sys
9 + import os
10 + import getpass
11 + from os.path import abspath
12 + import errno
13  
14   class Cfg:
15      def __init__ (self):
16          # TODO: make it a property.
17          self.installRoot = __file__.rsplit ("/", 1)[0]
18  
19 + class CommandFactory (object):
20 +    def __init__ (self, context, opts, args):
21 +        self.context = context
22 +        self.registry = {"start": StartCommand,
23 +                         "status": StatusCommand,
24 +                         "stop": StopCommand}
25 +        self.opts, self.args = opts, args
26      
27 < if __name__ == '__main__':
28 <    context = Context ()
29 <    context.addService (OptionParser ())
30 <    context.OptionParser ().add_option ("--profile",
31 <                                        help="start server in profiler mode",
32 <                                        default=False,
33 <                                        action="store_true",
34 <                                        dest="profile")
35 <    def stripTrailingSlash (option, opt_str, value, parser, *args, **kwargs):
36 <        setattr(parser.values, option.dest, value.rstrip ("/"))
37 <        
38 <    context.OptionParser ().add_option ("--base-url",
39 <                                        help="Base URL for the server (for usage behind a proxy).",
40 <                                        default="http://localhost:8030",
41 <                                        dest="baseUrl",
42 <                                        action="callback",
43 <                                        callback=stripTrailingSlash,
44 <                                        type="str",
45 <                                        nargs=1)
27 >    def createByName (self, name):
28 >        try:
29 >            obj = self.registry[name] ()
30 >        except KeyError:
31 >            return None
32 >        obj.context = self.context
33 >        obj.opts = self.opts
34 >        obj.args = self.args
35 >        return obj
36 >
37 > class Command (object):
38 >    def __init__ (self):
39 >        self.context = None
40 >        self.opts = None
41 >        self.args = None
42 >
43 >    def finish (self):
44 >        pass
45 >
46 > def checkIfPidRunning (pid):
47 >    try:
48 >        os.kill(pid, 0)
49 >        return True
50 >    except OSError, err:
51 >        return err.errno == errno.EPERM
52 >
53 > def getPidFromFile (filename):
54 >    try:
55 >        return int (open (filename).read ().strip ())
56 >    except ValueError:
57 >        print "Invalid lockfile format for %s." % filename
58 >        print "Cannot detect status."
59 >        sys.exit (2)
60 >
61 > class StatusCommand (Command):
62 >    def run (self):
63 >        filename = abspath (self.opts.pidFile)
64 >        try:
65 >            pid = getPidFromFile (filename)
66 >            if checkIfPidRunning (pid):
67 >                print "cmsWeb is running as pid %s" % pid
68 >                sys.exit (0)
69 >            print "cmsWeb not running."
70 >        except IOError:
71 >            print "File %s does not exists." % opts.pidFile
72 >            print "Cannot detect status."
73 >            sys.exit (2)
74 >
75 > class StopCommand (Command):
76 >    def run (self):
77 >        filename = abspath (self.opts.pidFile)
78 >        username = getpass.getuser ()
79 >        
80 >        try:
81 >            pid = getPidFromFile (filename)
82 >            if self.opts.forceKill == True:
83 >                print "Sending SIGKILL to pid %s" % pid
84 >                os.kill (pid, 9)
85 >                sys.exit (0)
86 >            print "Sending SIGTERM to pid %s" % pid
87 >            os.kill (pid, 15)
88 >        except OSError, err:
89 >            if err.errno == errno.EPERM:
90 >                print "Pid %s is not owned by user %s. Cannot stop it." % (pid, username)
91 >                sys.exit (2)
92 >            else:
93 >                print "Pid %s does not exists. Please remove the lock file %s." % (pid, filename)
94 >        except IOError:
95 >            print "File %s does not exists." % self.opts.pidFile
96 >            print "Cannot detect status."
97 >            sys.exit (2)
98 >        
99 >
100 > class StartCommand (Command):
101 >    def run (self):
102 >        app = BonsaiServer (self.context)
103 >        opts, args = self.context.OptionParser ().parse_args ()
104 >        filename = abspath (self.opts.pidFile)
105 >        try:
106 >            pid = getPidFromFile (filename)
107 >            if checkIfPidRunning (pid):
108 >                print "A process %s is alredy running using lock file %s. Nothing is done." % (pid, filename)
109 >                sys.exit (0)
110 >            else:
111 >                print "Process %s died unexpectedly. Removing lockfile %s." % (pid, filename)
112 >                os.unlink (filename)
113 >        except IOError:
114 >            # TODO: this should be a warning.
115 >            g_Logger.trace ("File %s does not exists. Will be created." % filename)
116 >        
117 >        open (filename, 'w').write (str (os.getpid ()))
118 >        self.context.addService (CmdLineArgs (self.context.OptionParser ()))
119 >        self.context.addService (Cfg ())
120 >        if opts.profile:
121 >            import pstats
122 >            try:
123 >                import cProfile as profile
124 >            except ImportError:
125 >                import profile
126 >            profile.run ('app.start ()', 'bonsaiProfiler')
127 >
128 >            p = pstats.Stats ('bonsaiProfiler')
129 >            p.strip_dirs().sort_stats (-1).print_stats()        
130 >        else:
131 >            app.start ()
132      
133 <    app = BonsaiServer (context)
133 >    def finish (self):
134 >        filename = abspath (self.opts.pidFile)
135 >        try:
136 >            os.unlink (filename)
137 >        except IOError:
138 >            print "Unable to remove lock file %s" % filename
139 >
140 > def getValidOptions (args):
141 >    validArguments = ["start",
142 >                      "stop",
143 >                      "restart",
144 >                      "status"]
145 >    validOptions = ["--cfg", "--force-kill", "--pid-file",
146 >                    "--log-file", "--log-level"]
147 >
148 >    result = []
149 >    for i in range (0, len (args)):
150 >        arg = sys.argv[i]
151 >        if arg in validArguments:
152 >            result.append (args[i])
153      
154 <    opts, args = context.OptionParser ().parse_args ()
155 <    context.addService (CmdLineArgs (context.OptionParser ()))
156 <    context.addService (Cfg ())
154 >    for i in range (0, len (args)):
155 >        option = args[i]
156 >        if option in validOptions:
157 >            result.append (option)
158 >            result.append (args[i+1])
159 >    return result
160  
161 <    if opts.profile:
162 <        import pstats
163 <        try:
164 <            import cProfile as profile
165 <        except ImportError:
166 <            import profile
167 <        profile.run ('app.start ()', 'bonsaiProfiler')
168 <        
169 <        p = pstats.Stats('bonsaiProfiler')
170 <        p.strip_dirs().sort_stats(-1).print_stats()        
171 <    else:
172 <        app.start ()
161 > class CmsWebApplication (object):
162 >    def __init__ (self):
163 >        self.context = Context ()
164 >        self.context.addService (OptionParser ())
165 >        self.parser = self.context.OptionParser ()
166 >        self.__addOptions ()
167 >        
168 >    def __addOptions (self):
169 >        self.parser.add_option ("--profile",
170 >                           help="start server in profiler mode",
171 >                           default=False,
172 >                           action="store_true",
173 >                           dest="profile")
174 >
175 >        self.parser.add_option ("--pid-file",
176 >                           help="File in which it is specified the pid of wanted instance",
177 >                           default="pid.txt",
178 >                           dest="pidFile",
179 >                           metavar="FILE")
180 >
181 >        self.parser.add_option ("--force-kill",
182 >                           help="Uses SIGKILL rather than SIGTERM",
183 >                           default=False,
184 >                           action="store_true",
185 >                           dest="forceKill",
186 >                           metavar="FILE")
187 >                          
188 >        def openFilename (option, opt_str, value, parser, *args, **kwargs):
189 >            try:
190 >                f=open (value, 'a')
191 >            except IOError:
192 >                print "WARNING: Unable to open log file %s. Using stderr." % value
193 >                f=sys.stderr
194 >            setattr (parser.values, option.dest, f)
195 >        
196 >        self.parser.add_option ("--log-file",
197 >                           help="FILE to which redirect log messages",
198 >                           dest="logFile",
199 >                           default=sys.stderr,
200 >                           action="callback",
201 >                           callback=openFilename,
202 >                           metavar="FILENAME",
203 >                           type="str",
204 >                           nargs=1)
205 >                          
206 >        self.parser.add_option ("--log-level",
207 >                            help="detail LEVEL for the main log",
208 >                            dest="logLevel",
209 >                            default=10,
210 >                            metavar="LEVEL",
211 >                            type="int")
212 >    
213 >    def run (self):
214 >        if "--help" in sys.argv:
215 >            g_Logger.detailLevel = -100
216 >        validOptions = getValidOptions (sys.argv)
217 >
218 >        opts, args = self.parser.parse_args (args=validOptions)
219 >
220 >        g_Logger.stream = opts.logFile
221 >        if "--help" not in sys.argv:
222 >            g_Logger.detailLevel = opts.logLevel
223 >        
224 >        if not len (args):
225 >            args = ["start"]
226 >        
227 >        factory = CommandFactory (self.context, opts, args)
228 >        startCommand = factory.createByName (args[0])
229 >        if not startCommand:
230 >            "Command %s not known." % args[0]
231 >            sys.exit (1)
232 >        startCommand.run ()
233 >        startCommand.finish ()
234 >
235 > if __name__ == '__main__':
236 >    app = CmsWebApplication ()
237 >    app.run ()

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines