import os
import getpass
import webdav3.client as wc
import tempfile
import shutil
[docs]class nextcloud:
"""
Class to simplify the connection to the ESS Nextcloud instance
The class use webdav to connect, and transfers files to a temporary
folder which is deleted on exit.
Authors:
- Yngve Levinsen
- Emanuele Laface (original idea)
"""
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)
[docs] 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)
[docs] def get_resource(self, filepath):
"""
Copy the file in filepath to a local temporary folder
Parameters
----------
filepath:
path to the file
returns
-------
str
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
[docs] def get_filelist(self, filepath="."):
"""
Lists files in a folder
Parameters
----------
filepath: str
path to list of files from
returns
-------
list
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)
Parameters
----------
current: str
The current file path
remainders: list
The remaining list of folders in the glob search
Returns
-------
list
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
[docs] def get_filelist_glob(self, filepath):
"""
Lists files in a path which can include * (may match multiple folders)
Parameters
----------
filepath: str
glob file path to look for files in
Returns
-------
list
list of all files that match the pattern
"""
# 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