summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2012-09-09 17:53:22 -0700
committerZac Medico <zmedico@gentoo.org>2012-09-09 17:53:22 -0700
commit45bc97f98b41fe4e2286dfb50d1c9f263b0da8a4 (patch)
treef2b08c5bf38eeaaf17e39c6012faa81f03b11469
parentObjectProxy: implement __enter__ and __exit__ (diff)
downloadportage-45bc97f98b41fe4e2286dfb50d1c9f263b0da8a4.tar.gz
portage-45bc97f98b41fe4e2286dfb50d1c9f263b0da8a4.tar.bz2
portage-45bc97f98b41fe4e2286dfb50d1c9f263b0da8a4.zip
repoman: fix popen unicode handling, bug #310789
-rwxr-xr-xbin/repoman88
1 files changed, 61 insertions, 27 deletions
diff --git a/bin/repoman b/bin/repoman
index d7c69b32f..1f4daede9 100755
--- a/bin/repoman
+++ b/bin/repoman
@@ -9,6 +9,7 @@
from __future__ import print_function
import calendar
+import codecs
import copy
import errno
import formatter
@@ -741,6 +742,36 @@ else:
def caterror(mycat):
err(mycat+" is not an official category. Skipping QA checks in this directory.\nPlease ensure that you add "+catdir+" to "+repodir+"/profiles/categories\nif it is a new category.")
+class repoman_popen(portage.proxy.objectproxy.ObjectProxy):
+ """
+ Implements an interface similar to os.popen(), but with customized
+ unicode handling (see bug #310789) and without the shell.
+ """
+
+ __slots__ = ('_proc', '_stdout')
+
+ def __init__(self, cmd):
+ args = portage.util.shlex_split(cmd)
+ encoding = _encodings['fs']
+ if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
+ # Python 3.1 does not support bytes in Popen args.
+ args = [_unicode_encode(x,
+ encoding=encoding, errors='strict') for x in args]
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ object.__setattr__(self, '_proc', proc)
+ object.__setattr__(self, '_stdout',
+ codecs.getreader(encoding)(proc.stdout, 'strict'))
+
+ def _get_target(self):
+ return object.__getattribute__(self, '_stdout')
+
+ __enter__ = _get_target
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ proc = object.__getattribute__(self, '_proc')
+ proc.wait()
+ proc.stdout.close()
+
class ProfileDesc(object):
__slots__ = ('abs_path', 'arch', 'status', 'sub_path', 'tree_path',)
def __init__(self, arch, status, sub_path, tree_path):
@@ -1150,7 +1181,7 @@ if vcs == "cvs":
myremoved = cvstree.findremoved(mycvstree, recursive=1, basedir="./")
elif vcs == "svn":
- with os.popen("svn status") as f:
+ with repoman_popen("svn status") as f:
svnstatus = f.readlines()
mychanged = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem and elem[:1] in "MR" ]
mynew = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A") ]
@@ -1158,23 +1189,23 @@ elif vcs == "svn":
myremoved = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")]
elif vcs == "git":
- with os.popen("git diff-index --name-only "
+ with repoman_popen("git diff-index --name-only "
"--relative --diff-filter=M HEAD") as f:
mychanged = f.readlines()
mychanged = ["./" + elem[:-1] for elem in mychanged]
- with os.popen("git diff-index --name-only "
+ with repoman_popen("git diff-index --name-only "
"--relative --diff-filter=A HEAD") as f:
mynew = f.readlines()
mynew = ["./" + elem[:-1] for elem in mynew]
if options.if_modified == "y":
- with os.popen("git diff-index --name-only "
+ with repoman_popen("git diff-index --name-only "
"--relative --diff-filter=D HEAD") as f:
myremoved = f.readlines()
myremoved = ["./" + elem[:-1] for elem in myremoved]
elif vcs == "bzr":
- with os.popen("bzr status -S .") as f:
+ with repoman_popen("bzr status -S .") as f:
bzrstatus = f.readlines()
mychanged = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M" ]
mynew = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "NK" or elem[0:1] == "R" ) ]
@@ -1182,13 +1213,13 @@ elif vcs == "bzr":
myremoved = [ "./" + elem.split()[-3:-2][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] == "K" or elem[0:1] == "R" ) ]
elif vcs == "hg":
- with os.popen("hg status --no-status --modified .") as f:
+ with repoman_popen("hg status --no-status --modified .") as f:
mychanged = f.readlines()
mychanged = ["./" + elem.rstrip() for elem in mychanged]
- mynew = os.popen("hg status --no-status --added .").readlines()
+ mynew = repoman_popen("hg status --no-status --added .").readlines()
mynew = ["./" + elem.rstrip() for elem in mynew]
if options.if_modified == "y":
- with os.popen("hg status --no-status --removed .") as f:
+ with repoman_popen("hg status --no-status --removed .") as f:
myremoved = f.readlines()
myremoved = ["./" + elem.rstrip() for elem in myremoved]
@@ -1426,10 +1457,10 @@ for x in effective_scanlist:
if vcs in ("git", "hg") and check_ebuild_notadded:
if vcs == "git":
- myf = os.popen("git ls-files --others %s" % \
+ myf = repoman_popen("git ls-files --others %s" % \
(portage._shell_quote(checkdir_relative),))
if vcs == "hg":
- myf = os.popen("hg status --no-status --unknown %s" % \
+ myf = repoman_popen("hg status --no-status --unknown %s" % \
(portage._shell_quote(checkdir_relative),))
for l in myf:
if l[:-1][-7:] == ".ebuild":
@@ -1443,9 +1474,11 @@ for x in effective_scanlist:
if vcs == "cvs":
myf=open(checkdir+"/CVS/Entries","r")
if vcs == "svn":
- myf = os.popen("svn status --depth=files --verbose " + checkdir)
+ myf = repoman_popen("svn status --depth=files --verbose " +
+ portage._shell_quote(checkdir))
if vcs == "bzr":
- myf = os.popen("bzr ls -v --kind=file " + checkdir)
+ myf = repoman_popen("bzr ls -v --kind=file " +
+ portage._shell_quote(checkdir))
myl = myf.readlines()
myf.close()
for l in myl:
@@ -1473,7 +1506,8 @@ for x in effective_scanlist:
if l[-7:] == ".ebuild":
eadded.append(os.path.basename(l[:-7]))
if vcs == "svn":
- myf = os.popen("svn status " + checkdir)
+ myf = repoman_popen("svn status " +
+ portage._shell_quote(checkdir))
myl=myf.readlines()
myf.close()
for l in myl:
@@ -2318,7 +2352,7 @@ else:
err("Error retrieving CVS tree; exiting.")
if vcs == "svn":
try:
- with os.popen("svn status --no-ignore") as f:
+ with repoman_popen("svn status --no-ignore") as f:
svnstatus = f.readlines()
myunadded = [ "./"+elem.rstrip().split()[1] for elem in svnstatus if elem.startswith("?") or elem.startswith("I") ]
except SystemExit as e:
@@ -2327,12 +2361,12 @@ else:
err("Error retrieving SVN info; exiting.")
if vcs == "git":
# get list of files not under version control or missing
- myf = os.popen("git ls-files --others")
+ myf = repoman_popen("git ls-files --others")
myunadded = [ "./" + elem[:-1] for elem in myf ]
myf.close()
if vcs == "bzr":
try:
- with os.popen("bzr status -S .") as f:
+ with repoman_popen("bzr status -S .") as f:
bzrstatus = f.readlines()
myunadded = [ "./"+elem.rstrip().split()[1].split('/')[-1:][0] for elem in bzrstatus if elem.startswith("?") or elem[0:2] == " D" ]
except SystemExit as e:
@@ -2340,14 +2374,14 @@ else:
except:
err("Error retrieving bzr info; exiting.")
if vcs == "hg":
- with os.popen("hg status --no-status --unknown .") as f:
+ with repoman_popen("hg status --no-status --unknown .") as f:
myunadded = f.readlines()
myunadded = ["./" + elem.rstrip() for elem in myunadded]
# Mercurial doesn't handle manually deleted files as removed from
# the repository, so the user need to remove them before commit,
# using "hg remove [FILES]"
- with os.popen("hg status --no-status --deleted .") as f:
+ with repoman_popen("hg status --no-status --deleted .") as f:
mydeleted = f.readlines()
mydeleted = ["./" + elem.rstrip() for elem in mydeleted]
@@ -2393,36 +2427,36 @@ else:
if vcs == "svn":
- with os.popen("svn status") as f:
+ with repoman_popen("svn status") as f:
svnstatus = f.readlines()
mychanged = [ "./" + elem.split()[-1:][0] for elem in svnstatus if (elem[:1] in "MR" or elem[1:2] in "M")]
mynew = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("A")]
myremoved = [ "./" + elem.split()[-1:][0] for elem in svnstatus if elem.startswith("D")]
# Subversion expands keywords specified in svn:keywords properties.
- with os.popen("svn propget -R svn:keywords") as f:
+ with repoman_popen("svn propget -R svn:keywords") as f:
props = f.readlines()
expansion = dict(("./" + prop.split(" - ")[0], prop.split(" - ")[1].split()) \
for prop in props if " - " in prop)
elif vcs == "git":
- with os.popen("git diff-index --name-only "
+ with repoman_popen("git diff-index --name-only "
"--relative --diff-filter=M HEAD") as f:
mychanged = f.readlines()
mychanged = ["./" + elem[:-1] for elem in mychanged]
- with os.popen("git diff-index --name-only "
+ with repoman_popen("git diff-index --name-only "
"--relative --diff-filter=A HEAD") as f:
mynew = f.readlines()
mynew = ["./" + elem[:-1] for elem in mynew]
- with os.popen("git diff-index --name-only "
+ with repoman_popen("git diff-index --name-only "
"--relative --diff-filter=D HEAD") as f:
myremoved = f.readlines()
myremoved = ["./" + elem[:-1] for elem in myremoved]
if vcs == "bzr":
- with os.popen("bzr status -S .") as f:
+ with repoman_popen("bzr status -S .") as f:
bzrstatus = f.readlines()
mychanged = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and elem[1:2] == "M" ]
mynew = [ "./" + elem.split()[-1:][0].split('/')[-1:][0] for elem in bzrstatus if elem and ( elem[1:2] in "NK" or elem[0:1] == "R" ) ]
@@ -2431,15 +2465,15 @@ else:
# Bazaar expands nothing.
if vcs == "hg":
- with os.popen("hg status --no-status --modified .") as f:
+ with repoman_popen("hg status --no-status --modified .") as f:
mychanged = f.readlines()
mychanged = ["./" + elem.rstrip() for elem in mychanged]
- with os.popen("hg status --no-status --added .") as f:
+ with repoman_popen("hg status --no-status --added .") as f:
mynew = f.readlines()
mynew = ["./" + elem.rstrip() for elem in mynew]
- with os.popen("hg status --no-status --removed .") as f:
+ with repoman_popen("hg status --no-status --removed .") as f:
myremoved = f.readlines()
myremoved = ["./" + elem.rstrip() for elem in myremoved]