fileutils.py

download

# Copyright (c) 2000-2003 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr

# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.

# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""
Some file / file path manipulation utilities
"""

__revision__ = "$Id: fileutils.py,v 1.6 2003/09/22 08:22:05 syt Exp $"

from __future__ import nested_scopes
import sys
import re
import shutil
from os.path import isabs, isdir, split, exists, walk
from os import sep, linesep, mkdir, remove
from sys import version_info

HAS_UNIV_OPEN = version_info[:2] >= (2, 3)
LINE_RGX = re.compile('\r\n|\r|\n')

def first_level_directory(path):
"""return the first level directory of a path"""
head, tail = split(path)
while head and tail:
head, tail = split(head)
if tail:
return tail
# path was absolute, head is the fs root
return head

class UnresolvableError(Exception):
"""exception raise by relative path when it's unable to compute relative path
between two paths
"""

def relative_path(from_file, to_file):
"""try to get a relative path from from <from_file> to <to_file>
(path will be absolute if to_file is an absolute file).

If both files are relative, they're expected to be relative to the same
directory.

FIXME: doesn't handle '.' and '..'

EXAMPLES:

>>> get_link_prefix( from_file='toto/index.html', to_file='index.html')
'../index.html'

>>> get_link_prefix( from_file='index.html', to_file='toto/index.html')
'toto/index.html'

>>> get_link_prefix( from_file='tutu/index.html', to_file='toto/index.html')
'../toto/index.html'

>>> get_link_prefix( from_file='toto/index.html', to_file='/index.html')
'/index.html'

>>> get_link_prefix( from_file='/toto/index.html', to_file='/index.html')
'/index.html'

>>> get_link_prefix( from_file='index.html', to_file='index.html')
''

>>> get_link_prefix( from_file='/index.html', to_file='toto/index.html')
Traceback (most recent call last):
File "<string>", line 1, in ?
File "<stdin>", line 37, in get_link_prefix
UnresolvableError
"""
if from_file == to_file:
return ''
if isabs(to_file):
return to_file
if isabs(from_file):
raise UnresolvableError()
from_parts = from_file.split(sep)
to_parts = to_file.split(sep)
idem = 1
result = []
while len(from_parts) > 1:
dirname = from_parts.pop(0)
if idem and len(to_parts) > 1 and dirname == to_parts[0]:
to_parts.pop(0)
else:
idem = 0
result.append('..')
result += to_parts
return sep.join(result)

def norm_read(path, linesep=linesep):
"""open a file, an normalize line feed
"""
if HAS_UNIV_OPEN:
return open(path, 'U').read()
stream = open(path)
return LINE_RGX.sub(linesep, stream.read())

def lines(path):
"""return a list of non empty lines in <filename>
"""
result = []
f = open(path)
for line in f.readlines():
line = line.strip()
if line:
result.append(line)
return result

BASE_BLACKLIST = ('CVS', 'debian', 'dist', 'build', '__buildlog')
IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc')

def export(from_dir, to_dir,
blacklist=BASE_BLACKLIST,
ignore_ext=IGNORED_EXTENSIONS):
"""make a mirror of from_dir in to_dir, omitting directories and files
listed in the black list
"""
def make_mirror(arg, dir, fnames):
"""walk handler"""
for norecurs in blacklist:
try:
fnames.remove(norecurs)
except:
pass
for file in fnames:
# don't include binary files
if file[-4:] in ignore_ext:
continue
if file[-1] == '~':
continue
src = '%s/%s' % (dir, file)
dest = to_dir + src[len(from_dir):]
print >>sys.stderr, src, '->', dest
if isdir(src):
if not exists(dest):
mkdir(dest)
else:
if exists(dest):
remove(dest)
shutil.copy2(src, dest)
try:
mkdir(to_dir)
except:
pass
walk(from_dir, make_mirror, None)