1995-01-10 13:08:10 -04:00
|
|
|
import os
|
|
|
|
import sys
|
2009-01-04 14:53:28 -04:00
|
|
|
from tkinter import *
|
|
|
|
from tkinter.scrolledtext import ScrolledText
|
|
|
|
from tkinter.dialog import Dialog
|
1995-01-10 13:08:10 -04:00
|
|
|
import signal
|
|
|
|
|
|
|
|
BUFSIZE = 512
|
|
|
|
|
|
|
|
class ShellWindow(ScrolledText):
|
|
|
|
|
2004-07-18 03:16:08 -03:00
|
|
|
def __init__(self, master=None, shell=None, **cnf):
|
|
|
|
if not shell:
|
|
|
|
try:
|
|
|
|
shell = os.environ['SHELL']
|
|
|
|
except KeyError:
|
|
|
|
shell = '/bin/sh'
|
|
|
|
shell = shell + ' -i'
|
2010-10-25 14:50:20 -03:00
|
|
|
args = shell.split()
|
2004-07-18 03:16:08 -03:00
|
|
|
shell = args[0]
|
|
|
|
|
2006-03-17 04:00:19 -04:00
|
|
|
ScrolledText.__init__(self, master, **cnf)
|
2004-07-18 03:16:08 -03:00
|
|
|
self.pos = '1.0'
|
|
|
|
self.bind('<Return>', self.inputhandler)
|
|
|
|
self.bind('<Control-c>', self.sigint)
|
|
|
|
self.bind('<Control-t>', self.sigterm)
|
|
|
|
self.bind('<Control-k>', self.sigkill)
|
|
|
|
self.bind('<Control-d>', self.sendeof)
|
|
|
|
|
|
|
|
self.pid, self.fromchild, self.tochild = spawn(shell, args)
|
|
|
|
self.tk.createfilehandler(self.fromchild, READABLE,
|
|
|
|
self.outputhandler)
|
|
|
|
|
|
|
|
def outputhandler(self, file, mask):
|
2010-10-25 14:50:20 -03:00
|
|
|
data = os.read(file, BUFSIZE).decode()
|
2004-07-18 03:16:08 -03:00
|
|
|
if not data:
|
|
|
|
self.tk.deletefilehandler(file)
|
|
|
|
pid, sts = os.waitpid(self.pid, 0)
|
2007-07-17 17:59:35 -03:00
|
|
|
print('pid', pid, 'status', sts)
|
2004-07-18 03:16:08 -03:00
|
|
|
self.pid = None
|
|
|
|
detail = sts>>8
|
|
|
|
cause = sts & 0xff
|
|
|
|
if cause == 0:
|
|
|
|
msg = "exit status %d" % detail
|
|
|
|
else:
|
|
|
|
msg = "killed by signal %d" % (cause & 0x7f)
|
|
|
|
if cause & 0x80:
|
|
|
|
msg = msg + " -- core dumped"
|
|
|
|
Dialog(self.master,
|
|
|
|
text=msg,
|
|
|
|
title="Exit status",
|
|
|
|
bitmap='warning',
|
|
|
|
default=0,
|
|
|
|
strings=('OK',))
|
|
|
|
return
|
|
|
|
self.insert(END, data)
|
|
|
|
self.pos = self.index("end - 1 char")
|
|
|
|
self.yview_pickplace(END)
|
|
|
|
|
|
|
|
def inputhandler(self, *args):
|
|
|
|
if not self.pid:
|
|
|
|
self.no_process()
|
|
|
|
return "break"
|
|
|
|
self.insert(END, "\n")
|
|
|
|
line = self.get(self.pos, "end - 1 char")
|
|
|
|
self.pos = self.index(END)
|
2010-10-25 14:50:20 -03:00
|
|
|
os.write(self.tochild, line.encode())
|
2004-07-18 03:16:08 -03:00
|
|
|
return "break"
|
|
|
|
|
|
|
|
def sendeof(self, *args):
|
|
|
|
if not self.pid:
|
|
|
|
self.no_process()
|
|
|
|
return "break"
|
|
|
|
os.close(self.tochild)
|
|
|
|
return "break"
|
|
|
|
|
|
|
|
def sendsig(self, sig):
|
|
|
|
if not self.pid:
|
|
|
|
self.no_process()
|
|
|
|
return "break"
|
|
|
|
os.kill(self.pid, sig)
|
|
|
|
return "break"
|
|
|
|
|
|
|
|
def sigint(self, *args):
|
|
|
|
return self.sendsig(signal.SIGINT)
|
|
|
|
|
|
|
|
def sigquit(self, *args):
|
|
|
|
return self.sendsig(signal.SIGQUIT)
|
|
|
|
|
|
|
|
def sigterm(self, *args):
|
|
|
|
return self.sendsig(signal.SIGTERM)
|
|
|
|
|
|
|
|
def sigkill(self, *args):
|
|
|
|
return self.sendsig(signal.SIGKILL)
|
|
|
|
|
|
|
|
def no_process(self):
|
|
|
|
Dialog(self.master,
|
|
|
|
text="No active process",
|
|
|
|
title="No process",
|
|
|
|
bitmap='error',
|
|
|
|
default=0,
|
|
|
|
strings=('OK',))
|
|
|
|
|
|
|
|
MAXFD = 100 # Max number of file descriptors (os.getdtablesize()???)
|
1995-01-10 13:08:10 -04:00
|
|
|
|
|
|
|
def spawn(prog, args):
|
2004-07-18 03:16:08 -03:00
|
|
|
p2cread, p2cwrite = os.pipe()
|
|
|
|
c2pread, c2pwrite = os.pipe()
|
|
|
|
pid = os.fork()
|
|
|
|
if pid == 0:
|
|
|
|
# Child
|
|
|
|
for i in 0, 1, 2:
|
|
|
|
try:
|
|
|
|
os.close(i)
|
|
|
|
except os.error:
|
|
|
|
pass
|
2006-08-29 01:39:12 -03:00
|
|
|
if os.dup(p2cread) != 0:
|
2004-07-18 03:16:08 -03:00
|
|
|
sys.stderr.write('popen2: bad read dup\n')
|
2006-08-29 01:39:12 -03:00
|
|
|
if os.dup(c2pwrite) != 1:
|
2004-07-18 03:16:08 -03:00
|
|
|
sys.stderr.write('popen2: bad write dup\n')
|
2006-08-29 01:39:12 -03:00
|
|
|
if os.dup(c2pwrite) != 2:
|
2004-07-18 03:16:08 -03:00
|
|
|
sys.stderr.write('popen2: bad write dup\n')
|
Merged revisions 61003-61033 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r61004 | georg.brandl | 2008-02-23 19:47:04 +0100 (Sat, 23 Feb 2008) | 2 lines
Documentation coverage builder, part 1.
........
r61006 | andrew.kuchling | 2008-02-23 20:02:33 +0100 (Sat, 23 Feb 2008) | 1 line
#1389051: IMAP module tries to read entire message in one chunk. Patch by Fredrik Lundh.
........
r61008 | andrew.kuchling | 2008-02-23 20:28:58 +0100 (Sat, 23 Feb 2008) | 1 line
#1389051, #1092502: fix excessively large allocations when using read() on a socket
........
r61011 | jeffrey.yasskin | 2008-02-23 20:40:54 +0100 (Sat, 23 Feb 2008) | 13 lines
Prevent classes like:
class RunSelfFunction(object):
def __init__(self):
self.thread = threading.Thread(target=self._run)
self.thread.start()
def _run(self):
pass
from creating a permanent cycle between the object and the thread by having the
Thread delete its references to the object when it completes.
As an example of the effect of this bug, paramiko.Transport inherits from
Thread to avoid it.
........
r61013 | jeffrey.yasskin | 2008-02-23 21:40:35 +0100 (Sat, 23 Feb 2008) | 3 lines
Followup to r61011: Also avoid the reference cycle when the Thread's target
raises an exception.
........
r61017 | georg.brandl | 2008-02-23 22:59:11 +0100 (Sat, 23 Feb 2008) | 2 lines
#2101: fix removeAttribute docs.
........
r61018 | georg.brandl | 2008-02-23 23:05:38 +0100 (Sat, 23 Feb 2008) | 2 lines
Add examples to modulefinder docs. Written for GHOP by Josip Dzolonga.
........
r61019 | georg.brandl | 2008-02-23 23:09:24 +0100 (Sat, 23 Feb 2008) | 2 lines
Use os.closerange() in popen2.
........
r61020 | georg.brandl | 2008-02-23 23:14:02 +0100 (Sat, 23 Feb 2008) | 2 lines
Use os.closerange().
........
r61021 | georg.brandl | 2008-02-23 23:35:33 +0100 (Sat, 23 Feb 2008) | 3 lines
In test_heapq and test_bisect, test both the Python and the C implementation.
Originally written for GHOP by Josip Dzolonga, heavily patched by me.
........
r61024 | facundo.batista | 2008-02-23 23:54:12 +0100 (Sat, 23 Feb 2008) | 3 lines
Added simple test case. Thanks Benjamin Peterson.
........
r61025 | georg.brandl | 2008-02-23 23:55:18 +0100 (Sat, 23 Feb 2008) | 2 lines
#1825: correctly document msilib.add_data.
........
r61027 | georg.brandl | 2008-02-24 00:02:23 +0100 (Sun, 24 Feb 2008) | 2 lines
#1826: allow dotted attribute paths in operator.attrgetter.
........
r61028 | georg.brandl | 2008-02-24 00:04:35 +0100 (Sun, 24 Feb 2008) | 2 lines
#1506171: added operator.methodcaller().
........
r61029 | georg.brandl | 2008-02-24 00:25:26 +0100 (Sun, 24 Feb 2008) | 2 lines
Document import ./. threading issues. #1720705.
........
r61032 | georg.brandl | 2008-02-24 00:43:01 +0100 (Sun, 24 Feb 2008) | 2 lines
Specify what kind of warning -3 emits.
........
r61033 | christian.heimes | 2008-02-24 00:59:45 +0100 (Sun, 24 Feb 2008) | 1 line
MS Windows doesn't have mode_t but stat.st_mode is defined as unsigned short.
........
2008-02-23 20:38:49 -04:00
|
|
|
os.closerange(3, MAXFD)
|
2004-07-18 03:16:08 -03:00
|
|
|
try:
|
|
|
|
os.execvp(prog, args)
|
|
|
|
finally:
|
|
|
|
sys.stderr.write('execvp failed\n')
|
|
|
|
os._exit(1)
|
|
|
|
os.close(p2cread)
|
|
|
|
os.close(c2pwrite)
|
|
|
|
return pid, c2pread, p2cwrite
|
1995-01-10 13:08:10 -04:00
|
|
|
|
|
|
|
def test():
|
2010-10-25 14:50:20 -03:00
|
|
|
shell = ' '.join(sys.argv[1: ])
|
2004-07-18 03:16:08 -03:00
|
|
|
root = Tk()
|
|
|
|
root.minsize(1, 1)
|
|
|
|
if shell:
|
|
|
|
w = ShellWindow(root, shell=shell)
|
|
|
|
else:
|
|
|
|
w = ShellWindow(root)
|
|
|
|
w.pack(expand=1, fill=BOTH)
|
|
|
|
w.focus_set()
|
|
|
|
w.tk.mainloop()
|
1995-01-10 13:08:10 -04:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2004-07-18 03:16:08 -03:00
|
|
|
test()
|