blob: f36e9230c73fb346d68c191f82be8f968c48f599 [file] [log] [blame]
# cvstree.py -- cvs tree utilities
# Copyright 1998-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from __future__ import print_function
import codecs
import re
import stat
import sys
import time
from portage import os
from portage import _encodings
from portage import _unicode_encode
if sys.hexversion >= 0x3000000:
long = int
# [D]/Name/Version/Date/Flags/Tags
def pathdata(entries, path):
"""(entries,path)
Returns the data(dict) for a specific file/dir at the path specified."""
mysplit=path.split("/")
myentries=entries
mytarget=mysplit[-1]
mysplit=mysplit[:-1]
for mys in mysplit:
if mys in myentries["dirs"]:
myentries=myentries["dirs"][mys]
else:
return None
if mytarget in myentries["dirs"]:
return myentries["dirs"][mytarget]
elif mytarget in myentries["files"]:
return myentries["files"][mytarget]
else:
return None
def fileat(entries, path):
return pathdata(entries,path)
def isadded(entries, path):
"""(entries,path)
Returns true if the path exists and is added to the cvs tree."""
mytarget=pathdata(entries, path)
if mytarget:
if "cvs" in mytarget["status"]:
return 1
basedir=os.path.dirname(path)
filename=os.path.basename(path)
try:
myfile = codecs.open(
_unicode_encode(os.path.join(basedir, 'CVS', 'Entries'),
encoding=_encodings['fs'], errors='strict'),
mode='r', encoding=_encodings['content'], errors='strict')
except IOError:
return 0
mylines=myfile.readlines()
myfile.close()
rep=re.compile("^\/"+re.escape(filename)+"\/");
for x in mylines:
if rep.search(x):
return 1
return 0
def findnew(entries,recursive=0,basedir=""):
"""(entries,recursive=0,basedir="")
Recurses the entries tree to find all elements that have been added but
have not yet been committed. Returns a list of paths, optionally prepended
with a basedir."""
if basedir and basedir[-1]!="/":
basedir=basedir+"/"
mylist=[]
for myfile in entries["files"]:
if "cvs" in entries["files"][myfile]["status"]:
if "0" == entries["files"][myfile]["revision"]:
mylist.append(basedir+myfile)
if recursive:
for mydir in entries["dirs"]:
mylist+=findnew(entries["dirs"][mydir],recursive,basedir+mydir)
return mylist
def findoption(entries, pattern, recursive=0, basedir=""):
"""(entries, pattern, recursive=0, basedir="")
Iterate over paths of cvs entries for which the pattern.search() method
finds a match. Returns a list of paths, optionally prepended with a
basedir."""
if not basedir.endswith("/"):
basedir += "/"
for myfile, mydata in entries["files"].items():
if "cvs" in mydata["status"]:
if pattern.search(mydata["flags"]):
yield basedir+myfile
if recursive:
for mydir, mydata in entries["dirs"].items():
for x in findoption(mydata, pattern,
recursive, basedir+mydir):
yield x
def findchanged(entries,recursive=0,basedir=""):
"""(entries,recursive=0,basedir="")
Recurses the entries tree to find all elements that exist in the cvs tree
and differ from the committed version. Returns a list of paths, optionally
prepended with a basedir."""
if basedir and basedir[-1]!="/":
basedir=basedir+"/"
mylist=[]
for myfile in entries["files"]:
if "cvs" in entries["files"][myfile]["status"]:
if "current" not in entries["files"][myfile]["status"]:
if "exists" in entries["files"][myfile]["status"]:
if entries["files"][myfile]["revision"]!="0":
mylist.append(basedir+myfile)
if recursive:
for mydir in entries["dirs"]:
mylist+=findchanged(entries["dirs"][mydir],recursive,basedir+mydir)
return mylist
def findmissing(entries,recursive=0,basedir=""):
"""(entries,recursive=0,basedir="")
Recurses the entries tree to find all elements that are listed in the cvs
tree but do not exist on the filesystem. Returns a list of paths,
optionally prepended with a basedir."""
if basedir and basedir[-1]!="/":
basedir=basedir+"/"
mylist=[]
for myfile in entries["files"]:
if "cvs" in entries["files"][myfile]["status"]:
if "exists" not in entries["files"][myfile]["status"]:
if "removed" not in entries["files"][myfile]["status"]:
mylist.append(basedir+myfile)
if recursive:
for mydir in entries["dirs"]:
mylist+=findmissing(entries["dirs"][mydir],recursive,basedir+mydir)
return mylist
def findunadded(entries,recursive=0,basedir=""):
"""(entries,recursive=0,basedir="")
Recurses the entries tree to find all elements that are in valid cvs
directories but are not part of the cvs tree. Returns a list of paths,
optionally prepended with a basedir."""
if basedir and basedir[-1]!="/":
basedir=basedir+"/"
mylist=[]
#ignore what cvs ignores.
for myfile in entries["files"]:
if "cvs" not in entries["files"][myfile]["status"]:
mylist.append(basedir+myfile)
if recursive:
for mydir in entries["dirs"]:
mylist+=findunadded(entries["dirs"][mydir],recursive,basedir+mydir)
return mylist
def findremoved(entries,recursive=0,basedir=""):
"""(entries,recursive=0,basedir="")
Recurses the entries tree to find all elements that are in flagged for cvs
deletions. Returns a list of paths, optionally prepended with a basedir."""
if basedir and basedir[-1]!="/":
basedir=basedir+"/"
mylist=[]
for myfile in entries["files"]:
if "removed" in entries["files"][myfile]["status"]:
mylist.append(basedir+myfile)
if recursive:
for mydir in entries["dirs"]:
mylist+=findremoved(entries["dirs"][mydir],recursive,basedir+mydir)
return mylist
def findall(entries, recursive=0, basedir=""):
"""(entries,recursive=0,basedir="")
Recurses the entries tree to find all new, changed, missing, and unadded
entities. Returns a 4 element list of lists as returned from each find*()."""
if basedir and basedir[-1]!="/":
basedir=basedir+"/"
mynew = findnew(entries,recursive,basedir)
mychanged = findchanged(entries,recursive,basedir)
mymissing = findmissing(entries,recursive,basedir)
myunadded = findunadded(entries,recursive,basedir)
myremoved = findremoved(entries,recursive,basedir)
return [mynew, mychanged, mymissing, myunadded, myremoved]
ignore_list = re.compile("(^|/)(RCS(|LOG)|SCCS|CVS(|\.adm)|cvslog\..*|tags|TAGS|\.(make\.state|nse_depinfo)|.*~|(\.|)#.*|,.*|_$.*|.*\$|\.del-.*|.*\.(old|BAK|bak|orig|rej|a|olb|o|obj|so|exe|Z|elc|ln)|core)$")
def apply_cvsignore_filter(list):
x=0
while x < len(list):
if ignore_list.match(list[x].split("/")[-1]):
list.pop(x)
else:
x+=1
return list
def getentries(mydir,recursive=0):
"""(basedir,recursive=0)
Scans the given directory and returns an datadict of all the entries in
the directory seperated as a dirs dict and a files dict."""
myfn=mydir+"/CVS/Entries"
# entries=[dirs, files]
entries={"dirs":{},"files":{}}
if not os.path.exists(mydir):
return entries
try:
myfile = codecs.open(_unicode_encode(myfn,
encoding=_encodings['fs'], errors='strict'),
mode='r', encoding=_encodings['content'], errors='strict')
mylines=myfile.readlines()
myfile.close()
except SystemExit as e:
raise
except:
mylines=[]
for line in mylines:
if line and line[-1]=="\n":
line=line[:-1]
if not line:
continue
if line=="D": # End of entries file
break
mysplit=line.split("/")
if len(mysplit)!=6:
print("Confused:",mysplit)
continue
if mysplit[0]=="D":
entries["dirs"][mysplit[1]]={"dirs":{},"files":{},"status":[]}
entries["dirs"][mysplit[1]]["status"]=["cvs"]
if os.path.isdir(mydir+"/"+mysplit[1]):
entries["dirs"][mysplit[1]]["status"]+=["exists"]
entries["dirs"][mysplit[1]]["flags"]=mysplit[2:]
if recursive:
rentries=getentries(mydir+"/"+mysplit[1],recursive)
entries["dirs"][mysplit[1]]["dirs"]=rentries["dirs"]
entries["dirs"][mysplit[1]]["files"]=rentries["files"]
else:
# [D]/Name/revision/Date/Flags/Tags
entries["files"][mysplit[1]]={}
entries["files"][mysplit[1]]["revision"]=mysplit[2]
entries["files"][mysplit[1]]["date"]=mysplit[3]
entries["files"][mysplit[1]]["flags"]=mysplit[4]
entries["files"][mysplit[1]]["tags"]=mysplit[5]
entries["files"][mysplit[1]]["status"]=["cvs"]
if entries["files"][mysplit[1]]["revision"][0]=="-":
entries["files"][mysplit[1]]["status"]+=["removed"]
for file in apply_cvsignore_filter(os.listdir(mydir)):
if file=="CVS":
continue
if os.path.isdir(mydir+"/"+file):
if file not in entries["dirs"]:
entries["dirs"][file]={"dirs":{},"files":{}}
# It's normal for a directory to be unlisted in Entries
# when checked out without -P (see bug #257660).
rentries=getentries(mydir+"/"+file,recursive)
entries["dirs"][file]["dirs"]=rentries["dirs"]
entries["dirs"][file]["files"]=rentries["files"]
if "status" in entries["dirs"][file]:
if "exists" not in entries["dirs"][file]["status"]:
entries["dirs"][file]["status"]+=["exists"]
else:
entries["dirs"][file]["status"]=["exists"]
elif os.path.isfile(mydir+"/"+file):
if file not in entries["files"]:
entries["files"][file]={"revision":"","date":"","flags":"","tags":""}
if "status" in entries["files"][file]:
if "exists" not in entries["files"][file]["status"]:
entries["files"][file]["status"]+=["exists"]
else:
entries["files"][file]["status"]=["exists"]
try:
mystat=os.stat(mydir+"/"+file)
mytime = time.asctime(time.gmtime(mystat[stat.ST_MTIME]))
if "status" not in entries["files"][file]:
entries["files"][file]["status"]=[]
if mytime==entries["files"][file]["date"]:
entries["files"][file]["status"]+=["current"]
except SystemExit as e:
raise
except Exception as e:
print("failed to stat",file)
print(e)
return
else:
print()
print("File of unknown type:",mydir+"/"+file)
print()
return entries