diff --git a/ess/__init__.py b/ess/__init__.py index cbeec8d3078e5143e96fa6da95b328e37a1656b0..5d17eec92d95fa5d39a180f469df6a1751e9be4a 100644 --- a/ess/__init__.py +++ b/ess/__init__.py @@ -1,6 +1,16 @@ -__all__ = ["fieldmap", "installed", "lib_tw", "SP_Relativity", "TraceWin", "TTF"] -__version__ = "2.4.2" from . import TraceWin from . import installed from . import lib_tw from . import fieldmap +from .nextcloud import nextcloud + +__all__ = [ + "fieldmap", + "installed", + "lib_tw", + "SP_Relativity", + "TraceWin", + "TTF", + "nextcloud", +] +__version__ = "2.5.0" diff --git a/ess/nextcloud.py b/ess/nextcloud.py new file mode 100644 index 0000000000000000000000000000000000000000..782bb23724bd4270aed5f62d61130f08bf6082e0 --- /dev/null +++ b/ess/nextcloud.py @@ -0,0 +1,124 @@ +import os +import getpass +import webdav3.client as wc +import tempfile +import shutil + + +class nextcloud: + def _request_password(self, username): + self.password = getpass.getpass("Password for {}:".format(username)) + + def __init__(self, username=None): + self.server = "https://nextcloud.esss.lu.se" + self.username = username + while self.username is None: + for key in ["JUPYTERHUB_USER", "USER", "LOGNAME"]: + if key in os.environ: + self.username = os.environ[key] + self._request_password(self.username) + self.tmpfolder = tempfile.mkdtemp() + + def __del__(self): + shutil.rmtree(self.tmpfolder) + + def connect(self): + """ + Connect to the server. + + This must be called after a new class has been initialized. + """ + options = { + "webdav_hostname": self.server, + "webdav_login": self.username, + "webdav_password": self.password, + "webdav_root": "/remote.php/webdav", + } + self.client = wc.Client(options) + + def get_resource(self, filepath): + """ + Copy the file in filepath to a local temporary folder + + :param filepath: path to the file + :return: full path to the local copy of the file + """ + check = self.client.check(filepath) + if check: + folder_path = os.path.join(self.tmpfolder, os.path.dirname(filepath)) + if not os.path.exists(folder_path): + os.makedirs(folder_path) + local_filepath = os.path.join(folder_path, os.path.basename(filepath)) + self.client.download_sync(remote_path=filepath, local_path=local_filepath) + return local_filepath + + def get_filelist(self, filepath="."): + """ + Lists files in a folder + + :param filepath: path to list of files from + :return: list of files in filepath + """ + check = self.client.check(filepath) + if check: + return self.client.list(filepath) + else: + return [] + + def _globsearch(self, current, remainders): + """ + A recursive search through a list of paths that are expected to be a folder path. + Each folder/file may include regular expressions used in re.search() + + Start a call to this function by self._globsearch('', folders) + + :param current: The current file path + :param remainders: the remaining list of folders in the glob search + :return: A list of full paths to all matching files + """ + import re + + paths = [] + for i in range(len(remainders)): + folder = remainders[i] + if "*" not in folder: + current = os.path.join(current, folder) + else: + for path in self.client.list(current): + if re.search(folder, path): + if i + 1 == len(remainders): + paths.append(os.path.join(current, path)) + else: + new_current = os.path.join(current, path) + paths.extend( + self._globsearch(new_current, remainders[i + 1 :]) + ) + break + return paths + + def get_filelist_glob(self, filepath): + """ + Lists files in a path which can include * (may match multiple folders) + + :param filepath: glob file path to look for files in + :return: list of all files + """ + + # First we need to split in a list of each folder + folders = [] + while 1: + filepath, folder = os.path.split(filepath) + + if folder != "": + folders.append(folder) + else: + if filepath != "": + folders.append(filepath) + + break + + folders.reverse() + + all_paths = self._globsearch("", folders) + + return all_paths