2006-03-18 05:07:36 +03:00
|
|
|
# -*-python-*-
|
2000-05-10 02:38:21 +04:00
|
|
|
#
|
2013-01-04 23:01:54 +04:00
|
|
|
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
|
2000-05-10 02:38:21 +04:00
|
|
|
#
|
|
|
|
# By using this file, you agree to the terms and conditions set forth in
|
2005-12-17 20:19:28 +03:00
|
|
|
# the LICENSE.html file which can be found at the top level of the ViewVC
|
|
|
|
# distribution or at http://viewvc.org/license-1.html.
|
2000-05-10 02:38:21 +04:00
|
|
|
#
|
2006-03-18 05:07:36 +03:00
|
|
|
# For more information, visit http://viewvc.org/
|
2000-05-10 02:38:21 +04:00
|
|
|
#
|
|
|
|
# -----------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# popen.py: a replacement for os.popen()
|
|
|
|
#
|
|
|
|
# This implementation of popen() provides a cmd + args calling sequence,
|
|
|
|
# rather than a system() type of convention. The shell facilities are not
|
|
|
|
# available, but that implies we can avoid worrying about shell hacks in
|
|
|
|
# the arguments.
|
|
|
|
#
|
|
|
|
# -----------------------------------------------------------------------
|
|
|
|
|
|
|
|
import os
|
2000-05-22 12:46:04 +04:00
|
|
|
import sys
|
2003-02-09 12:57:46 +03:00
|
|
|
import sapi
|
2003-06-02 08:05:00 +04:00
|
|
|
import threading
|
2003-02-09 12:57:46 +03:00
|
|
|
|
|
|
|
if sys.platform == "win32":
|
|
|
|
import win32popen
|
|
|
|
import win32event
|
|
|
|
import win32process
|
|
|
|
import debug
|
|
|
|
import StringIO
|
2000-05-10 02:38:21 +04:00
|
|
|
|
2000-05-10 04:58:44 +04:00
|
|
|
def popen(cmd, args, mode, capture_err=1):
|
2003-02-09 12:57:46 +03:00
|
|
|
if sys.platform == "win32":
|
|
|
|
command = win32popen.CommandLine(cmd, args)
|
|
|
|
|
Wow. Drop a "general code cleanup" kind of bomb on the codebase. All
of this is aimed at not paying the maintenance price of supporting
Python versions prior to 2.4 any longer, plus a little bit of just
getting dead code out of the way.
* lib/compat.py
Remove as unused.
* bin/cvsdbadmin,
* bin/loginfo-handler,
* bin/make-database,
* bin/svndbadmin,
* lib/accept.py,
* lib/blame.py,
* lib/cvsdb.py,
* lib/popen.py,
* lib/query.py,
* lib/sapi.py,
* lib/vcauth/forbidden/__init__.py
* lib/vcauth/forbiddenre/__init__.py,
* lib/vcauth/svnauthz/__init__.py,
* lib/vclib/__init__.py,
* lib/vclib/ccvs/blame.py,
* lib/win32popen.py,
* tests/timelog.py
Replace explicit import and use of the 'string' module with newer constructs.
* bin/standalone.py,
* lib/viewvc.py
No longer use 'compat' module. Replace explicit import and use of
the 'string' module with newer constructs.
* lib/dbi.py
Use calender.timegm() instead of compat.timegm().
* lib/vcauth/__init__.py
Lose unused module imports.
* lib/config.py,
Replace explicit import and use of the 'string' module with newer
constructs where possible. Lose old ConfigParser patch-up code for
Python 1.5.1.
* lib/vclib/ccvs/ccvs.py
Replace explicit import and use of the 'string' module with newer
constructs where possible. Import _path_join() from bincvs, and use
it instead of a bunch of copy-and-pasted string join() statements
throughout.
* lib/vclib/ccvs/__init__.py
(cvs_strptime): Moved here from the 'compat' module.
* lib/vclib/ccvs/bincvs.py
(): No longer use 'compat' module. Replace explicit import and use
of the 'string' module with newer constructs.
(_path_join): New, used now instead of a bunch of copy-and-pasted
string join() statements throughout.
* viewvc-install
Don't use the 'compat' module any more.
Also, so some rearranging of non-critical bits.
* misc/: New directory.
* misc/py2html.py: Moved from 'lib/py2html.py'.
* misc/PyFontify.py: Moved from 'lib/PyFontify.py'.
* misc/elemx/: Moved from 'elemx/'.
* misc/tparse/: Moved from 'tparse/'.
* tools/make-release
Omit 'misc' directory from releases, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2437 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 20:49:52 +04:00
|
|
|
if mode.find('r') >= 0:
|
2003-06-10 03:20:00 +04:00
|
|
|
hStdIn = None
|
|
|
|
|
2003-02-09 12:57:46 +03:00
|
|
|
if debug.SHOW_CHILD_PROCESSES:
|
|
|
|
dbgIn, dbgOut = None, StringIO.StringIO()
|
|
|
|
|
|
|
|
handle, hStdOut = win32popen.MakeSpyPipe(0, 1, (dbgOut,))
|
|
|
|
|
|
|
|
if capture_err:
|
|
|
|
hStdErr = hStdOut
|
|
|
|
dbgErr = dbgOut
|
|
|
|
else:
|
|
|
|
dbgErr = StringIO.StringIO()
|
2003-06-10 03:20:00 +04:00
|
|
|
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
|
2003-02-09 12:57:46 +03:00
|
|
|
else:
|
2003-06-02 08:40:44 +04:00
|
|
|
handle, hStdOut = win32popen.CreatePipe(0, 1)
|
2003-02-09 12:57:46 +03:00
|
|
|
if capture_err:
|
|
|
|
hStdErr = hStdOut
|
|
|
|
else:
|
2003-06-10 03:20:00 +04:00
|
|
|
hStdErr = win32popen.NullFile(1)
|
2003-02-09 12:57:46 +03:00
|
|
|
|
|
|
|
else:
|
|
|
|
if debug.SHOW_CHILD_PROCESSES:
|
|
|
|
dbgIn, dbgOut, dbgErr = StringIO.StringIO(), StringIO.StringIO(), StringIO.StringIO()
|
|
|
|
hStdIn, handle = win32popen.MakeSpyPipe(1, 0, (dbgIn,))
|
2003-06-10 03:20:00 +04:00
|
|
|
x, hStdOut = win32popen.MakeSpyPipe(None, 1, (dbgOut,))
|
2003-02-09 12:57:46 +03:00
|
|
|
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
|
|
|
|
else:
|
2003-06-02 08:40:44 +04:00
|
|
|
hStdIn, handle = win32popen.CreatePipe(0, 1)
|
2003-02-09 12:57:46 +03:00
|
|
|
hStdOut = None
|
|
|
|
hStdErr = None
|
|
|
|
|
|
|
|
phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, hStdErr)
|
|
|
|
|
|
|
|
if debug.SHOW_CHILD_PROCESSES:
|
2003-02-11 05:58:04 +03:00
|
|
|
debug.Process(command, dbgIn, dbgOut, dbgErr)
|
2003-06-10 03:20:00 +04:00
|
|
|
|
2003-02-09 12:57:46 +03:00
|
|
|
return _pipe(win32popen.File2FileObject(handle, mode), phandle)
|
|
|
|
|
2000-05-22 12:46:04 +04:00
|
|
|
# flush the stdio buffers since we are about to change the FD under them
|
|
|
|
sys.stdout.flush()
|
|
|
|
sys.stderr.flush()
|
|
|
|
|
2000-05-10 02:38:21 +04:00
|
|
|
r, w = os.pipe()
|
|
|
|
pid = os.fork()
|
|
|
|
if pid:
|
|
|
|
# in the parent
|
|
|
|
|
|
|
|
# close the descriptor that we don't need and return the other one.
|
Wow. Drop a "general code cleanup" kind of bomb on the codebase. All
of this is aimed at not paying the maintenance price of supporting
Python versions prior to 2.4 any longer, plus a little bit of just
getting dead code out of the way.
* lib/compat.py
Remove as unused.
* bin/cvsdbadmin,
* bin/loginfo-handler,
* bin/make-database,
* bin/svndbadmin,
* lib/accept.py,
* lib/blame.py,
* lib/cvsdb.py,
* lib/popen.py,
* lib/query.py,
* lib/sapi.py,
* lib/vcauth/forbidden/__init__.py
* lib/vcauth/forbiddenre/__init__.py,
* lib/vcauth/svnauthz/__init__.py,
* lib/vclib/__init__.py,
* lib/vclib/ccvs/blame.py,
* lib/win32popen.py,
* tests/timelog.py
Replace explicit import and use of the 'string' module with newer constructs.
* bin/standalone.py,
* lib/viewvc.py
No longer use 'compat' module. Replace explicit import and use of
the 'string' module with newer constructs.
* lib/dbi.py
Use calender.timegm() instead of compat.timegm().
* lib/vcauth/__init__.py
Lose unused module imports.
* lib/config.py,
Replace explicit import and use of the 'string' module with newer
constructs where possible. Lose old ConfigParser patch-up code for
Python 1.5.1.
* lib/vclib/ccvs/ccvs.py
Replace explicit import and use of the 'string' module with newer
constructs where possible. Import _path_join() from bincvs, and use
it instead of a bunch of copy-and-pasted string join() statements
throughout.
* lib/vclib/ccvs/__init__.py
(cvs_strptime): Moved here from the 'compat' module.
* lib/vclib/ccvs/bincvs.py
(): No longer use 'compat' module. Replace explicit import and use
of the 'string' module with newer constructs.
(_path_join): New, used now instead of a bunch of copy-and-pasted
string join() statements throughout.
* viewvc-install
Don't use the 'compat' module any more.
Also, so some rearranging of non-critical bits.
* misc/: New directory.
* misc/py2html.py: Moved from 'lib/py2html.py'.
* misc/PyFontify.py: Moved from 'lib/PyFontify.py'.
* misc/elemx/: Moved from 'elemx/'.
* misc/tparse/: Moved from 'tparse/'.
* tools/make-release
Omit 'misc' directory from releases, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2437 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 20:49:52 +04:00
|
|
|
if mode.find('r') >= 0:
|
2000-05-10 02:38:21 +04:00
|
|
|
os.close(w)
|
2003-02-09 12:57:46 +03:00
|
|
|
return _pipe(os.fdopen(r, mode), pid)
|
2000-05-10 02:38:21 +04:00
|
|
|
os.close(r)
|
2003-02-09 12:57:46 +03:00
|
|
|
return _pipe(os.fdopen(w, mode), pid)
|
2000-05-10 02:38:21 +04:00
|
|
|
|
|
|
|
# in the child
|
|
|
|
|
|
|
|
# we'll need /dev/null for the discarded I/O
|
|
|
|
null = os.open('/dev/null', os.O_RDWR)
|
|
|
|
|
Wow. Drop a "general code cleanup" kind of bomb on the codebase. All
of this is aimed at not paying the maintenance price of supporting
Python versions prior to 2.4 any longer, plus a little bit of just
getting dead code out of the way.
* lib/compat.py
Remove as unused.
* bin/cvsdbadmin,
* bin/loginfo-handler,
* bin/make-database,
* bin/svndbadmin,
* lib/accept.py,
* lib/blame.py,
* lib/cvsdb.py,
* lib/popen.py,
* lib/query.py,
* lib/sapi.py,
* lib/vcauth/forbidden/__init__.py
* lib/vcauth/forbiddenre/__init__.py,
* lib/vcauth/svnauthz/__init__.py,
* lib/vclib/__init__.py,
* lib/vclib/ccvs/blame.py,
* lib/win32popen.py,
* tests/timelog.py
Replace explicit import and use of the 'string' module with newer constructs.
* bin/standalone.py,
* lib/viewvc.py
No longer use 'compat' module. Replace explicit import and use of
the 'string' module with newer constructs.
* lib/dbi.py
Use calender.timegm() instead of compat.timegm().
* lib/vcauth/__init__.py
Lose unused module imports.
* lib/config.py,
Replace explicit import and use of the 'string' module with newer
constructs where possible. Lose old ConfigParser patch-up code for
Python 1.5.1.
* lib/vclib/ccvs/ccvs.py
Replace explicit import and use of the 'string' module with newer
constructs where possible. Import _path_join() from bincvs, and use
it instead of a bunch of copy-and-pasted string join() statements
throughout.
* lib/vclib/ccvs/__init__.py
(cvs_strptime): Moved here from the 'compat' module.
* lib/vclib/ccvs/bincvs.py
(): No longer use 'compat' module. Replace explicit import and use
of the 'string' module with newer constructs.
(_path_join): New, used now instead of a bunch of copy-and-pasted
string join() statements throughout.
* viewvc-install
Don't use the 'compat' module any more.
Also, so some rearranging of non-critical bits.
* misc/: New directory.
* misc/py2html.py: Moved from 'lib/py2html.py'.
* misc/PyFontify.py: Moved from 'lib/PyFontify.py'.
* misc/elemx/: Moved from 'elemx/'.
* misc/tparse/: Moved from 'tparse/'.
* tools/make-release
Omit 'misc' directory from releases, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2437 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 20:49:52 +04:00
|
|
|
if mode.find('r') >= 0:
|
2000-05-10 02:38:21 +04:00
|
|
|
# hook stdout/stderr to the "write" channel
|
|
|
|
os.dup2(w, 1)
|
|
|
|
# "close" stdin; the child shouldn't use it
|
2000-05-22 12:46:04 +04:00
|
|
|
### this isn't quite right... we may want the child to read from stdin
|
2000-05-10 02:38:21 +04:00
|
|
|
os.dup2(null, 0)
|
2000-05-10 04:58:44 +04:00
|
|
|
# what to do with errors?
|
|
|
|
if capture_err:
|
|
|
|
os.dup2(w, 2)
|
|
|
|
else:
|
|
|
|
os.dup2(null, 2)
|
2000-05-10 02:38:21 +04:00
|
|
|
else:
|
|
|
|
# hook stdin to the "read" channel
|
|
|
|
os.dup2(r, 0)
|
|
|
|
# "close" stdout/stderr; the child shouldn't use them
|
2000-05-22 12:46:04 +04:00
|
|
|
### this isn't quite right... we may want the child to write to these
|
2000-05-10 04:58:44 +04:00
|
|
|
os.dup2(null, 1)
|
|
|
|
os.dup2(null, 2)
|
2000-05-10 02:38:21 +04:00
|
|
|
|
|
|
|
# don't need these FDs any more
|
|
|
|
os.close(null)
|
|
|
|
os.close(r)
|
|
|
|
os.close(w)
|
|
|
|
|
|
|
|
# the stdin/stdout/stderr are all set up. exec the target
|
2000-05-25 10:57:02 +04:00
|
|
|
try:
|
|
|
|
os.execvp(cmd, (cmd,) + tuple(args))
|
|
|
|
except:
|
2001-10-31 12:15:42 +03:00
|
|
|
# aid debugging, if the os.execvp above fails for some reason:
|
Wow. Drop a "general code cleanup" kind of bomb on the codebase. All
of this is aimed at not paying the maintenance price of supporting
Python versions prior to 2.4 any longer, plus a little bit of just
getting dead code out of the way.
* lib/compat.py
Remove as unused.
* bin/cvsdbadmin,
* bin/loginfo-handler,
* bin/make-database,
* bin/svndbadmin,
* lib/accept.py,
* lib/blame.py,
* lib/cvsdb.py,
* lib/popen.py,
* lib/query.py,
* lib/sapi.py,
* lib/vcauth/forbidden/__init__.py
* lib/vcauth/forbiddenre/__init__.py,
* lib/vcauth/svnauthz/__init__.py,
* lib/vclib/__init__.py,
* lib/vclib/ccvs/blame.py,
* lib/win32popen.py,
* tests/timelog.py
Replace explicit import and use of the 'string' module with newer constructs.
* bin/standalone.py,
* lib/viewvc.py
No longer use 'compat' module. Replace explicit import and use of
the 'string' module with newer constructs.
* lib/dbi.py
Use calender.timegm() instead of compat.timegm().
* lib/vcauth/__init__.py
Lose unused module imports.
* lib/config.py,
Replace explicit import and use of the 'string' module with newer
constructs where possible. Lose old ConfigParser patch-up code for
Python 1.5.1.
* lib/vclib/ccvs/ccvs.py
Replace explicit import and use of the 'string' module with newer
constructs where possible. Import _path_join() from bincvs, and use
it instead of a bunch of copy-and-pasted string join() statements
throughout.
* lib/vclib/ccvs/__init__.py
(cvs_strptime): Moved here from the 'compat' module.
* lib/vclib/ccvs/bincvs.py
(): No longer use 'compat' module. Replace explicit import and use
of the 'string' module with newer constructs.
(_path_join): New, used now instead of a bunch of copy-and-pasted
string join() statements throughout.
* viewvc-install
Don't use the 'compat' module any more.
Also, so some rearranging of non-critical bits.
* misc/: New directory.
* misc/py2html.py: Moved from 'lib/py2html.py'.
* misc/PyFontify.py: Moved from 'lib/PyFontify.py'.
* misc/elemx/: Moved from 'elemx/'.
* misc/tparse/: Moved from 'tparse/'.
* tools/make-release
Omit 'misc' directory from releases, too.
git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@2437 8cb11bc2-c004-0410-86c3-e597b4017df7
2010-09-03 20:49:52 +04:00
|
|
|
print "<h2>exec failed:</h2><pre>", cmd, ' '.join(args), "</pre>"
|
2001-10-31 12:15:42 +03:00
|
|
|
raise
|
2000-05-10 02:38:21 +04:00
|
|
|
|
|
|
|
# crap. shouldn't be here.
|
|
|
|
sys.exit(127)
|
|
|
|
|
|
|
|
class _pipe:
|
|
|
|
"Wrapper for a file which can wait() on a child process at close time."
|
|
|
|
|
2003-06-02 08:05:00 +04:00
|
|
|
def __init__(self, file, child_pid, done_event = None, thread = None):
|
2000-05-10 02:38:21 +04:00
|
|
|
self.file = file
|
|
|
|
self.child_pid = child_pid
|
2003-02-09 12:57:46 +03:00
|
|
|
if sys.platform == "win32":
|
|
|
|
if done_event:
|
|
|
|
self.wait_for = (child_pid, done_event)
|
|
|
|
else:
|
|
|
|
self.wait_for = (child_pid,)
|
2003-06-02 08:05:00 +04:00
|
|
|
else:
|
|
|
|
self.thread = thread
|
2003-06-10 03:20:00 +04:00
|
|
|
|
2000-05-22 12:46:04 +04:00
|
|
|
def eof(self):
|
2006-01-22 20:01:02 +03:00
|
|
|
### should be calling file.eof() here instead of file.close(), there
|
|
|
|
### may be data in the pipe or buffer after the process exits
|
2003-02-09 12:57:46 +03:00
|
|
|
if sys.platform == "win32":
|
|
|
|
r = win32event.WaitForMultipleObjects(self.wait_for, 1, 0)
|
|
|
|
if r == win32event.WAIT_OBJECT_0:
|
|
|
|
self.file.close()
|
|
|
|
self.file = None
|
|
|
|
return win32process.GetExitCodeProcess(self.child_pid)
|
|
|
|
return None
|
|
|
|
|
2003-06-02 08:05:00 +04:00
|
|
|
if self.thread and self.thread.isAlive():
|
|
|
|
return None
|
|
|
|
|
2000-05-22 12:46:04 +04:00
|
|
|
pid, status = os.waitpid(self.child_pid, os.WNOHANG)
|
|
|
|
if pid:
|
|
|
|
self.file.close()
|
|
|
|
self.file = None
|
|
|
|
return status
|
|
|
|
return None
|
|
|
|
|
2000-05-10 02:38:21 +04:00
|
|
|
def close(self):
|
2000-05-22 12:46:04 +04:00
|
|
|
if self.file:
|
|
|
|
self.file.close()
|
|
|
|
self.file = None
|
2003-02-09 12:57:46 +03:00
|
|
|
if sys.platform == "win32":
|
|
|
|
win32event.WaitForMultipleObjects(self.wait_for, 1, win32event.INFINITE)
|
|
|
|
return win32process.GetExitCodeProcess(self.child_pid)
|
|
|
|
else:
|
2003-06-02 08:05:00 +04:00
|
|
|
if self.thread:
|
|
|
|
self.thread.join()
|
2007-04-18 01:07:33 +04:00
|
|
|
if type(self.child_pid) == type([]):
|
2006-03-17 23:25:34 +03:00
|
|
|
for pid in self.child_pid:
|
|
|
|
exit = os.waitpid(pid, 0)[1]
|
|
|
|
return exit
|
2007-04-18 01:07:33 +04:00
|
|
|
else:
|
|
|
|
return os.waitpid(self.child_pid, 0)[1]
|
2000-05-22 12:46:04 +04:00
|
|
|
return None
|
2000-05-10 02:38:21 +04:00
|
|
|
|
|
|
|
def __getattr__(self, name):
|
|
|
|
return getattr(self.file, name)
|
|
|
|
|
|
|
|
def __del__(self):
|
2003-02-09 12:57:46 +03:00
|
|
|
self.close()
|