|
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 | + from string import maketrans as _maketrans |
| 29 | +except: |
| 30 | + _maketrans = str.maketrans |
| 31 | + |
| 32 | +_sep2slash = _maketrans(os.path.sep,"/") |
| 33 | +_slash2sep = _maketrans("/",os.path.sep) |
| 34 | +_from_mswin = (lambda path: str.translate(path,_sep2slash)) if os.path.sep != '/' else (lambda x:x) |
| 35 | +_to_mswin = (lambda path: str.translate(path,_slash2sep)) if os.path.sep != '/' else (lambda x:x) |
| 36 | + |
12 | 37 | class CollectionManager(Manager):
|
13 | 38 |
|
| 39 | + def put_recursive (self, localpath, path, abort_if_not_empty = True, **put_options): |
| 40 | + c = self.sess.collections.create( path ) |
| 41 | + w = list(itertools.islice(c.walk(), 0, 2)) # dereference first 1 to 2 elements of the walk |
| 42 | + if abort_if_not_empty and (len(w) > 1 or len(w[0][-1]) > 0): |
| 43 | + raise RuntimeError('collection {path!r} exists and is non-empty'.format(**locals())) |
| 44 | + localpath = os.path.normpath(localpath) |
| 45 | + for my_dir,sub_dirs,sub_files in os.walk(localpath,topdown=True): |
| 46 | + dir_without_prefix = os.path.relpath( my_dir, localpath ) |
| 47 | + subcoll = self.sess.collections.create(path if dir_without_prefix == os.path.curdir |
| 48 | + else path + "/" + _from_mswin(dir_without_prefix)) |
| 49 | + for file_ in sub_files: |
| 50 | + self.sess.data_objects.put( os.path.join(my_dir,file_), subcoll.path + "/" + file_, **put_options) |
| 51 | + |
| 52 | + |
| 53 | + def get_recursive (self, path, localpath, abort_if_not_empty = True, **get_options): |
| 54 | + if os.path.isdir(localpath): |
| 55 | + w = list(itertools.islice(os.walk(localpath), 0, 2)) |
| 56 | + if abort_if_not_empty and (len(w) > 1 or len(w[0][-1]) > 0): |
| 57 | + raise RuntimeError('local directory {localpath!r} exists and is non-empty'.format(**locals())) |
| 58 | + def unprefix (path,prefix=''): |
| 59 | + return path if not path.startswith(prefix) else path[len(prefix):] |
| 60 | + c = self.get(path) |
| 61 | + # TODO ## For a visible percent-complete status: |
| 62 | + # # nbytes = sum(d.size for el in c.walk() for d in el[2]) |
| 63 | + # ## (Then use eg tqdm module to create progress-bar.) |
| 64 | + c_prefix = c.path + "/" |
| 65 | + for coll,sub_colls,sub_datas in c.walk(topdown=True): |
| 66 | + relative_collpath = unprefix (coll.path + "/", c_prefix) |
| 67 | + new_target_dir = os.path.join(localpath, _to_mswin(relative_collpath)) |
| 68 | + make_writable_dir_if_none_exists( new_target_dir ) |
| 69 | + for data in sub_datas: |
| 70 | + local_data_path = os.path.join(new_target_dir, data.name) |
| 71 | + self.sess.data_objects.get( data.path, local_data_path, **get_options ) |
| 72 | + |
| 73 | + |
14 | 74 | def get(self, path):
|
15 | 75 | query = self.sess.query(Collection).filter(Collection.name == path)
|
16 | 76 | try:
|
|
0 commit comments