# # Copyright (c) 2013-2022 CERN # # Copyright (c) 2012-2013 Members of the EMI Collaboration # See http://www.eu-emi.eu/partners for details on the copyright # holders. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #from __future__ import absolute_import # not available in python 2.4 from __future__ import division import sys import stat import errno import gfal2 from gfal2_util import base class CommandRm(base.CommandBase): def __init__(self): super(CommandRm, self).__init__() self.return_code = 0 @base.arg("-r", "-R", "--recursive", action='store_true', help="remove directories and their contents recursively") @base.arg("--dry-run", action='store_true', help="do not perform any actual change, just print what would happen") @base.arg("--just-delete", action='store_true', help="do not perform any check on the file, this is needed for HTTP signed URLs") @base.arg("--from-file", type=str, default=None, help="read surls from a file") @base.arg("--bulk", action='store_true', default=False, help="use bulk deletion") @base.arg("file", action='store', nargs='*', type=base.surl, help="uri(s) of the file(s) to be deleted") def execute_rm(self): """ Removes files or directories """ if self.params.from_file and self.params.file: sys.stderr.write("--from-file and positional arguments can not be used at the same time\n") return errno.EINVAL if self.params.bulk and self.params.recursive: sys.stderr.write("--bulk and --recursive can not be used at the same time\n") return errno.EINVAL if self.params.file: files = self.params.file elif self.params.from_file: files = [line.strip() for line in open(self.params.from_file, 'r').readlines()] files = [f for f in files if len(f) > 0] else: sys.stderr.write("Missing surl\n") return errno.EINVAL if self.params.bulk: self._do_bulk(files) else: for f in files: self._do_rm(f) return self.return_code def _do_rm(self, surl): """ Perform the action, either removing or just informing """ if not self.params.just_delete: try: st = self.context.stat(surl) except gfal2.GError: e = sys.exc_info()[1] self._propagate_error_code(e.code) if e.code == errno.ENOENT: print("%s\tMISSING" % surl) return else: print("%s\tFAILED" % surl) raise if stat.S_ISDIR(st.st_mode): self._do_rmdir(surl) return if self.params.dry_run: print("%s\tSKIP" % surl) return try: self.context.unlink(surl) print("%s\tDELETED" % surl) except gfal2.GError: e = sys.exc_info()[1] self._propagate_error_code(e.code) if e.code == errno.ENOENT: print("%s\tMISSING" % surl) return else: print("%s\tFAILED" % surl) raise def _do_rmdir(self, surl): """ Remove a directory recursively """ if not self.params.recursive: raise gfal2.GError("Can not remove %s, is a directory" % surl, errno.EISDIR) # Content base_dir = surl if base_dir[-1] != '/': base_dir += '/' contents = self.context.listdir(surl) for c in contents: if c in ['.', '..']: continue self._do_rm(base_dir + c) # Rmdir self if self.params.dry_run: print("%s\tSKIP DIR" % surl) else: try: self.context.rmdir(surl) print("%s\tRMDIR" % surl) except gfal2.GError: e = sys.exc_info()[1] self._propagate_error_code(e.code) if e.code == errno.ENOENT: print("%s\tMISSING" % surl) else: print("%s\tFAILED" % surl) raise def _do_bulk(self, surls): """ Do a bulk deletion """ if self.params.dry_run: print("\tBULK DELETION") return errors = self.context.unlink(surls) for error, surl in zip(errors, surls): if error is None: print("%s\tDELETED" % surl) else: print("%s\tFAILED: %s" % (surl, error)) self._propagate_error_code(error.code) def _propagate_error_code(self, error_code): """ Propagate the error code if the return code is empty """ if self.return_code == 0: self.return_code = error_code