You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-lib/pym/calculate/lib/utils/files.py

1094 lines
36 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#-*- coding: utf-8 -*-
# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from os import path
import subprocess
from subprocess import Popen,PIPE,STDOUT
import stat
from shutil import copytree, rmtree,copy2
from calculate.lib import cl_overriding
import re
import sys
from itertools import *
import tarfile
import select
import fcntl
from contextlib import contextmanager
import signal
@contextmanager
def timeout(seconds):
def timeout_handler(signum,frame):
pass
original_handler = signal.signal(signal.SIGALRM, timeout_handler)
try:
signal.alarm(seconds)
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, original_handler)
try:
from magic import (open as type_file, MAGIC_NONE, MAGIC_CONTINUE,
MAGIC_MIME_TYPE, MAGIC_COMPRESS,
MAGIC_MIME_ENCODING, MAGIC_SYMLINK)
except ImportError as e:
try:
from magic import (open as type_file, NONE as MAGIC_NONE,
CONTINUE as MAGIC_CONTNUE, MIME_TYPE as MAGIC_MIME_TYPE,
COMPRESS as MAGIC_COMPRESS,MIME_ENCODING as MIME_ENCODING,
SYMLINK as MAGIC_SYMLINK)
except:
type_file = None
MAGIC_NONE = 0
MAGIC_SYMLINK = 0x002
MAGIC_COMPRESS = 0x004
MAGIC_CONTINUE = 0x020
MAGIC_MIME_TYPE = 0x010
MAGIC_MIME_ENCODING = 0x400
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_lib3',sys.modules[__name__])
reSearch = lambda pattern,listar:map(lambda x:x.groups(),
filter(None,
map(pattern.search,listar)))
class FilesError(Exception):
pass
class process:
"""Execute system command by Popen
Examples:
execute program and get result:
if process("/bin/gzip","/boot/somefile").success():
print "Gzip success"
unzip and process unzip data by cpio (list files):
processGzip = process("/bin/gzip","-dc","/boot/initrd")
processCpio = process("/bin/cpio","-tf",stdin=processGzip)
filelist = processCpio.readlines()
execute command and send data:
processGrub = process("/sbin/grub")
processGrub.write("root (hd0,0)\n")
processGrub.write("setup (hd0)\n")
processGrub.write("quit\n")
isok = processGrub.success()
union stdout and stderr:
process("/bin/ls","/",stderr=STDOUT)
result to stdout:
process("/bin/ls",stdout=None)
get data from keyboard:
process("/bin/cat",stdin=None)
"""
def __init__(self,command,*params,**kwarg):
if not "stdin" in kwarg:
stdin=self._defaultStdin
else:
if kwarg["stdin"] == None:
stdin = self._keyboardStdin
else:
stdin=kwarg["stdin"].getStdout
self.stdout = kwarg.get("stdout",PIPE)
self.envdict = kwarg.get("envdict",os.environ.copy())
self.envdict["LANG"] = kwarg.get('lang','C')
self.langc = "langc" in kwarg
self.stderr = kwarg.get("stderr",PIPE)
self.cwd = kwarg.get("cwd",None)
self.command = getProgPath(command)
if not self.command:
raise FilesError(_("Command not found '%s'")%
command)
self.command = [self.command] + list(params)
self.stdin = stdin
self.iter = None
self.pipe = None
self.cacheresult = None
self.cacheerr = None
self.communicated = False
def _open(self):
"""Open pipe if it not open"""
if not self.pipe:
self.pipe = Popen(self.command,
stdout=self.stdout,
stdin=self.stdin(),
stderr=self.stderr,
cwd=self.cwd,
close_fds=True,
env=self.envdict)
def _defaultStdin(self):
"""Return default stdin"""
return PIPE
def _keyboardStdin(self):
"""Return keyboard stdin"""
return None
def getStdout(self):
"""Get current stdout"""
self.close()
self._open()
return self.pipe.stdout
def write(self,data):
"""Write to process stdin"""
self._open()
self.pipe.stdin.write(data)
self.pipe.stdin.flush()
def close(self):
"""Close stdin"""
if self.pipe:
self.pipe.stdin.close()
def readerr(self):
self.read()
return self.cacheerr
def readByLine(self):
try:
self._open()
if self.cacheresult is None:
self.cacheresult = []
s = self.pipe.stdout.readline()
while s:
yield s
s = self.pipe.stdout.readline()
if self.pipe.stderr:
self.cacheerr = self.pipe.stderr.read()
else:
self.cacheerr = ""
except KeyboardInterrupt:
self.kill()
raise KeyboardInterrupt
finally:
self.cacheresult = "\n".join(self.cacheresult)
def read(self):
"""Read all data"""
try:
self._open()
if self.cacheresult is None:
self.cacheresult,self.cacheerr = self.pipe.communicate()
return self.cacheresult
except KeyboardInterrupt:
self.kill()
raise KeyboardInterrupt
def readlines(self):
"""Read lines"""
return self.read().split('\n')
def __iter__(self):
"""Get iterator"""
if not self.iter:
self.iter = iter(self.readlines())
return self.iter
def kill(self):
"""Kill this process"""
if self.pipe:
self.pipe.kill()
def next(self):
"""Next string from stdout"""
return self.__iter__().next()
def returncode(self):
"""Get return code"""
self.read()
return self.pipe.returncode
def success(self):
"""Success or not"""
return self.returncode() == 0
def failed(self):
"""Failed or not"""
return self.returncode() != 0
def getModeFile(nameFile, mode="all"):
"""Выдает информацию о файле
mode=="all"
права файла, владелец, группа файла
mode=="mode"
права файла
mode=="owner"
владелец, группа файла
"""
fst = os.lstat(nameFile)
if mode == "all":
return (stat.S_IMODE(fst.st_mode), fst.st_uid, fst.st_gid)
if mode == "mode":
return stat.S_IMODE(fst.st_mode)
if mode == "owner":
return fst.st_uid, fst.st_gid
def chownR(directory, uid, gid):
"""Recusive chown"""
def chownPaths(rootPath, listPath, uid, gid):
for chPath in listPath:
chownPath = path.join(rootPath, chPath)
statInfo = os.lstat(chownPath)[stat.ST_MODE]
if stat.S_ISLNK(statInfo):
os.lchown(chownPath, uid, gid)
else:
os.chown(chownPath, uid, gid)
for root, dirs, files in os.walk(directory):
# меняем владельца директории
os.chown(root, uid, gid)
# Меняем владельца директорий
chownPaths(root, dirs, uid, gid)
# Меняем владельца файлов
chownPaths(root, files, uid, gid)
return True
class proxy_type_file:
def __init__(self,flags):
self.flags = flags
def load(self):
pass
def setflags(self,flags):
self.flags = flags
def close(self):
pass
def _get_cmd_by_flags(self,flags):
"""
Получить команду для выполнения по флагам
"""
paramdict = {MAGIC_CONTINUE:"-k",
MAGIC_SYMLINK:"-L",
MAGIC_MIME_TYPE:"--mime-type",
MAGIC_MIME_ENCODING:"--mime-encoding",
MAGIC_COMPRESS:"-z"}
appendParam = map(lambda x:paramdict[x],
filter(lambda x:flags & x,
sorted(paramdict.keys())))
fileCmd = getProgPath('/usr/bin/file')
return [fileCmd,'-b']+appendParam
def file(self,filename):
if path.exists(filename):
processFile = \
process(*(self._get_cmd_by_flags(self.flags)+[filename]))
if processFile.success():
return processFile.read().rstrip()
return None
class typeFile:
"""Получение типа файла"""
def __init__(self, magic=MAGIC_MIME_ENCODING|MAGIC_MIME_TYPE):
if type_file is None:
self.magicObject = proxy_type_file(MAGIC_NONE)
else:
self.magicObject = type_file(MAGIC_NONE)
self.magicObject.load()
self.magicObject.setflags(magic)
def __del__(self):
"""Закрываем magic"""
self.magicObject.close()
def getMType(self, filename):
"""Информация о типе файла"""
ret = self.magicObject.file(filename)
# fix for kernel 3.7.7 (bad work samba)
if ret is None and self.magicObject.errno() == 5:
r,w = os.pipe()
devnull = os.open(os.devnull,os.O_WRONLY)
cat = subprocess.Popen(['/bin/cat',filename],stdout=w,
stderr=devnull,close_fds=True)
ret = self.magicObject.descriptor(r)
os.close(w)
os.close(devnull)
cat.wait()
return ret
def isBinary(self, filename):
"""является ли файл бинарным"""
mime = self.getMType(filename)
if mime.startswith("text"):
return False
else:
return True
class scanDirectory:
"""Класс для cканирования директории"""
def processingFile(self, pathname, prefix):
"""Обработка в случае файла"""
return True
def processingDirectory(self, pathname, prefix):
"""Обработка в случае директории если возвращаем None то пропуск дир."""
return True
def scanningDirectory(self, scanDir, skipFile=[], skipDir=[],
prefix=None, flagDir=False):
"""Сканирование и обработка шаблонов в директории scanDir"""
ret = True
if not prefix:
prefix = path.join(scanDir,"")[:-1]
if not flagDir:
# проверка корневой директории
retDir = self.processingDirectory(scanDir, scanDir)
if retDir is None:
return None
elif retDir is False:
return False
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
for absPath in sorted(listDirectory(scanDir,fullPath=True)):
relPath = absPath.split(prefix)[1]
stInfo = os.lstat(absPath)
statInfo = stInfo[stat.ST_MODE]
if stat.S_ISREG(statInfo):
# Обработка файла
if relPath in skipFile:
continue
if not self.processingFile(absPath, prefix):
return False
elif stat.S_ISDIR(statInfo):
# Обработка директории
if relPath in skipDir:
continue
retDir = self.processingDirectory(absPath, prefix)
if retDir is None:
continue
elif retDir is False:
return False
ret = self.scanningDirectory(absPath, skipFile,
skipDir, prefix, True)
if ret is False:
return False
return ret
class processProgress(process):
"""
Generator like process progress
"""
def __init__(self,command,*params,**kwarg):
process.__init__(self,command,*params,**kwarg)
self.readsize = kwarg.get("readsize",10)
self.delimeter = re.compile("\n")
self.init(**kwarg)
def init(self,*args,**kwarg):
pass
def processInit(self):
pass
def processEnd(self):
pass
def processString(self,strdata):
self.cacheresult.append(strdata)
return strdata
def processBuffer(self,buf):
pass
def progress(self):
try:
res = self.processInit()
if res != None: yield res
self._open()
if self.cacheresult is None:
self.cacheresult = []
self.buf = ""
fd = self.pipe.stdout.fileno()
fl = fcntl.fcntl(fd,fcntl.F_GETFL)
fcntl.fcntl(fd,fcntl.F_SETFL,fl | os.O_NONBLOCK)
hasData = True
while hasData or self.pipe.poll() is None:
hasData = False
try:
part = self.pipe.stdout.read(self.readsize)
if not part:
continue
except IOError as e:
# re-raise not "Resource temporary unavailable"
if e.errno != 11:
raise
continue
hasData = True
if self.buf:
self.buf += part
else:
self.buf = part
res = self.processBuffer(part)
if res:
yield res
while self.delimeter.search(self.buf):
strdata, self.buf = self.delimeter.split(self.buf,1)
res = self.processString(strdata)
if res:
yield res
res = self.processEnd()
if res != None: yield res
except KeyboardInterrupt:
self.pipe.kill()
raise
finally:
if self.cacheresult:
self.cacheresult = "\n".join(self.cacheresult)
else:
self.cacheresult = ""
def countFiles(dirpath,onefilesystem=True):
"""
Count files in specified dirpath
"""
num = 1
for dirpath,dirnames,filenames in os.walk(dirpath):
num += len(set(dirnames) | set(filenames))
if onefilesystem:
mountDirs = filter(lambda x:path.ismount(path.join(dirpath,x)),
dirnames)
for dirname in mountDirs:
dirnames.remove(dirname)
return num
def getFilesCount(directory):
"""Alias for compatibility"""
return countFiles(directory,onefilesystem=False)
def runOsCommand(cmd,in_str=None, env_dict=None):
"""Run system command
Параметры:
cmd внешняя программа
in_str данные передаваемые программе на страндартный вход.
env_dict словарь переменных окружения
Возвращает (код возврата, список stdout+stderr)
"""
pipe = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env_dict,
close_fds=True,
shell=True)
fout, fin, ferr = (pipe.stdout, pipe.stdin, pipe.stderr)
# если есть данные на вход, передать их
if in_str:
fin.write(in_str)
fin.close()
res = map(lambda x: x.rstrip(), fout.readlines())
fout.close()
res += map(lambda x: x.rstrip(), ferr.readlines())
ferr.close()
# Код возврата
retcode = pipe.wait()
return retcode, res
def copyDir(srcDir, destDir):
"""Копируем директорию srcDir в destDir
При копировании сохраняются владелец, группа, права
"""
def ignoreFile(pathname, names):
"""Игнорирование сокетов при копировании"""
ignore = []
for name in names:
if stat.S_ISSOCK(os.lstat(path.join(pathname, name))[stat.ST_MODE]):
ignore.append(name)
return ignore
copytree(srcDir, destDir, ignore=ignoreFile)
return True
def removeDir(rmDir):
"""Рекурсивное удаление директории"""
rmtree(rmDir)
return True
def getRunCommands(not_chroot=False):
"""List run program"""
def getCmd(procNum):
cmdLineFile = '/proc/%s/cmdline'%procNum
try:
if path.exists(cmdLineFile):
if not_chroot:
root_link = '/proc/%s/root'%procNum
if os.readlink(root_link) != "/":
return ""
return open(cmdLineFile,'r').read().strip()
except Exception as e:
pass
return ""
if not os.access('/proc',os.R_OK):
return []
return filter(None,
map(getCmd,
filter(lambda x:x.isdigit(),
listDirectory('/proc'))))
def isMount(pathname):
"""В случае монтирования директории выдает другой примонтированный путь"""
findPath = [path.abspath(pathname)]
if findPath[0].startswith('/dev'):
info = device.getUdevDeviceInfo(name=findPath[0])
if 'DM_VG_NAME' in info and 'DM_LV_NAME' in info:
lvmDeviceName = \
'/dev/mapper/{vg}-{lv}'.format(vg=info['DM_VG_NAME'],
lv=info['DM_LV_NAME'])
findPath.append(lvmDeviceName)
mtabFile = '/etc/mtab'
if not os.access(mtabFile,os.R_OK):
return ""
return filter(lambda x: x!=findPath,
reduce(lambda x,y: y,
ifilter(lambda x: any(p in x for p in findPath),
imap(lambda x: [x[0], x[1]],
imap(lambda x: x.split(" "),
open(mtabFile)))), [""]))[0]
def commonPath(*paths):
"""Return common path from list of paths"""
paths = map(lambda x:path.normpath(x).split('/'),paths)
res = map(lambda x:x[0],
filter(lambda x:filter(lambda y:x[0]==y,x[1:]),zip(*paths)))
return "/".join(res)
def childMounts(pathname):
"""Get all mount points which contain path"""
if pathname != "none":
absPath = path.abspath(pathname)
else:
absPath = pathname
mtabFile = '/etc/mtab'
if not os.access(mtabFile,os.R_OK):
return ""
return reduce(lambda x,y: x + [y],
filter(lambda x: commonPath(absPath,x[0])==absPath or \
commonPath(absPath,x[1])==absPath,
map(lambda x: [x[0], x[1]],
map(lambda x: x.split(" "),
open(mtabFile)))),
[])
def pathJoin(*paths):
"""Складывает пути, в отличии от os.path.join, складывает абсолютные пути"""
if len(paths)==1:
return paths[0]
return reduce(path.join,
filter(lambda x:x and x != "/",
map(lambda x: x.startswith("/") and x[1:] or x,
paths[1:])),paths[0])
def checkDigestFile(digestfile):
"""Check digest by digestfile"""
reEntry = re.compile(r"# (\S+) HASH\n(\S+) (\S+)",re.S)
result = []
for alg,hashdata,filename in \
reEntry.findall(open(digestfile,'r').read()):
if hasattr(hashlib,alg.lower()):
hashobj = getattr(hashlib,alg.lower())
filename = path.join(path.dirname(digestfile),filename)
if os.path.exists(filename):
digest = hashobj(open(filename,'r').read())
result.append((alg,
digest.hexdigest().upper() == hashdata.upper()))
return result
def listDirectory(directory,fullPath=False,onlyDir=False):
"""Get files from directory, if it exists"""
if not path.exists(directory):
return []
try:
if fullPath:
if onlyDir:
return filter(lambda x:path.isdir(x),
map(lambda x:path.join(directory,x),
os.listdir(directory)))
else:
return map(lambda x:path.join(directory,x),
os.listdir(directory))
else:
if onlyDir:
return filter(lambda x:path.isdir(path.join(directory,x)),
os.listdir(directory))
else:
return os.listdir(directory)
except OSError:
pass
return []
def makeDirectory(pathname):
"""Make directory and parent.
Return False on error"""
try:
parent = path.split(path.normpath(pathname))[0]
if not path.exists(parent):
makeDirectory(parent)
else:
if path.exists(pathname):
return True
os.mkdir(pathname)
return True
except Exception, e:
return False
def readLinesFile(filename):
"""Read file by line"""
try:
if path.exists(filename):
for line in open(filename,'r'):
yield line.rstrip('\n')
except (OSError,IOError):
pass
finally:
raise StopIteration
def readFile(filename,tailbyte=None):
"""
Прочитать целый файл или вернуть пустую строку.
tailbyte: прочитать только последнее указанное количество байт
"""
try:
if path.exists(filename):
with open(filename,'r') as f:
if tailbyte:
seeksize = max(0,os.stat(filename).st_size-tailbyte)
if seeksize:
f.seek(seeksize)
return f.read()
except (OSError,IOError):
pass
return ""
def writeFile(filename):
"""
Открыть файл на запись и создать необходимые каталоги
"""
dn = path.dirname(filename)
if not path.exists(dn):
os.makedirs(dn)
return open(filename,'w')
import common
class getProgPath:
"""Get full path of program or False"""
cache = {}
def __call__(self,progname):
baseprogname = path.basename(progname)
if baseprogname in self.cache:
return self.cache[baseprogname]
env = {"LANG":"C"}
env.update(os.environ.items() + [("PATH",common.getpathenv())] +\
env.items())
res = runOsCommand("which %s"%baseprogname,env_dict=env)
if path.isabs(progname) and path.exists(progname):
self.cache[baseprogname] = progname
return self.cache[baseprogname]
elif res[0] == 0:
self.cache[baseprogname] = res[1][0].strip()
return self.cache[baseprogname]
else:
return False
getProgPath = getProgPath()
def checkUtils(*utils):
"""Check utils, exit if it not found and return fullpath"""
retval = []
for util in utils:
utilPath = getProgPath(util)
if not utilPath:
raise FilesError(_("Command not found '%s'")%
path.basename(util))
retval.append(utilPath)
if len(retval) == 1:
return retval[0]
else:
return retval
def getCmdLineParam(paramName):
"""Get value of param /proc/cmdline. If param not found then empty.
"""
cmdLine = '/proc/cmdline'
paramName = "%s="%paramName
params = \
map(lambda x:x.partition('=')[2],
filter(lambda x:x.startswith(paramName),
readFile(cmdLine).split(' ')))
if params:
return params[-1]
else:
return ""
from device import getUUIDDict
def isFstabMount(pathname,mapDevUuid={},listFstab=[]):
"""Get mount point or device from fstab"""
def removeQuotes(s):
return s.replace('"','').replace("'","")
if pathname == "swap":
absPath = "swap"
else:
absPath = path.abspath(pathname)
if not mapDevUuid:
mapDevUuid.update(getUUIDDict())
# convert fstab to
# [['/dev/sda3', '/', '', 'reiserfs', 'noatime', '', '', '0', '2\n'],
# ['/dev/sda5', '/var/calculate', 'reiserfs', 'noatime', '0', '0\n']]
#if not listFstab:
if not listFstab:
listFstab.extend(
map(lambda x: [mapDevUuid.get(removeQuotes(x[0]),x[0]),
x[1] if x[2] != "swap" else "swap"],
filter(lambda x: len(x) >= 4,
map(lambda x: filter(lambda x: x,
x.replace('\t',' ').split(' ')),
filter(lambda x: not x.startswith('#') and x.strip(),
open("/etc/fstab"))))))
# get mount point or device or dir
return filter(lambda x: x!=absPath,
reduce(lambda x,y: y,
filter(lambda x: absPath in x and x[1] != "none",
listFstab),[""]))[0]
class SingletonParam(type):
def __init__(cls, name, bases, dict):
super(SingletonParam, cls).__init__(name, bases, dict)
cls.instance = {}
def __call__(cls,*args,**kw):
keyarg = args[0] if args else ""
if not keyarg in cls.instance:
cls.instance[keyarg] = \
super(SingletonParam, cls).__call__(*args, **kw)
return cls.instance[keyarg]
import device
class FStab(object):
"""Data reader for fstab"""
__metaclass__ = SingletonParam
fstab_file = '/etc/fstab'
NAME, DIR, TYPE, OPTS, FREQ, PASSNO = range(0,6)
def __init__(self,fstab_file=None,devs=[]):
if fstab_file:
self.fstab_file = fstab_file
self.cache = []
self.rotateCache = []
self.dictUUID = getUUIDDict(devs=devs)
self.rebuildCache()
def rebuildCache(self):
"""Rebuild cache from fstab file"""
def setlen(ar):
return ar[:6]+[""]*(6-len(ar))
self.cache = \
map(lambda x:setlen(map(lambda y:y.strip(),x.split())),
filter(lambda x:x.strip() and not x.lstrip().startswith("#"),
open(self.fstab_file,'r').read().split('\n')))
for data in self.cache:
convertDev = lambda x: path.realpath(x) if x.startswith('/') else x
data[0] = device.getUdevDeviceInfo(
name=convertDev(self.dictUUID.get(data[0],data[0]))
).get('DEVNAME',data[0])
data[1] = data[1] if data[2] != "swap" else "swap"
self.rotateCache = zip(*self.cache)
def getBy(self,what=DIR,where=NAME,_in=None,eq=None,
noteq=None,allentry=False):
"""Get data from fstab"""
if not eq is None:
filterfunc = lambda x: x[where] == eq
elif not _in is None:
filterfunc = lambda x: _in in x[where]
else:
filterfunc = lambda x: x[where] != noteq
res = map(lambda x:x[what],filter(filterfunc,self.cache))
if allentry:
return res
else:
return "" if not res else res[-1]
def getFields(self,*fields):
"""Get all data by specifie fields"""
return zip(*reduce(lambda x,y:x+[self.rotateCache[y]],fields,[]))
def isExists(self,what=DIR,eq=None,noteq=None):
"""Field with condition exist in fstab"""
if not eq is None:
filterfunc = lambda x: x[what] == eq
else:
filterfunc = lambda x: x[what] != noteq
return bool(filter(filterfunc,self.cache))
def tarLinks(rootpath,archpath,skip=[]):
"""
Поместить все симлинки в архив
"""
links = []
lenprefix = len(path.normpath(rootpath))+1
if path.exists(archpath):
os.unlink(archpath)
# create arch
tar = tarfile.open(archpath,"w:bz2")
# find links
if skip:
reSkip = re.compile("|".join(map(lambda x:x.replace("*",".*"),
skip))).search
else:
reSkip = lambda x:False
for link in ifilterfalse(reSkip,
find(rootpath,filetype="l",onefilesystem=True)):
ti = tar.gettarinfo(link)
ti.name = link[lenprefix:]
tar.addfile(ti)
links.append(link)
tar.close()
return links
def getch():
"""
Get char from keyboard
"""
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
def find(directory,onefilesystem=False,filetype=None,
fullpath=True, depth=None, downfilter=None):
"""
Поиск файлов в каталоге
"""
ldirectory = len(directory)
if downfilter or onefilesystem or depth:
_downfilter = lambda dp: (
(depth is None or dp[ldirectory:].count('/') < depth) and
(not downfilter or downfiler(dp)) and
(not onefilesystem or not path.ismount(dp)))
else:
_downfilter = None
if filetype:
def dirfilter(dp):
link = path.islink(dp)
return ("l" in filetype and link) or ("d" in filetype and not link)
_dirfilter = dirfilter
else:
_dirfilter = None
if fullpath or _dirfilter or _downfilter:
_dirfullpath = lambda root,fn: path.join(root,fn)
else:
_dirfullpath = lambda root,fn:fn
if filetype:
def filefilter(fp):
link = path.islink(fp)
return ("l" in filetype and link) or ("f" in filetype and not link)
_filefilter = filefilter
else:
_filefilter = None
if fullpath or _filefilter:
_filefullpath = lambda root,fn: path.join(root,fn)
else:
_filefullpath = lambda root,fn:fn
for root,directories,files in os.walk(directory):
for fn in files:
fp = _filefullpath(root,fn)
if not _filefilter or _filefilter(fp):
yield fp if fullpath else fn
for dn in directories[:]:
dp = _dirfullpath(root,dn)
if not _dirfilter or _dirfilter(dp):
yield dp if fullpath else dn
if _downfilter and not _downfilter(dp):
directories.remove(dn)
def copyWithPath(fn,dest,prefix=None):
"""
Копировать файл в dst с созданием каталогов
source: префикс исходного файла
dest: каталог для копирывания
fn: имя файла
"""
try:
if prefix:
destFile = pathJoin(dest,fn[len(prefix):])
else:
destFile = pathJoin(dest,path.basename(fn))
destDir = path.dirname(destFile)
if not path.exists(destDir):
os.makedirs(destDir)
copy2(fn,destFile)
except Exception as e:
raise FilesError(
_("Failed to copy '%(src)s' to '%(dst)s'")%
{'src':fn,
'dst':destFile})
def getLoopFromPath(directory):
"""
Получить loop, использующие файлы в данной директории
"""
losetup = getProgPath('losetup')
p = process(losetup,'-a')
rePattern = re.compile('(^\/dev\/loop[^:]+)[^(]+\(([^)]+)\).*')
return map(lambda x:x[0],
filter(lambda x:x[1].startswith(directory),
reSearch(rePattern,
p.readlines())))
def getMdRaidDevices():
"""
Получить словарь: какой mdraid какие использует устройства
"""
reMdInfo = re.compile('^(\w+)\s+:\s+active.*?raid\d+\s+(.*)')
return dict(map(lambda x:(x[0],map(lambda x:x.partition('[')[0],
x[1].split())),
reSearch(reMdInfo,readLinesFile('/proc/mdstat'))))
def sambaPasswordCheck(username,password,server,resource):
"""
Подключиться к указанному samba ресурсу сервера по логину паролю
"""
smbclient = getProgPath('/usr/sbin/smbclient')
if not smbclient:
raise FilesError(_("Command not found '%s'")%"smbclint")
p = process(smbclient,"-U",username,"//%s/%s"%(server,resource),
envdict={'PASSWD':password})
return p.success()
class PercentProgress(processProgress):
"""
Объект выдает прогресс, ища в выводе \d+%
Args:
part: количество прогрессов в программе
delimeter: разделители строк по умолчанию \n и \r
cachefilter: фильтр вывода программы (регулярная строка)
startpart: используется для вывода процентов прогрессбар
с определенного места (0 по умолчанию)
end: конечный прогрессбар (по умолчанию)
atty: для получения данных создается pty
"""
def init(self,*args,**kwargs):
self.rePerc = re.compile("(\d+)%",re.S)
self.part = kwargs.get("part",1)
if self.part < 1:
self.part = 1
self.add_offset = 100 / self.part
self.offset = 0 + kwargs.get("startpart",0)*self.add_offset
self.is_end = kwargs.get("end",True)
self.stderr = STDOUT
self.delimeter = re.compile("[%s]"%kwargs.get("delimeter","\n\r"))
self.cachedata = re.compile(kwargs.get("cachefilter",
"((?:\[31;01m\*|\[33;01m\*|error:|warning:|fatal:).*)"))
self.atty = kwargs.get("atty",False)
self.alldata = ""
def _open(self):
self.master,self.slave = None,None
if self.atty:
if not self.pipe:
self.master,self.slave = os.openpty()
self.pipe = Popen(self.command,
stdout=self.slave,
stderr=self.slave,
cwd=self.cwd,
close_fds=True,
env=self.envdict)
self.pipe.stdout = os.fdopen(self.master,'r')
else:
process._open(self)
def processInit(self):
self.percent = 0
self.showval = 0
if not self.offset:
return 0
def processEnd(self):
if not self.slave is None:
os.close(self.slave)
if self.is_end:
self.percent = 100
return 100
def processString(self, strdata):
self.alldata += strdata
match = self.rePerc.search(strdata)
resSearch = self.cachedata.search(strdata)
if resSearch:
self.cacheresult.append(
re.sub("\[31;01m\*|\[33;01m\*|\[.*?m",
"", resSearch.group(1)))
if match:
percent = int(match.group(1))
if percent < self.percent:
self.offset = self.offset + self.add_offset
percent = percent / self.part
if percent != self.percent:
self.percent = percent
showval = min(99,self.percent + self.offset)
if showval != self.showval:
self.showval = showval
return self.showval
def set_active_tty(ttynum):
"""
Установить активный терминал
"""
chvt = getProgPath("/usr/bin/chvt2")
if chvt:
os.system('chvt %d &>/dev/null' % ttynum)