206 lines
6.6 KiB
Python
206 lines
6.6 KiB
Python
# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
|
|
"""Des fonctions pour gérer les chemins.
|
|
"""
|
|
|
|
__all__ = ('in_PATH', 'matches_name',
|
|
'KNOWN_BINARY_EXTS', 'fileext_is_binary',
|
|
'dirname', 'basename', 'splitall',
|
|
'abspath', 'abspath2', 'relpath', 'ppath',
|
|
'mkdirp', 'mkdirof',
|
|
)
|
|
|
|
import os, re
|
|
from os import path
|
|
from fnmatch import fnmatch
|
|
|
|
def in_PATH(cmd):
|
|
"""Retourner True si la commande cmd est dans le PATH et est exécutable.
|
|
"""
|
|
PATH = os.environ.get('PATH', None)
|
|
if not PATH: return False
|
|
|
|
for p in PATH.split(os.pathsep):
|
|
pf = path.join(p, cmd)
|
|
if os.access(pf, os.X_OK):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def matches_name(pattern, name, basedir=''):
|
|
"""Retourner True si name correspond au pattern pattern
|
|
|
|
name étant exprimé relativement au répertoire basedir, si pattern se
|
|
termine par '/', alors la correspondance ne se fait que si name est
|
|
effectivement un répertoire sur le système de fichier. Sinon, la
|
|
correspondance se fait sur le nom de fichier, sans tenir compte du système
|
|
de fichier.
|
|
"""
|
|
if pattern[-1:] == '/':
|
|
pf = path.join(basedir, name)
|
|
pattern = pattern[:-1]
|
|
return path.isdir(pf) and fnmatch(name, pattern)
|
|
else:
|
|
return fnmatch(name, pattern)
|
|
|
|
KNOWN_BINARY_EXTS = (
|
|
'.avi', '.bin', '.bmp', '.bpt', '.bro', '.bz2', '.class', '.com',
|
|
'.dat', '.dll', '.doc', '.eps', '.ex_', '.exe', '.fm', '.gif', '.gz',
|
|
'.hqx', '.icns', '.ico', '.ins', '.jar', '.jpeg', '.jpg', '.lib',
|
|
'.mcp', '.mov', '.mp3', '.mpg', '.objectplant', '.ofp', '.opn',
|
|
'.ovl', '.pdf', '.png', '.ppt', '.pqg', '.prj', '.ps', '.pyc', '.pyd',
|
|
'.pyo', '.rpm', '.sit', '.sl', '.snd', '.so', '.so.3', '.srpm',
|
|
'.strings', '.swf', '.tar', '.tgz', '.tbz2', '.tif', '.tiff',
|
|
'.wordbreak', '.xbm', '.xls', '.zip',
|
|
)
|
|
def fileext_is_binary(file):
|
|
"""Retourner True si l'extension du fichier est celle d'un fichier binaire
|
|
"""
|
|
_, f = path.split(file)
|
|
if f == '.DS_Store': return True
|
|
_, fe = path.splitext(f)
|
|
return fe.lower() in KNOWN_BINARY_EXTS
|
|
|
|
def dirname(file):
|
|
"""Retourner le répertoire qui contient file.
|
|
|
|
dirname('/') --> '/'
|
|
"""
|
|
return path.split(file)[0]
|
|
|
|
def basename(file, strip_ext=None):
|
|
"""Retourner le nom de base de file, en enlevant éventuellement l'extension strip_ext
|
|
"""
|
|
bn = path.split(file)[1]
|
|
if strip_ext is not None:
|
|
n, e = path.splitext(bn)
|
|
if e == strip_ext: bn = n
|
|
return bn
|
|
|
|
RE_ROOT = re.compile(r'/*$')
|
|
def splitall(file):
|
|
"""Retourner tous les composants de file (répertoires et fichier)
|
|
|
|
Par exemple:
|
|
splitall("/a/b") --> ["a", "b"]
|
|
Cas particuliers:
|
|
splitall("") --> []
|
|
splitall("/") --> []
|
|
"""
|
|
dirs = []
|
|
while RE_ROOT.match(file) is None:
|
|
dir, name = path.split(file)
|
|
dirs.insert(0, name)
|
|
file = dir
|
|
return dirs
|
|
|
|
def _join(dir, name):
|
|
return path.normpath(path.join(dir, name))
|
|
|
|
def abspath(file, basedir=None, cwd=None):
|
|
"""Retourner le chemin absolu de file.
|
|
|
|
file est exprimé par rapport au répertoire basedir, qui est exprimé par
|
|
rapport à cwd s'il est relatif.
|
|
"""
|
|
if path.isabs(file): return file
|
|
if basedir is not None:
|
|
file = _join(basedir, file)
|
|
if path.isabs(file): return file
|
|
if cwd is None: cwd = os.getcwd()
|
|
return _join(cwd, file)
|
|
|
|
def abspath2(file, basedir=None, cwd=None):
|
|
"""Retourner le chemin absolu de file.
|
|
|
|
Si file a un chemin ou s'il existe dans cwd, il est exprimé par rapport à cwd.
|
|
Si file est sans chemin et qu'il n'existe pas dans cwd, il est exprimé par
|
|
rapport à basedir.
|
|
"""
|
|
if path.isabs(file): return file
|
|
if cwd is None: cwd = os.getcwd()
|
|
cwdfile = _join(cwd, file)
|
|
if path.exists(cwdfile): return cwdfile
|
|
if basedir is not None:
|
|
dir, _ = path.split(file)
|
|
if dir == "": file = _join(basedir, file)
|
|
if path.isabs(file): return file
|
|
return _join(cwd, file)
|
|
|
|
def relpath(file, basedir=None, cwd=None):
|
|
"""Retourner le chemin relatif pour accéder à file depuis cwd.
|
|
file est exprimé par rapport au répertoire basedir.
|
|
"""
|
|
if cwd is None: cwd = os.getcwd()
|
|
cwd = path.abspath(cwd)
|
|
cwdslash = cwd + '/'
|
|
if basedir is None: basedir = cwd
|
|
if not path.isabs(file): file = path.abspath(path.join(basedir, file))
|
|
file = path.normpath(file)
|
|
|
|
if file.startswith(cwdslash):
|
|
file = file[len(cwdslash):]
|
|
elif file == cwd:
|
|
file = '.'
|
|
else:
|
|
prefix = path.commonprefix([file, cwd])
|
|
if not prefix.endswith('/'):
|
|
pos = prefix.rfind('/')
|
|
if pos != - 1: prefix = prefix[:pos + 1]
|
|
file = file[len(prefix):]
|
|
cwd = cwd[len(prefix):]
|
|
levels = len(splitall(cwd))
|
|
relpath = ''
|
|
for _ in range(levels):
|
|
relpath = path.join('..', relpath)
|
|
file = path.join(relpath, file)
|
|
return file
|
|
|
|
def ppath(file, basedir=None, cwd=None, homedir=None):
|
|
"""Retourner si possible le chemin relatif pour accéder à file depuis cwd,
|
|
homedir, ou le chemin absolu, suivant les cas exposés ci-dessous. file est
|
|
exprimé par rapport au répertoire basedir.
|
|
|
|
Le chemin retourné par cette fonction est destiné à l'affichage.
|
|
|
|
- Si file est situé dans l'arborescence à partir de cwd, alors retourner un
|
|
chemin du genre relpath/to/file.
|
|
- Si file est situé dans le répertoire $HOME, alors retourner un chemine du
|
|
genre ~/path/to/file
|
|
- Sinon, retourner le chemin absolu /path/to/file
|
|
"""
|
|
if cwd is None: cwd = os.getcwd()
|
|
cwd = path.abspath(cwd)
|
|
if basedir is None: basedir = cwd
|
|
if not path.isabs(file): file = path.abspath(path.join(basedir, file))
|
|
file = path.normpath(file)
|
|
if homedir is None: homedir = path.expanduser('~')
|
|
homedir = path.abspath(homedir)
|
|
# depuis cwd
|
|
ppath = relpath(file, cwd=cwd)
|
|
if not ppath.startswith('../'): return ppath
|
|
# depuis ~
|
|
ppath = relpath(file, cwd=homedir)
|
|
if ppath == '.': return '~'
|
|
elif not ppath.startswith('../'): return '~/' + ppath
|
|
# sinon chemin absolu
|
|
return file
|
|
|
|
def mkdirp(dir):
|
|
"""Créer si nécessaire le répertoire
|
|
|
|
@return: True si le répertoire a été créé, False sinon
|
|
"""
|
|
if not path.isdir(dir):
|
|
os.makedirs(dir)
|
|
return True
|
|
return False
|
|
|
|
def mkdirof(file):
|
|
"""Créer si nécessaire le répertoire du fichier file
|
|
|
|
@return: True si le répertoire a été créé, False sinon
|
|
"""
|
|
dir, _ = path.split(file)
|
|
return mkdirp(dir)
|