Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/omero/plugins/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,8 @@ def __init__(this, name, help, wait=False):
Examples:
omero admin cleanse --dry-run /OMERO # Lists files that will be \
deleted
omero admin cleanse --dry-run --subdirectory Files /OMERO # List only those \
fies in /OMERO/Files which will be deleted
omero admin cleanse /OMERO # Actually delete them.
omero admin cleanse /volumes/data/OMERO # Delete from a standard \
location.
Expand All @@ -430,6 +432,15 @@ def __init__(this, name, help, wait=False):
help="omero.data.dir directory value e.g. /OMERO")
x.add_login_arguments()

cleanse.add_argument(
"--subdirectory", choices=("Pixels", "Files", "Thumbnails",
"ManagedRepository"),
help="Limit to a single subdirectory, e.g. Files")

cleanse.add_argument(
"-v", "--verbose", action="store_true",
help="Print more information when using --dry-run")

removepyramids.add_argument(
"--dry-run", action="store_true",
help="Print out which files would be deleted")
Expand Down Expand Up @@ -1960,7 +1971,8 @@ def cleanse(self, args):
self.check_access()
from omero.util.cleanse import cleanse
cleanse(data_dir=args.data_dir, client=self.ctx.conn(args),
dry_run=args.dry_run)
dry_run=args.dry_run, subdirectory=args.subdirectory,
verbose=args.verbose)

@admin_only(full_admin=False)
def log(self, args):
Expand Down
122 changes: 86 additions & 36 deletions src/omero/util/cleanse.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

from Glacier2 import PermissionDeniedException
from getopt import getopt, GetoptError
from omero.util import get_user
from omero.util import get_user, long_to_path
from math import ceil
from stat import ST_SIZE

Expand Down Expand Up @@ -67,6 +67,7 @@ def usage(error):
-u Administrator username to log in to OMERO with
-k Session key to log in to OMERO with
--dry-run Just prints out what would have been done
--subdirectory Limit search to a single directory, e.g. Files

Examples:
%s --dry-run -u root /OMERO
Expand All @@ -91,13 +92,28 @@ class Cleanser(object):
PYRAMID_LOCK = ".pyr_lock"
PYRAMID_TEMP = ".tmp"

def __init__(self, query_service, object_type):
def __init__(self, query_service, object_type, data_dir):
self.query_service = query_service
self.object_type = object_type
self.cleansed = list()
self.bytes_cleansed = 0
self.deferred_paths = list()
self.dry_run = False
self.verbose = False
self.data_dir = data_dir

def is_object_id(self, path):
file = os.path.basename(path)
try:
ofid = int(file)
expected_path = long_to_path(
ofid, os.path.join(self.data_dir, 'Files'))
if expected_path == path:
return True
except ValueError:
pass
return False


def cleanse(self, root):
"""
Expand All @@ -107,7 +123,13 @@ def cleanse(self, root):
for file in os.listdir(root):
path = os.path.join(root, file)
if os.path.isdir(path):
self.cleanse(path)
# Check if it's an OriginalFile ID
if path.startswith(os.path.join(self.data_dir, 'Files')) and \
self.is_object_id(path):
self.query_or_defer(path)
else:
# If it's not a candidate for deletion, recurse into it.
self.cleanse(path)
else:
self.query_or_defer(path)

Expand Down Expand Up @@ -161,20 +183,26 @@ def do_cleanse(self):
path = self.deferred_paths[i]
if object_id.val not in existing_ids:
if object_id.val == -1:
if self.dry_run:
if self.dry_run and self.verbose:
print(r" \_ %s (ignored/keep)" % path)
else:
size = os.stat(path)[ST_SIZE]
self.cleansed.append(path)
self.bytes_cleansed = size
if self.dry_run:
print(r" \_ %s (remove)" % path)
if os.path.isdir(path):
if self.dry_run:
print(f" \_ {path} (removedir)")
else:
print(f"No action taken for directory {path}")
else:
try:
os.unlink(path)
except OSError as e:
print(e)
elif self.dry_run:
if self.dry_run:
print(f" \_ {path} (remove)")
else:
try:
os.unlink(path)
except OSError as e:
print(e)
elif self.dry_run and self.verbose:
print(r" \_ %s (keep)" % path)
self.deferred_paths = list()

Expand Down Expand Up @@ -216,7 +244,23 @@ def initial_check(config_service, admin_service=None):
sys.exit(3)


def cleanse(data_dir, client, dry_run=False):
def cleanse_dir(data_dir, directory, dry_run, verbose, query_service):
full_path = os.path.join(data_dir, directory)
if not os.path.exists(full_path):
print("%s does not exist. Skipping..." % full_path)
return None
if dry_run:
print("Reconciling OMERO data directory...\n %s" % full_path)
object_type = SEARCH_DIRECTORIES[directory]
cleanser = Cleanser(query_service, object_type, data_dir)
cleanser.dry_run = dry_run
cleanser.verbose = verbose
cleanser.cleanse(full_path)
cleanser.finalize()
return cleanser

def cleanse(data_dir, client, dry_run=False, subdirectory=None,
verbose=False):
client.getImplicitContext().put(omero.constants.GROUP, '-1')

admin_service = client.sf.getAdminService()
Expand All @@ -225,30 +269,27 @@ def cleanse(data_dir, client, dry_run=False):

initial_check(config_service, admin_service)

try:
cleanser = ""
for directory in SEARCH_DIRECTORIES:
full_path = os.path.join(data_dir, directory)
if not os.path.exists(full_path):
print("%s does not exist. Skipping..." % full_path)
continue
if subdirectory is None or subdirectory != "ManagedRepository":
try:
cleanser = ""
if subdirectory is not None:
cleanser = cleanse_dir(
data_dir, subdirectory, dry_run, verbose, query_service)
else:
for directory in SEARCH_DIRECTORIES:
cleanser = cleanse_dir(
data_dir, directory, dry_run, verbose, query_service)
finally:
if dry_run:
print("Reconciling OMERO data directory...\n %s" % full_path)
object_type = SEARCH_DIRECTORIES[directory]
cleanser = Cleanser(query_service, object_type)
cleanser.dry_run = dry_run
cleanser.cleanse(full_path)
cleanser.finalize()
finally:
if dry_run:
print(cleanser)
print(cleanser)

# delete empty directories from the managed repositories
proxy, description = client.getManagedRepository(description=True)
if proxy:
root = description.path.val + description.name.val
print("Removing empty directories from...\n %s" % root)
delete_empty_dirs(proxy, root, client, dry_run)
if subdirectory is None or subdirectory == "ManagedRepository":
# delete empty directories from the managed repositories
proxy, description = client.getManagedRepository(description=True)
if proxy:
root = description.path.val + description.name.val
print("Removing empty directories from...\n %s" % root)
delete_empty_dirs(proxy, root, client, dry_run)


def delete_empty_dirs(repo, root, client, dry_run):
Expand Down Expand Up @@ -402,7 +443,8 @@ def main():
Default main() that performs OMERO data directory cleansing.
"""
try:
options, args = getopt(sys.argv[1:], "u:k:", ["dry-run"])
options, args = getopt(sys.argv[1:], "u:k:",
["dry-run", "subdirectory=", "verbose"])
except GetoptError as xxx_todo_changeme:
(msg, opt) = xxx_todo_changeme.args
usage(msg)
Expand All @@ -415,13 +457,19 @@ def main():
username = get_user("root")
session_key = None
dry_run = False
subdirectory = None
verbose = False
for option, argument in options:
if option == "-u":
username = argument
if option == "-k":
session_key = argument
if option == "--dry-run":
dry_run = True
if option == "--subdirectory":
subdirectory = argument
if option == "--verbose":
verbose = True

if session_key is None:
print("Username: %s" % username)
Expand All @@ -443,7 +491,9 @@ def main():
sys.exit(1)

try:
cleanse(data_dir, client, dry_run)
print(f'verbose is {verbose}')
cleanse(data_dir, client, dry_run, subdirectory=subdirectory,
verbose=verbose)
finally:
if session_key is None:
client.closeSession()
Expand Down
Loading