60""" Adds an include path to the scanner. """
+ 61ifinclude.endswith('/')orinclude.endswith('\\'):
+ 62include=include+'**'
+ 63
+ 64self.includes.append(include)
+
108""" Returns if path is selected by all selectors in the scanner. """
+109LOGGER.debug("is_selected: path = "+path)
+110forselectorinself.selectors:
+111ifnotselector.is_selected(path):
+112returnFalse
+113LOGGER.debug("Selected: "+path)
+114returnTrue
+
117""" Test if a file matches one filetype. """
+118iflen(self.filetypes)==0:
+119returnTrue
+120LOGGER.debug("is_filetype: path = "+path)
+121forfiletypeinself.filetypes:
+122ifself.match(path,filetype):
+123LOGGER.debug("Filetype: "+path+" by "+filetype)
+124returnTrue
+125returnFalse
+
156"""Scans the filesystem for files that match the selection paths.
+157
+158 The scanner is configured with a root directory. Any number of include
+159 and exclude paths can be added. The scan() method is a generator that
+160 returns matching files one at a time when called as an iterator.
+161
+162 This is a revisited implementation of the filescanner. It now relies on
+163 the module pathaddition.match that implements a Ant-like regular expression matcher.
+164
+165 Rules:
+166 - Includes and excludes should not start with *
+167 - Includes and excludes should not have wildcard searches ending with ** (e.g. wildcard**)
+168
+169 Supported includes and excludes:
+170 - filename.txt
+171 - filename.*
+172 - dir/
+173 - dir/*
+174 - dir/**
+175 """
+
230"""Finds all the subdirectory roots based on the include paths.
+231
+232 Often large archive operations define a number of archives from the root
+233 of the drive. Walking the tree from the root is very time-consuming, so
+234 selecting more specific subdirectory roots improves performance.
+235 """
+236defsplitpath(path):
+237""" Returns the splitted path"""
+238returnpath.split(os.sep)
+
239
+240root_dirs=[]
+241
+242# Look for includes that start with wildcards.
+243subdirs_not_usable=False
+244forincinself.includes+self.includes_files:
+245first_path_segment=splitpath(os.path.normpath(inc))[0]
+246iffirst_path_segment.find('*')!=-1:
+247subdirs_not_usable=True
+248
+249# Parse all includes for sub-roots
+250ifnotsubdirs_not_usable:
+251forincinself.includes+self.includes_files:
+252include=None
+253LOGGER.debug("===> inc %s"%inc)
+254contains_globs=False
+255forpathcompinsplitpath(os.path.normpath(inc)):
+256ifpathcomp.find('*')!=-1:
+257contains_globs=True
+258break
+259else:
+260ifinclude==None:
+261include=pathcomp
+262else:
+263include=os.path.join(include,pathcomp)
+264ifnotcontains_globs:
+265include=os.path.dirname(include)
+266
+267LOGGER.debug("include %s"%include)
+268ifinclude!=None:
+269root_dir=os.path.normpath(os.path.join(self.root_dir,include))
+270is_new_root=True
+271forrootinroot_dirs[:]:
+272ifdestinsrc(root,root_dir):
+273LOGGER.debug("root contains include, skip it")
+274is_new_root=False
+275break
+276ifdestinsrc(root_dir,root):
+277LOGGER.debug("include contains root, so remove root")
+278root_dirs.remove(root)
+279ifis_new_root:
+280root_dirs.append(root_dir)
+281
+282iflen(root_dirs)==0:
+283root_dirs=[os.path.normpath(self.root_dir)]
+284LOGGER.debug('Roots = '+str(root_dirs))
+285returnroot_dirs
+
295"""Recursively move a file or directory to another location.
+296
+297 If the destination is on our current filesystem, then simply use
+298 rename. Otherwise, copy src to the dst and then remove src.
+299 A lot more could be done here... A look at a mv.c shows a lot of
+300 the issues this implementation glosses over.
+301
+302 """
+303try:
+304os.rename(src,dst)
+305exceptOSError:
+306ifos.path.isdir(src):
+307ifdestinsrc(src,dst):
+308raiseException,"Cannot move a directory '%s' into itself '%s'."%(src,dst)
+309shutil.copytree(src,dst,symlinks=True)
+310rmtree(src)
+311else:
+312shutil.copy2(src,dst)
+313os.unlink(src)
+
336""" Fixed version of destinscr, that doesn't match dst with same root name."""
+337ifsys.platform=="win32":
+338src=src.lower()
+339dst=dst.lower()
+340src=os.path.abspath(src)
+341dst=os.path.abspath(dst)
+342ifnotsrc.endswith(os.path.sep):
+343src+=os.path.sep
+344ifnotdst.endswith(os.path.sep):
+345dst+=os.path.sep
+346returndst.startswith(src)
+
350""" Search for executable in the PATH."""
+351pathlist=os.environ['PATH'].split(os.pathsep)
+352forfolderinpathlist:
+353filename=os.path.join(folder,executable)
+354try:
+355status=os.stat(filename)
+356exceptos.error:
+357continue
+358# Check if the path is a regular file
+359ifstat.S_ISREG(status[stat.ST_MODE]):
+360mode=stat.S_IMODE(status[stat.ST_MODE])
+361ifmode&0111:
+362returnos.path.normpath(filename)
+363returnNone
+
405"""Given a byte string, guess the encoding.
+406
+407 First it tries for UTF8/UTF16 BOM.
+408
+409 Next it tries the standard 'UTF8', 'ISO-8859-1', and 'cp1252' encodings,
+410 Plus several gathered from locale information.
+411
+412 The calling program *must* first call locale.setlocale(locale.LC_ALL, '')
+413
+414 If successful it returns (decoded_unicode, successful_encoding)
+415 If unsuccessful it raises a ``UnicodeError``.
+416
+417 This was taken from http://www.voidspace.org.uk/python/articles/guessing_encoding.shtml
+418 """
+419forbom,encinENCODING_MATRIX.items():
+420ifdata.startswith(bom):
+421returndata.decode(enc),enc
+422encodings=['ascii','UTF-8']
+423successful_encoding=None
+424try:
+425encodings.append(locale.getlocale()[1])
+426except(AttributeError,IndexError):
+427pass
+428try:
+429encodings.append(locale.getdefaultlocale()[1])
+430except(AttributeError,IndexError):
+431pass
+432# latin-1
+433encodings.append('ISO8859-1')
+434encodings.append('cp1252')
+435forencinencodings:
+436ifnotenc:
+437continue
+438try:
+439decoded=unicode(data,enc)
+440successful_encoding=enc
+441break
+442except(UnicodeError,LookupError):
+443pass
+444ifsuccessful_encodingisNone:
+445raiseUnicodeError('Unable to decode input data. Tried the'
+446' following encodings: %s.'%
+447', '.join([repr(enc)forencinencodingsifenc]))
+448else:
+449ifsuccessful_encoding=='ascii':
+450# our default ascii encoding
+451successful_encoding='ISO8859-1'
+452return(decoded,successful_encoding)
+
557""" Return the first free drive found else it raise an exception. """
+558DRIVE_LABELS=sorted(list(set(string.ascii_uppercase)-set(win32api.GetLogicalDriveStrings())),reverse=True)
+559iflen(DRIVE_LABELS)!=0:
+560returnDRIVE_LABELS[0]+":"
+561raiseException("No free drive left.")
+
579""" Catch os.rmdir failures on Windows when path is too long (more than 256 chars)."""
+580path=win32api.GetShortPathName(path)
+581win32file.RemoveDirectory(path)
+
584""" Catch os.rmdir failures on Windows when path is too long (more than 256 chars)."""
+585filename=win32api.GetShortPathName(filename)
+586filename=filename.lstrip("\\\\?\\")
+587os.remove(filename)
+
590""" Windows helper function to map a network drive. """
+591flags=0
+592ifpersistent:
+593flags=win32netcon.CONNECT_UPDATE_PROFILE
+594win32wnet.WNetAddConnection2(win32netcon.RESOURCETYPE_DISK,drive,unc,None,username,password,flags)
+
598""" Windows helper function to map a network drive. """
+599drive_type=win32file.GetDriveType(drive)
+600ifdrive_type==win32con.DRIVE_REMOTE:
+601win32wnet.WNetCancelConnection2(drive,win32netcon.CONNECT_UPDATE_PROFILE,1)
+602else:
+603raiseException("%s couldn't be umount."%drive)
+
621"""
+622 Recursively touches all the files in the source path mentioned.
+623 It does not touch the directories.
+624 """
+625srcnames=os.listdir(srcdir)
+626fornameinsrcnames:
+627srcfname=os.path.join(srcdir,name)
+628ifos.path.isdir(srcfname):
+629touch(srcfname)
+630else:
+631ifos.path.exists(srcfname):
+632os.utime(srcfname,None)
+