1 # cvstree.py -- cvs tree utilities
2 # Copyright 1998-2004 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
6 from __future__ import print_function
13 from portage import os
14 from portage import _encodings
15 from portage import _unicode_encode
17 if sys.hexversion >= 0x3000000:
20 # [D]/Name/Version/Date/Flags/Tags
22 def pathdata(entries, path):
24 Returns the data(dict) for a specific file/dir at the path specified."""
25 mysplit=path.split("/")
30 if mys in myentries["dirs"]:
31 myentries=myentries["dirs"][mys]
34 if mytarget in myentries["dirs"]:
35 return myentries["dirs"][mytarget]
36 elif mytarget in myentries["files"]:
37 return myentries["files"][mytarget]
41 def fileat(entries, path):
42 return pathdata(entries,path)
44 def isadded(entries, path):
46 Returns true if the path exists and is added to the cvs tree."""
47 mytarget=pathdata(entries, path)
49 if "cvs" in mytarget["status"]:
52 basedir=os.path.dirname(path)
53 filename=os.path.basename(path)
57 _unicode_encode(os.path.join(basedir, 'CVS', 'Entries'),
58 encoding=_encodings['fs'], errors='strict'),
59 mode='r', encoding=_encodings['content'], errors='strict')
62 mylines=myfile.readlines()
65 rep=re.compile("^\/"+re.escape(filename)+"\/");
72 def findnew(entries,recursive=0,basedir=""):
73 """(entries,recursive=0,basedir="")
74 Recurses the entries tree to find all elements that have been added but
75 have not yet been committed. Returns a list of paths, optionally prepended
77 if basedir and basedir[-1]!="/":
80 for myfile in entries["files"]:
81 if "cvs" in entries["files"][myfile]["status"]:
82 if "0" == entries["files"][myfile]["revision"]:
83 mylist.append(basedir+myfile)
85 for mydir in entries["dirs"]:
86 mylist+=findnew(entries["dirs"][mydir],recursive,basedir+mydir)
89 def findoption(entries, pattern, recursive=0, basedir=""):
90 """(entries, pattern, recursive=0, basedir="")
91 Iterate over paths of cvs entries for which the pattern.search() method
92 finds a match. Returns a list of paths, optionally prepended with a
94 if not basedir.endswith("/"):
96 for myfile, mydata in entries["files"].items():
97 if "cvs" in mydata["status"]:
98 if pattern.search(mydata["flags"]):
101 for mydir, mydata in entries["dirs"].items():
102 for x in findoption(mydata, pattern,
103 recursive, basedir+mydir):
106 def findchanged(entries,recursive=0,basedir=""):
107 """(entries,recursive=0,basedir="")
108 Recurses the entries tree to find all elements that exist in the cvs tree
109 and differ from the committed version. Returns a list of paths, optionally
110 prepended with a basedir."""
111 if basedir and basedir[-1]!="/":
114 for myfile in entries["files"]:
115 if "cvs" in entries["files"][myfile]["status"]:
116 if "current" not in entries["files"][myfile]["status"]:
117 if "exists" in entries["files"][myfile]["status"]:
118 if entries["files"][myfile]["revision"]!="0":
119 mylist.append(basedir+myfile)
121 for mydir in entries["dirs"]:
122 mylist+=findchanged(entries["dirs"][mydir],recursive,basedir+mydir)
125 def findmissing(entries,recursive=0,basedir=""):
126 """(entries,recursive=0,basedir="")
127 Recurses the entries tree to find all elements that are listed in the cvs
128 tree but do not exist on the filesystem. Returns a list of paths,
129 optionally prepended with a basedir."""
130 if basedir and basedir[-1]!="/":
133 for myfile in entries["files"]:
134 if "cvs" in entries["files"][myfile]["status"]:
135 if "exists" not in entries["files"][myfile]["status"]:
136 if "removed" not in entries["files"][myfile]["status"]:
137 mylist.append(basedir+myfile)
139 for mydir in entries["dirs"]:
140 mylist+=findmissing(entries["dirs"][mydir],recursive,basedir+mydir)
143 def findunadded(entries,recursive=0,basedir=""):
144 """(entries,recursive=0,basedir="")
145 Recurses the entries tree to find all elements that are in valid cvs
146 directories but are not part of the cvs tree. Returns a list of paths,
147 optionally prepended with a basedir."""
148 if basedir and basedir[-1]!="/":
152 #ignore what cvs ignores.
153 for myfile in entries["files"]:
154 if "cvs" not in entries["files"][myfile]["status"]:
155 mylist.append(basedir+myfile)
157 for mydir in entries["dirs"]:
158 mylist+=findunadded(entries["dirs"][mydir],recursive,basedir+mydir)
161 def findremoved(entries,recursive=0,basedir=""):
162 """(entries,recursive=0,basedir="")
163 Recurses the entries tree to find all elements that are in flagged for cvs
164 deletions. Returns a list of paths, optionally prepended with a basedir."""
165 if basedir and basedir[-1]!="/":
168 for myfile in entries["files"]:
169 if "removed" in entries["files"][myfile]["status"]:
170 mylist.append(basedir+myfile)
172 for mydir in entries["dirs"]:
173 mylist+=findremoved(entries["dirs"][mydir],recursive,basedir+mydir)
176 def findall(entries, recursive=0, basedir=""):
177 """(entries,recursive=0,basedir="")
178 Recurses the entries tree to find all new, changed, missing, and unadded
179 entities. Returns a 4 element list of lists as returned from each find*()."""
181 if basedir and basedir[-1]!="/":
183 mynew = findnew(entries,recursive,basedir)
184 mychanged = findchanged(entries,recursive,basedir)
185 mymissing = findmissing(entries,recursive,basedir)
186 myunadded = findunadded(entries,recursive,basedir)
187 myremoved = findremoved(entries,recursive,basedir)
188 return [mynew, mychanged, mymissing, myunadded, myremoved]
190 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)$")
191 def apply_cvsignore_filter(list):
194 if ignore_list.match(list[x].split("/")[-1]):
200 def getentries(mydir,recursive=0):
201 """(basedir,recursive=0)
202 Scans the given directory and returns an datadict of all the entries in
203 the directory seperated as a dirs dict and a files dict."""
204 myfn=mydir+"/CVS/Entries"
205 # entries=[dirs, files]
206 entries={"dirs":{},"files":{}}
207 if not os.path.exists(mydir):
210 myfile = codecs.open(_unicode_encode(myfn,
211 encoding=_encodings['fs'], errors='strict'),
212 mode='r', encoding=_encodings['content'], errors='strict')
213 mylines=myfile.readlines()
215 except SystemExit as e:
220 if line and line[-1]=="\n":
224 if line=="D": # End of entries file
226 mysplit=line.split("/")
228 print("Confused:",mysplit)
231 entries["dirs"][mysplit[1]]={"dirs":{},"files":{},"status":[]}
232 entries["dirs"][mysplit[1]]["status"]=["cvs"]
233 if os.path.isdir(mydir+"/"+mysplit[1]):
234 entries["dirs"][mysplit[1]]["status"]+=["exists"]
235 entries["dirs"][mysplit[1]]["flags"]=mysplit[2:]
237 rentries=getentries(mydir+"/"+mysplit[1],recursive)
238 entries["dirs"][mysplit[1]]["dirs"]=rentries["dirs"]
239 entries["dirs"][mysplit[1]]["files"]=rentries["files"]
241 # [D]/Name/revision/Date/Flags/Tags
242 entries["files"][mysplit[1]]={}
243 entries["files"][mysplit[1]]["revision"]=mysplit[2]
244 entries["files"][mysplit[1]]["date"]=mysplit[3]
245 entries["files"][mysplit[1]]["flags"]=mysplit[4]
246 entries["files"][mysplit[1]]["tags"]=mysplit[5]
247 entries["files"][mysplit[1]]["status"]=["cvs"]
248 if entries["files"][mysplit[1]]["revision"][0]=="-":
249 entries["files"][mysplit[1]]["status"]+=["removed"]
251 for file in apply_cvsignore_filter(os.listdir(mydir)):
254 if file=="digest-framerd-2.4.3":
256 if os.path.isdir(mydir+"/"+file):
257 if file not in entries["dirs"]:
258 entries["dirs"][file]={"dirs":{},"files":{}}
259 # It's normal for a directory to be unlisted in Entries
260 # when checked out without -P (see bug #257660).
261 rentries=getentries(mydir+"/"+file,recursive)
262 entries["dirs"][file]["dirs"]=rentries["dirs"]
263 entries["dirs"][file]["files"]=rentries["files"]
264 if "status" in entries["dirs"][file]:
265 if "exists" not in entries["dirs"][file]["status"]:
266 entries["dirs"][file]["status"]+=["exists"]
268 entries["dirs"][file]["status"]=["exists"]
269 elif os.path.isfile(mydir+"/"+file):
270 if file=="digest-framerd-2.4.3":
272 if file not in entries["files"]:
273 entries["files"][file]={"revision":"","date":"","flags":"","tags":""}
274 if "status" in entries["files"][file]:
275 if file=="digest-framerd-2.4.3":
277 if "exists" not in entries["files"][file]["status"]:
278 if file=="digest-framerd-2.4.3":
279 print("no exists in status")
280 entries["files"][file]["status"]+=["exists"]
282 if file=="digest-framerd-2.4.3":
284 entries["files"][file]["status"]=["exists"]
286 if file=="digest-framerd-2.4.3":
288 mystat=os.stat(mydir+"/"+file)
289 mytime = time.asctime(time.gmtime(long(mystat.st_mtime)))
290 if "status" not in entries["files"][file]:
291 if file=="digest-framerd-2.4.3":
292 print("status not set")
293 entries["files"][file]["status"]=[]
294 if file=="digest-framerd-2.4.3":
295 print("date:",entries["files"][file]["date"])
296 print("sdate:",mytime)
297 if mytime==entries["files"][file]["date"]:
298 entries["files"][file]["status"]+=["current"]
299 if file=="digest-framerd-2.4.3":
303 except SystemExit as e:
305 except Exception as e:
306 print("failed to stat",file)
312 print("File of unknown type:",mydir+"/"+file)