| 
1 | 1 | from __future__ import absolute_import  | 
 | 2 | +import os  | 
 | 3 | +import stat  | 
 | 4 | +import itertools  | 
2 | 5 | from irods.models import Collection  | 
3 | 6 | from irods.manager import Manager  | 
4 | 7 | from irods.message import iRODSMessage, CollectionRequest, FileOpenRequest, ObjCopyRequest, StringStringMap  | 
 | 
9 | 12 | import irods.keywords as kw  | 
10 | 13 | 
 
  | 
11 | 14 | 
 
  | 
 | 15 | +class GetPathCreationError ( RuntimeError ):  | 
 | 16 | +    """Error denoting the failure to create a new directory for writing.  | 
 | 17 | +    """  | 
 | 18 | + | 
 | 19 | +def make_writable_dir_if_none_exists( path ):  | 
 | 20 | +    if not os.path.exists(path):  | 
 | 21 | +        os.mkdir(path)  | 
 | 22 | +    if os.path.isdir( path ):  | 
 | 23 | +        os.chmod(path, os.stat(path).st_mode | stat.S_IWUSR)  | 
 | 24 | +    if not os.path.isdir( path ) or not os.access( path, os.W_OK ):  | 
 | 25 | +        raise GetPathCreationError( '{!r} not a writable directory'.format(path) )  | 
 | 26 | + | 
 | 27 | +try:  | 
 | 28 | +    # Python 2 only  | 
 | 29 | +    from string import maketrans as _maketrans  | 
 | 30 | +except:  | 
 | 31 | +    _maketrans = str.maketrans  | 
 | 32 | + | 
 | 33 | +_sep2slash = _maketrans(os.path.sep,"/")  | 
 | 34 | +_slash2sep = _maketrans("/",os.path.sep)  | 
 | 35 | +_from_mswin = (lambda path: str.translate(path,_sep2slash)) if os.path.sep != '/' else (lambda x:x)  | 
 | 36 | +_to_mswin =   (lambda path: str.translate(path,_slash2sep)) if os.path.sep != '/' else (lambda x:x)  | 
 | 37 | + | 
12 | 38 | class CollectionManager(Manager):  | 
13 | 39 | 
 
  | 
 | 40 | +    def put_recursive (self, localpath, path, abort_if_not_empty = True, **put_options):  | 
 | 41 | +        c = self.sess.collections.create( path )  | 
 | 42 | +        w = list(itertools.islice(c.walk(), 0, 2))  # dereference first 1 to 2 elements of the walk  | 
 | 43 | +        if abort_if_not_empty and (len(w) > 1 or len(w[0][-1]) > 0):  | 
 | 44 | +            raise RuntimeError('collection {path!r} exists and is non-empty'.format(**locals()))  | 
 | 45 | +        localpath = os.path.normpath(localpath)  | 
 | 46 | +        for my_dir,_,sub_files in os.walk(localpath,topdown=True):  | 
 | 47 | +            dir_without_prefix = os.path.relpath( my_dir, localpath )  | 
 | 48 | +            subcoll = self.sess.collections.create(path if dir_without_prefix == os.path.curdir  | 
 | 49 | +                                                        else path + "/" + _from_mswin(dir_without_prefix))  | 
 | 50 | +            for file_ in sub_files:  | 
 | 51 | +                self.sess.data_objects.put( os.path.join(my_dir,file_), subcoll.path + "/" + file_, **put_options)  | 
 | 52 | + | 
 | 53 | + | 
 | 54 | +    def get_recursive (self, path, localpath, abort_if_not_empty = True, **get_options):  | 
 | 55 | +        if os.path.isdir(localpath):  | 
 | 56 | +            w = list(itertools.islice(os.walk(localpath), 0, 2))  | 
 | 57 | +            if abort_if_not_empty and (len(w) > 1 or len(w[0][-1]) > 0):  | 
 | 58 | +                raise RuntimeError('local directory {localpath!r} exists and is non-empty'.format(**locals()))  | 
 | 59 | +        def unprefix (path,prefix=''):  | 
 | 60 | +            return path if not path.startswith(prefix) else path[len(prefix):]  | 
 | 61 | +        c = self.get(path)  | 
 | 62 | +        # TODO ## For a visible percent-complete status:  | 
 | 63 | +        #      #  nbytes = sum(d.size for el in c.walk() for d in el[2])  | 
 | 64 | +        #      ## (Then use eg tqdm module to create progress-bar.)  | 
 | 65 | +        c_prefix = c.path + "/"  | 
 | 66 | +        for coll,_,sub_datas in c.walk(topdown=True):  | 
 | 67 | +            relative_collpath = unprefix (coll.path + "/", c_prefix)  | 
 | 68 | +            new_target_dir = os.path.join(localpath, _to_mswin(relative_collpath))  | 
 | 69 | +            make_writable_dir_if_none_exists( new_target_dir )  | 
 | 70 | +            for data in sub_datas:  | 
 | 71 | +                local_data_path = os.path.join(new_target_dir, data.name)  | 
 | 72 | +                self.sess.data_objects.get( data.path, local_data_path, **get_options )  | 
 | 73 | + | 
 | 74 | + | 
14 | 75 |     def get(self, path):  | 
15 | 76 |         query = self.sess.query(Collection).filter(Collection.name == path)  | 
16 | 77 |         try:  | 
 | 
0 commit comments