OLD | NEW |
| (Empty) |
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, plugin as oldplugin | |
11 from twisted import plugin as newplugin | |
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 = oldplugin._getPlugIns("tap", debug, progress) | |
60 for plug in plugins: | |
61 if hasattr(plug, 'tapname'): | |
62 shortTapName = plug.tapname | |
63 else: | |
64 shortTapName = plug.module.split('.')[-1] | |
65 tapLookup[shortTapName] = plug | |
66 | |
67 plugins = newplugin.getPlugins(IServiceMaker) | |
68 for plug in plugins: | |
69 tapLookup[plug.tapname] = plug | |
70 | |
71 return tapLookup | |
72 | |
73 def addToApplication(ser, name, append, procname, type, encrypted, uid, gid): | |
74 if append and os.path.exists(append): | |
75 a = service.loadApplication(append, 'pickle', None) | |
76 else: | |
77 a = service.Application(name, uid, gid) | |
78 if procname: | |
79 service.IProcess(a).processName = procname | |
80 ser.setServiceParent(service.IServiceCollection(a)) | |
81 sob.IPersistable(a).setStyle(type) | |
82 passphrase = app.getSavePassphrase(encrypted) | |
83 if passphrase: | |
84 append = None | |
85 sob.IPersistable(a).save(filename=append, passphrase=passphrase) | |
86 | |
87 class FirstPassOptions(usage.Options): | |
88 synopsis = """Usage: mktap [options] <command> [command options] """ | |
89 | |
90 recursing = 0 | |
91 params = () | |
92 | |
93 optParameters = [ | |
94 ['uid', 'u', None, "The uid to run as.", uidFromString], | |
95 ['gid', 'g', None, "The gid to run as.", gidFromString], | |
96 ['append', 'a', None, | |
97 "An existing .tap file to append the plugin to, rather than " | |
98 "creating a new one."], | |
99 ['type', 't', 'pickle', | |
100 "The output format to use; this can be 'pickle', 'xml', " | |
101 "or 'source'."], | |
102 ['appname', 'n', None, "The process name to use for this application."] | |
103 ] | |
104 | |
105 optFlags = [ | |
106 ['encrypted', 'e', "Encrypt file before writing " | |
107 "(will make the extension of the resultant " | |
108 "file begin with 'e')"], | |
109 ['debug', 'd', "Show debug information for plugin loading"], | |
110 ['progress', 'p', "Show progress information for plugin loading"], | |
111 ['help', 'h', "Display this message"], | |
112 ] | |
113 #zsh_altArgDescr = {"foo":"use this description for foo instead"} | |
114 #zsh_multiUse = ["foo", "bar"] | |
115 #zsh_mutuallyExclusive = [("foo", "bar"), ("bar", "baz")] | |
116 zsh_actions = {"append":'_files -g "*.tap"', | |
117 "type":"(pickle xml source)"} | |
118 zsh_actionDescr = {"append":"tap file to append to", "uid":"uid to run as", | |
119 "gid":"gid to run as", "type":"output format"} | |
120 | |
121 def init(self, tapLookup): | |
122 sc = [] | |
123 for (name, module) in tapLookup.iteritems(): | |
124 if IServiceMaker.providedBy(module): | |
125 sc.append(( | |
126 name, None, lambda m=module: m.options(), module.description
)) | |
127 else: | |
128 sc.append(( | |
129 name, None, lambda obj=module: obj.load().Options(), | |
130 getattr(module, 'description', ''))) | |
131 | |
132 sc.sort() | |
133 self.subCommands = sc | |
134 | |
135 def parseArgs(self, *rest): | |
136 self.params += rest | |
137 | |
138 def _reportDebug(self, info): | |
139 print 'Debug: ', info | |
140 | |
141 def _reportProgress(self, info): | |
142 s = self.pb(info) | |
143 if s: | |
144 print '\rProgress: ', s, | |
145 if info == 1.0: | |
146 print '\r' + (' ' * 79) + '\r', | |
147 | |
148 def postOptions(self): | |
149 if self.recursing: | |
150 return | |
151 debug = progress = None | |
152 if self['debug']: | |
153 debug = self._reportDebug | |
154 if self['progress']: | |
155 progress = self._reportProgress | |
156 self.pb = util.makeStatBar(60, 1.0) | |
157 try: | |
158 self.tapLookup = loadPlugins(debug, progress) | |
159 except IOError: | |
160 raise usage.UsageError("Couldn't load the plugins file!") | |
161 self.init(self.tapLookup) | |
162 self.recursing = 1 | |
163 self.parseOptions(self.params) | |
164 if not hasattr(self, 'subOptions') or self['help']: | |
165 raise usage.UsageError(str(self)) | |
166 if hasattr(self, 'subOptions') and self.subOptions.get('help'): | |
167 raise usage.UsageError(str(self.subOptions)) | |
168 if not self.tapLookup.has_key(self.subCommand): | |
169 raise usage.UsageError("Please select one of: "+ | |
170 ' '.join(self.tapLookup)) | |
171 | |
172 | |
173 def run(): | |
174 options = FirstPassOptions() | |
175 try: | |
176 options.parseOptions(sys.argv[1:]) | |
177 except usage.UsageError, e: | |
178 print e | |
179 sys.exit(2) | |
180 except KeyboardInterrupt: | |
181 sys.exit(1) | |
182 | |
183 plg = options.tapLookup[options.subCommand] | |
184 if not IServiceMaker.providedBy(plg): | |
185 plg = plg.load() | |
186 ser = plg.makeService(options.subOptions) | |
187 addToApplication(ser, | |
188 options.subCommand, options['append'], options['appname'], | |
189 options['type'], options['encrypted'], | |
190 options['uid'], options['gid']) | |
OLD | NEW |