| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 106 |
|
|---|
| 107 |
|
|---|
| 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']) |
|---|