Skip to content
tools.py 4.26 KiB
Newer Older
Seblu's avatar
Seblu committed
# -*- python -*-
Seblu's avatar
Seblu committed
# -*- coding: utf-8 -*-
# Started 26/05/2011 by Seblu <seblu@seblu.net>

'''
InstallSystems Generic Tools Library
'''

import os
import hashlib
Seblu's avatar
Seblu committed
import shutil
import urllib2
from installsystems.tarball import Tarball
Seblu's avatar
Seblu committed

def md5sum(path=None, fileobj=None):
Seblu's avatar
Seblu committed
    '''
    Compute md5 of a file
    '''
    if path is None and fileobj is None:
        raise ValueError("No path or fileobj specified")
    if fileobj is None:
        fileobj = uopen(path)
Seblu's avatar
Seblu committed
    m = hashlib.md5()
    while True:
        buf = fileobj.read(1024 * m.block_size)
        if len(buf) == 0:
            break
        m.update(buf)
Seblu's avatar
Seblu committed
    return m.hexdigest()

Seblu's avatar
Seblu committed
def copyfileobj(sfile, dfile):
Seblu's avatar
Seblu committed
    '''
    Copy data from sfile to dfile computing length and md5 on the fly
Seblu's avatar
Seblu committed
    '''
Seblu's avatar
Seblu committed
    f_sum = hashlib.md5()
    f_len = 0
    while True:
        buf = sfile.read(1024 * f_sum.block_size)
        buf_len = len(buf)
        if buf_len == 0:
            break
        f_len += buf_len
        f_sum.update(buf)
Seblu's avatar
Seblu committed
        if dfile is not None:
            dfile.write(buf)
Seblu's avatar
Seblu committed
    return (f_len , f_sum.hexdigest())

def copy(source, destination, uid=None, gid=None, mode=None, timeout=None):
Seblu's avatar
Seblu committed
    '''
    Copy a source to destination. Take care of path type
    '''
    stype = pathtype(source)
    dtype = pathtype(destination)
    # ensure destination is not a directory
    if dtype == "file" and os.path.isdir(destination):
        destination = os.path.join(destination, os.path.basename(source))
    # trivial case
Seblu's avatar
Seblu committed
    if stype == dtype == "file":
        shutil.copy(source, destination)
    elif stype == "http" and dtype == "file":
        f_dest = open(destination, "w")
        f_source = urllib2.urlopen(source, timeout=timeout)
        f_dest.write(f_source.read())
Seblu's avatar
Seblu committed
    elif stype == "file" and dtype == "":
Seblu's avatar
Seblu committed
        raise NotImplementedError
    else:
        raise NotImplementedError
    # setting destination file rights
    if dtype == "file":
        chrights(destination, uid, gid, mode)
Seblu's avatar
Seblu committed

def mkdir(path, uid=None, gid=None, mode=None):
Seblu's avatar
Seblu committed
    '''
    Create a directory and set rights
    '''
    os.mkdir(path)
    chrights(path, uid, gid, mode)

Seblu's avatar
Seblu committed
def chrights(path, uid=None, gid=None, mode=None, mtime=None):
Seblu's avatar
Seblu committed
    '''
    Set rights on a file
    '''
    if uid is not None:
        os.chown(path, uid, -1)
    if gid is not None:
        os.chown(path, -1, gid)
    if mode is not None:
        os.chmod(path, mode)
Seblu's avatar
Seblu committed
    if mtime is not None:
        os.utime(path, (mtime, mtime))

def pathtype(path):
Seblu's avatar
Seblu committed
    '''
    Return path type. This is usefull to know what kind of path is given
    '''
Seblu's avatar
Seblu committed
    if path.startswith("http://") or path.startswith("https://"):
        return "http"
    if path.startswith("ftp://") or path.startswith("ftps://"):
        return "ftp"
Seblu's avatar
Seblu committed
    elif path.startswith("ssh://"):
        return "ssh"
Seblu's avatar
Seblu committed
    else:
Seblu's avatar
Seblu committed
        return "file"

Seblu's avatar
Seblu committed
def isfile(path):
    '''
    Return True if path is of type file
    '''
    return pathtype(path) == "file"

def abspath(path):
Seblu's avatar
Seblu committed
    '''
    Format a path to be absolute
    '''
    ptype = pathtype(path)
Seblu's avatar
Seblu committed
    if ptype in ("http", "ssh"):
        return path
    elif ptype == "file":
        if path.startswith("file://"):
Aurélien Dunand's avatar
Aurélien Dunand committed
            path = path[len("file://"):]
Seblu's avatar
Seblu committed
        return os.path.abspath(path)
    else:
        return None
Seblu's avatar
Seblu committed
def uopen(path, mode="rb"):
Seblu's avatar
Seblu committed
    '''
    Universal Open
    Create a file-like object to a file which can be remote
    '''
    ftype = pathtype(path)
    if ftype == "file":
Seblu's avatar
Seblu committed
        return open(path, mode)
    elif ftype == "http" or ftype == "ftp":
        return urllib2.urlopen(path)
    else:
        raise NotImplementedError
Seblu's avatar
Seblu committed

def getsize(path):
Seblu's avatar
Seblu committed
    '''
    Get size of a path. Recurse if directory
    '''
Seblu's avatar
Seblu committed
    total_sz = os.path.getsize(path)
    if os.path.isdir(path):
        for root, dirs, files in os.walk(path):
            for filename in dirs + files:
                filepath = os.path.join(root, filename)
                filestat = os.lstat(filepath)
                if stat.S_ISDIR(filestat.st_mode) or stat.S_ISREG(filestat.st_mode):
                    total_sz += filestat.st_size
    return total_sz

def human_size(num):
    '''
    Return human readable size
    '''
    for x in ['Bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']:
        if num < 1024.0:
            return "%3.1f%s" % (num, x)
        num /= 1024.0
    return "%3.1f%s" % (num, x)