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
47 changes: 43 additions & 4 deletions powersimdata/data_access/data_access.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import glob
import operator
import os
import posixpath
Expand Down Expand Up @@ -46,15 +47,14 @@ def copy(self, src, dest, recursive=False, update=False):
command = CommandBuilder.copy(src, dest, recursive, update)
return self.execute_command(command)

def remove(self, target, recursive=False, force=False):
def remove(self, target, recursive=False, confirm=True):
"""Wrapper around rm command

:param str target: path to remove
:param bool recursive: delete directories recursively
:param bool force: remove without confirmation
:param bool confirm: prompt before executing command
"""
command = CommandBuilder.remove(target, recursive, force)
return self.execute_command(command)
raise NotImplementedError

def _exists(self, filepath):
"""Return whether the file exists
Expand Down Expand Up @@ -196,6 +196,26 @@ def makedir(self, relative_path):
target = os.path.join(self.root, relative_path)
os.makedirs(target, exist_ok=True)

def remove(self, target, recursive=False, confirm=True):
"""Remove target using rm semantics

:param str target: path to remove
:param bool recursive: delete directories recursively
:param bool confirm: prompt before executing command
"""
if confirm:
confirmed = input(f"Delete {target}? [y/n] (default is 'n')")
if confirmed.lower() != "y":
print("Operation cancelled.")
return
if recursive:
shutil.rmtree(target)
else:
files = [f for f in glob.glob(target) if os.path.isfile(f)]
for f in files:
os.remove(f)
print("--> Done!")

def execute_command(self, command):
"""Execute a command locally at the data access.

Expand Down Expand Up @@ -431,6 +451,25 @@ def makedir(self, relative_path):
if len(stderr.readlines()) != 0:
raise IOError("Failed to create %s on server" % full_path)

def remove(self, target, recursive=False, confirm=True):
"""Run rm command on server

:param str target: path to remove
:param bool recursive: delete directories recursively
:param bool confirm: prompt before executing command
:raises IOError: if command generated stderr
"""
command = CommandBuilder.remove(target, recursive)
if confirm:
confirmed = input(f"Execute '{command}'? [y/n] (default is 'n')")
if confirmed.lower() != "y":
print("Operation cancelled.")
return
_, _, stderr = self.execute_command(command)
if len(stderr.readlines()) != 0:
raise IOError(f"Failed to delete target={target} on server")
print("--> Done!")

def _exists(self, filepath):
"""Return whether the file exists

Expand Down
31 changes: 11 additions & 20 deletions powersimdata/scenario/delete.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import glob
import os
import posixpath

from powersimdata.data_access.data_access import LocalDataAccess
from powersimdata.scenario.state import State
from powersimdata.utility import server_setup

Expand Down Expand Up @@ -30,8 +30,11 @@ def print_scenario_info(self):
except AttributeError:
print("Scenario has been deleted")

def delete_scenario(self):
"""Deletes scenario on server."""
def delete_scenario(self, confirm=True):
"""Deletes scenario on server.

:param bool confirm: prompt before each batch
"""

# Delete entry in scenario list
scenario_id = self._scenario_info["id"]
Expand All @@ -40,36 +43,24 @@ def delete_scenario(self):

wildcard = f"{scenario_id}_*"

# Delete links to base profiles on server
print("--> Deleting scenario input data on server")
target = posixpath.join(self.path_config.input_dir(), wildcard)
_, _, stderr = self._data_access.remove(target, recursive=False, force=True)
if len(stderr.readlines()) != 0:
raise IOError("Failed to delete scenario input data on server")
self._data_access.remove(target, recursive=False, confirm=confirm)

# Delete output profiles
print("--> Deleting scenario output data on server")
target = posixpath.join(self.path_config.output_dir(), wildcard)
_, _, stderr = self._data_access.remove(target, recursive=False, force=True)
if len(stderr.readlines()) != 0:
raise IOError("Failed to delete scenario output data on server")
self._data_access.remove(target, recursive=False, confirm=confirm)

# Delete temporary folder enclosing simulation inputs
print("--> Deleting temporary folder on server")
tmp_dir = posixpath.join(
self.path_config.execute_dir(), f"scenario_{scenario_id}"
)
_, _, stderr = self._data_access.remove(tmp_dir, recursive=True, force=True)
if len(stderr.readlines()) != 0:
raise IOError("Failed to delete temporary folder on server")
self._data_access.remove(tmp_dir, recursive=True, confirm=confirm)

# Delete local files
print("--> Deleting input and output data on local machine")
local_file = glob.glob(
os.path.join(server_setup.LOCAL_DIR, "data", "**", wildcard)
)
for f in local_file:
os.remove(f)
target = os.path.join(server_setup.LOCAL_DIR, "data", "**", wildcard)
LocalDataAccess().remove(target, recursive=False, confirm=confirm)

# Delete attributes
self._clean()
Expand Down
34 changes: 19 additions & 15 deletions powersimdata/scenario/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ def print_scenario_info(self):
for key, val in self._scenario_info.items():
print("%s: %s" % (key, val))

def move_scenario(self, target="disk"):
def move_scenario(self, target="disk", confirm=True):
"""Move scenario.

:param str target: optional argument specifying the backup system.
:param bool confirm: prompt before deleting each batch of files
Comment thread
rouille marked this conversation as resolved.
:raises TypeError: if target is not a str
:raises ValueError: if target is unknown (only "disk" is supported)
"""
if not isinstance(target, str):
raise TypeError("string is expected for optional argument target")
Expand All @@ -38,9 +41,9 @@ def move_scenario(self, target="disk"):

backup = BackUpDisk(self._data_access, self._scenario_info)

backup.move_input_data()
backup.move_output_data()
backup.move_temporary_folder()
backup.move_input_data(confirm=confirm)
backup.move_output_data(confirm=confirm)
backup.move_temporary_folder(confirm=confirm)

sid = self._scenario_info["id"]
self._execute_list_manager.set_status(sid, "moved")
Expand All @@ -58,7 +61,7 @@ class BackUpDisk(object):

:param powersimdata.data_access.data_access.DataAccess data_access:
data access object.
:param dict scenario: scenario information.
:param dict scenario_info: scenario information.
"""

def __init__(self, data_access, scenario_info):
Expand All @@ -67,36 +70,37 @@ def __init__(self, data_access, scenario_info):
self._scenario_info = scenario_info
Comment thread
rouille marked this conversation as resolved.
self.backup_config = server_setup.PathConfig(server_setup.BACKUP_DATA_ROOT_DIR)
self.server_config = server_setup.PathConfig(server_setup.DATA_ROOT_DIR)
self.scenario_id = self._scenario_info["id"]
self.wildcard = f"{self.scenario_id}_*"

def move_input_data(self):
def move_input_data(self, confirm=True):
"""Moves input data."""
print("--> Moving scenario input data to backup disk")
source = posixpath.join(
self.server_config.input_dir(),
self._scenario_info["id"] + "_*",
self.wildcard,
)
target = self.backup_config.input_dir()
self._data_access.copy(source, target, update=True)
self._data_access.remove(source, recursive=True, force=True)
self._data_access.remove(source, recursive=False, confirm=confirm)

def move_output_data(self):
def move_output_data(self, confirm=True):
"""Moves output data"""
print("--> Moving scenario output data to backup disk")
source = posixpath.join(
self.server_config.output_dir(),
self._scenario_info["id"] + "_*",
self.wildcard,
)
target = self.backup_config.output_dir()
self._data_access.copy(source, target, update=True)
self._data_access.remove(source, recursive=True, force=True)
self._data_access.remove(source, recursive=False, confirm=confirm)

def move_temporary_folder(self):
def move_temporary_folder(self, confirm=True):
"""Moves temporary folder."""
print("--> Moving temporary folder to backup disk")
source = posixpath.join(
self.server_config.execute_dir(),
"scenario_" + self._scenario_info["id"],
self.server_config.execute_dir(), "scenario_" + self.scenario_id
)
target = self.backup_config.execute_dir()
self._data_access.copy(source, target, recursive=True, update=True)
self._data_access.remove(source, recursive=True, force=True)
self._data_access.remove(source, recursive=True, confirm=confirm)
12 changes: 4 additions & 8 deletions powersimdata/utility/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,15 @@ def copy(src, dest, recursive=False, update=False):
return fr"\cp {flags} {src} {dest}"

@staticmethod
def remove(target, recursive=False, force=False):
def remove(target, recursive=False):
"""Builds a rm command with some options

:param str target: the path or file to be removed
:param bool recursive: whether to pass -r option
:param bool force: whether to pass -f option
"""
r_flag = "r" if recursive else ""
f_flag = "f" if force else ""
if recursive or force:
flags = f"-{r_flag}{f_flag}"
return f"rm {flags} {target}"
return f"rm {target}"
if recursive:
return f"rm -rf {target}"
return f"rm -f {target}"


class MemoryCache:
Expand Down
8 changes: 2 additions & 6 deletions powersimdata/utility/tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,10 @@ def test_copy_command():


def test_remove_command():
expected = "rm target"
expected = "rm -f target"
command = CommandBuilder.remove("target")
assert expected == command

expected = "rm -r target"
command = CommandBuilder.remove("target", recursive=True)
assert expected == command

expected = "rm -rf target"
command = CommandBuilder.remove("target", recursive=True, force=True)
command = CommandBuilder.remove("target", recursive=True)
assert expected == command