root / trunk / twisted / scripts / mktap.py

Revision 25788, 6.3 kB (checked in by exarkun, 6 months ago)

Merge remove-old-plugins-1911

Author: exarkun
Reviewer: therve
Fixes: #1911

Remove the old Twisted plugin API and adjust the two remaining users of it so that
they only use the new Twisted plugin API.

Line 
1 # -*- test-case-name: twisted.scripts.test.test_mktap -*-
2 # Copyright (c) 2001-2008 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 import warnings, sys, os
6
7
8 from twisted.application import service, app
9 from twisted.persisted import sob
10 from twisted.python import usage, util
11 from twisted import plugin
12 from twisted.python.util import uidFromString, gidFromString
13
14 # API COMPATIBILITY
15 IServiceMaker = service.IServiceMaker
16 _tapHelper = service.ServiceMaker
17
18 warnings.warn(
19     "mktap and related support modules are deprecated as of Twisted 8.0.  "
20     "Use Twisted Application Plugins with the 'twistd' command directly, "
21     "as described in 'Writing a Twisted Application Plugin for twistd' "
22     "chapter of the Developer Guide.", DeprecationWarning, stacklevel=2)
23
24
25
26 def getid(uid, gid):
27     """
28     Convert one or both of a string representation of a UID and GID into
29     integer form.  On platforms where L{pwd} and L{grp} is available, user and
30     group names can be converted.
31
32     @type uid: C{str} or C{NoneType}
33     @param uid: A string giving the base-ten representation of a UID or the
34         name of a user which can be converted to a UID via L{pwd.getpwnam},
35         or None if no UID value is to be obtained.
36
37     @type gid: C{str} or C{NoneType}
38     @param uid: A string giving the base-ten representation of a GID or the
39         name of a group which can be converted to a GID via
40         L{grp.getgrnam}, or None if no UID value is to be obtained.
41
42     @return: A two-tuple giving integer UID and GID information for
43         whichever (or both) parameter is provided with a non-C{None} value.
44
45     @raise ValueError: If a user or group name is supplied and L{pwd} or L{grp}
46         is not available.
47     """
48     if uid is not None:
49         uid = uidFromString(uid)
50     if gid is not None:
51         gid = gidFromString(gid)
52     return (uid, gid)
53
54
55
56 def loadPlugins(debug = None, progress = None):
57     tapLookup = {}
58
59     plugins = plugin.getPlugins(IServiceMaker)
60     for plug in plugins:
61         tapLookup[plug.tapname] = plug
62
63     return tapLookup
64
65 def addToApplication(ser, name, append, procname, type, encrypted, uid, gid):
66     if append and os.path.exists(append):
67         a = service.loadApplication(append, 'pickle', None)
68     else:
69         a = service.Application(name, uid, gid)
70     if procname:
71         service.IProcess(a).processName = procname
72     ser.setServiceParent(service.IServiceCollection(a))
73     sob.IPersistable(a).setStyle(type)
74     passphrase = app.getSavePassphrase(encrypted)
75     if passphrase:
76         append = None
77     sob.IPersistable(a).save(filename=append, passphrase=passphrase)
78
79 class FirstPassOptions(usage.Options):
80     synopsis = """Usage:    mktap [options] <command> [command options] """
81
82     recursing = 0
83     params = ()
84
85     optParameters = [
86         ['uid', 'u', None, "The uid to run as.", uidFromString],
87         ['gid', 'g', None, "The gid to run as.", gidFromString],
88         ['append', 'a', None,
89          "An existing .tap file to append the plugin to, rather than "
90          "creating a new one."],
91         ['type', 't', 'pickle',
92          "The output format to use; this can be 'pickle', 'xml', "
93          "or 'source'."],
94         ['appname', 'n', None, "The process name to use for this application."]
95     ]
96
97     optFlags = [
98         ['encrypted', 'e', "Encrypt file before writing "
99                            "(will make the extension of the resultant "
100                            "file begin with 'e')"],
101         ['debug', 'd',     "Show debug information for plugin loading"],
102         ['progress', 'p'"Show progress information for plugin loading"],
103         ['help', 'h'"Display this message"],
104     ]
105     #zsh_altArgDescr = {"foo":"use this description for foo instead"}
106     #zsh_multiUse = ["foo", "bar"]
107     #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")]
108     zsh_actions = {"append":'_files -g "*.tap"',
109                    "type":"(pickle xml source)"}
110     zsh_actionDescr = {"append":"tap file to append to", "uid":"uid to run as",
111                        "gid":"gid to run as", "type":"output format"}
112
113     def init(self, tapLookup):
114         sc = []
115         for (name, module) in tapLookup.iteritems():
116             if IServiceMaker.providedBy(module):
117                 sc.append((
118                     name, None, lambda m=module: m.options(), module.description))
119             else:
120                 sc.append((
121                     name, None, lambda obj=module: obj.load().Options(),
122                     getattr(module, 'description', '')))
123
124         sc.sort()
125         self.subCommands = sc
126
127     def parseArgs(self, *rest):
128         self.params += rest
129
130     def _reportDebug(self, info):
131         print 'Debug: ', info
132
133     def _reportProgress(self, info):
134         s = self.pb(info)
135         if s:
136             print '\rProgress: ', s,
137         if info == 1.0:
138             print '\r' + (' ' * 79) + '\r',
139
140     def postOptions(self):
141         if self.recursing:
142             return
143         debug = progress = None
144         if self['debug']:
145             debug = self._reportDebug
146         if self['progress']:
147             progress = self._reportProgress
148             self.pb = util.makeStatBar(60, 1.0)
149         try:
150             self.tapLookup = loadPlugins(debug, progress)
151         except IOError:
152             raise usage.UsageError("Couldn't load the plugins file!")
153         self.init(self.tapLookup)
154         self.recursing = 1
155         self.parseOptions(self.params)
156         if not hasattr(self, 'subOptions') or self['help']:
157             raise usage.UsageError(str(self))
158         if hasattr(self, 'subOptions') and self.subOptions.get('help'):
159             raise usage.UsageError(str(self.subOptions))
160         if not self.tapLookup.has_key(self.subCommand):
161             raise usage.UsageError("Please select one of: "+
162                                    ' '.join(self.tapLookup))
163
164
165 def run():
166     options = FirstPassOptions()
167     try:
168         options.parseOptions(sys.argv[1:])
169     except usage.UsageError, e:
170         print e
171         sys.exit(2)
172     except KeyboardInterrupt:
173         sys.exit(1)
174
175     plg = options.tapLookup[options.subCommand]
176     if not IServiceMaker.providedBy(plg):
177         plg = plg.load()
178     ser = plg.makeService(options.subOptions)
179     addToApplication(ser,
180                      options.subCommand, options['append'], options['appname'],
181                      options['type'], options['encrypted'],
182                      options['uid'], options['gid'])
Note: See TracBrowser for help on using the browser.