1
0
mirror of https://github.com/arsenetar/dupeguru.git synced 2024-11-18 04:59:03 +00:00
dupeguru/py/directories.py

162 lines
5.4 KiB
Python
Raw Normal View History

#!/usr/bin/env python
"""
Unit Name: dupeguru.directories
Created By: Virgil Dupras
Created On: 2006/02/27
Last modified by:$Author: virgil $
Last modified on:$Date: 2009-05-28 16:02:48 +0200 (Thu, 28 May 2009) $
$Revision: 4388 $
Copyright 2004-2006 Hardcoded Software (http://www.hardcoded.net)
"""
import xml.dom.minidom
from hsfs import phys
import hsfs as fs
from hsutil.files import FileOrPath
from hsutil.path import Path
(STATE_NORMAL,
STATE_REFERENCE,
STATE_EXCLUDED) = range(3)
class AlreadyThereError(Exception):
"""The path being added is already in the directory list"""
class InvalidPathError(Exception):
"""The path being added is invalid"""
class Directories(object):
#---Override
def __init__(self):
self._dirs = []
self.states = {}
self.dirclass = phys.Directory
self.special_dirclasses = {}
def __contains__(self,path):
for d in self._dirs:
if path in d.path:
return True
return False
def __delitem__(self,key):
self._dirs.__delitem__(key)
def __getitem__(self,key):
return self._dirs.__getitem__(key)
def __len__(self):
return len(self._dirs)
#---Private
def _get_files(self, from_dir, state=STATE_NORMAL):
state = self.states.get(from_dir.path, state)
result = []
for subdir in from_dir.dirs:
for file in self._get_files(subdir, state):
yield file
if state != STATE_EXCLUDED:
for file in from_dir.files:
file.is_ref = state == STATE_REFERENCE
yield file
#---Public
def add_path(self, path):
"""Adds 'path' to self, if not already there.
Raises AlreadyThereError if 'path' is already in self. If path is a directory containing
some of the directories already present in self, 'path' will be added, but all directories
under it will be removed. Can also raise InvalidPathError if 'path' does not exist.
"""
if path in self:
raise AlreadyThereError
self._dirs = [d for d in self._dirs if d.path not in path]
try:
dirclass = self.special_dirclasses.get(path, self.dirclass)
d = dirclass(None, unicode(path))
d[:] #If an InvalidPath exception has to be raised, it will be raised here
self._dirs.append(d)
return d
except fs.InvalidPath:
raise InvalidPathError
def get_files(self):
"""Returns a list of all files that are not excluded.
Returned files also have their 'is_ref' attr set.
"""
for d in self._dirs:
d.force_update()
try:
for file in self._get_files(d):
yield file
except fs.InvalidPath:
pass
def GetState(self, path):
"""Returns the state of 'path' (One of the STATE_* const.)
Raises LookupError if 'path' is not in self.
"""
if path not in self:
raise LookupError("The path '%s' is not in the directory list." % str(path))
try:
return self.states[path]
except KeyError:
if path[-1].startswith('.'): # hidden
return STATE_EXCLUDED
parent = path[:-1]
if parent in self:
return self.GetState(parent)
else:
return STATE_NORMAL
def LoadFromFile(self,infile):
try:
doc = xml.dom.minidom.parse(infile)
except:
return
root_dir_nodes = doc.getElementsByTagName('root_directory')
for rdn in root_dir_nodes:
if not rdn.getAttributeNode('path'):
continue
path = rdn.getAttributeNode('path').nodeValue
try:
self.add_path(Path(path))
except (AlreadyThereError,InvalidPathError):
pass
state_nodes = doc.getElementsByTagName('state')
for sn in state_nodes:
if not (sn.getAttributeNode('path') and sn.getAttributeNode('value')):
continue
path = sn.getAttributeNode('path').nodeValue
state = sn.getAttributeNode('value').nodeValue
self.SetState(Path(path), int(state))
def Remove(self,directory):
self._dirs.remove(directory)
def SaveToFile(self,outfile):
with FileOrPath(outfile, 'wb') as fp:
doc = xml.dom.minidom.Document()
root = doc.appendChild(doc.createElement('directories'))
for root_dir in self:
root_dir_node = root.appendChild(doc.createElement('root_directory'))
root_dir_node.setAttribute('path', unicode(root_dir.path).encode('utf-8'))
for path,state in self.states.iteritems():
state_node = root.appendChild(doc.createElement('state'))
state_node.setAttribute('path', unicode(path).encode('utf-8'))
state_node.setAttribute('value', str(state))
doc.writexml(fp,'\t','\t','\n',encoding='utf-8')
def SetState(self,path,state):
try:
if self.GetState(path) == state:
return
self.states[path] = state
if (self.GetState(path[:-1]) == state) and (not path[-1].startswith('.')):
del self.states[path]
except LookupError:
pass