diff --git a/navigator/components/NavWindow.js b/navigator/components/NavWindow.js index a9c290f..588a2a6 100644 --- a/navigator/components/NavWindow.js +++ b/navigator/components/NavWindow.js @@ -676,6 +676,25 @@ export class NavWindow { keepers.push(response) } proc.input(JSON.stringify(keepers) + "\n", true); + } else if (payload.hasOwnProperty("choices")) { + let choices = {}; + for (let choice of payload["choices"]) { + choices[choice[0]] = { + label: choice[1], + internal_name: choice[0], + type: "radio", + default: false + } + } + choices[payload["choices"][0][0]].default = true; + this.stop_load(); + let response = await this.modal_prompt.prompt(payload["message"], choices); + this.start_load(); + if (response === null) { + proc.input(JSON.stringify("abort") + "\n"); + return; + } + proc.input(JSON.stringify(response) + "\n", true); } else { var user_response = await this.modal_prompt.confirm(payload["message"]); proc.input(JSON.stringify(user_response) + "\n", true); diff --git a/navigator/scripts/paste.py3 b/navigator/scripts/paste.py3 index 77ac86e..1e0a886 100755 --- a/navigator/scripts/paste.py3 +++ b/navigator/scripts/paste.py3 @@ -1,20 +1,20 @@ #!/usr/bin/env python3 """ - Cockpit Navigator - A File System Browser for Cockpit. - Copyright (C) 2021 Josh Boudreau + Cockpit Navigator - A File System Browser for Cockpit. + Copyright (C) 2021 Josh Boudreau - This file is part of Cockpit Navigator. - Cockpit Navigator is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Cockpit Navigator is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Cockpit Navigator. If not, see . + This file is part of Cockpit Navigator. + Cockpit Navigator is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Cockpit Navigator is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Cockpit Navigator. If not, see . """ """ @@ -28,87 +28,97 @@ from optparse import OptionParser import json import subprocess -def prompt_user(message, wants_response, conflicts = None): - payload = { - "wants-response": wants_response, - "message": message - } - if conflicts != None: - payload["conflicts"] = conflicts - print(json.dumps(payload) + "\n") - if wants_response: - response = json.loads(input()) - if isinstance(response, str) and response == "abort": - sys.exit(0) - return response - return +def prompt_user(message, wants_response, conflicts = None, choices = None): + payload = { + "wants-response": wants_response, + "message": message + } + if conflicts != None: + payload["conflicts"] = conflicts + if choices != None: + payload["choices"] = choices + print(json.dumps(payload) + "\n") + if wants_response: + response = json.loads(input()) + if isinstance(response, str) and response == "abort": + sys.exit(0) + return response + return def split_paths_at_cwd(paths, cwd): - response = [] - for path in paths: - response.append(cwd + "/./" + os.path.relpath(path, cwd)) - return response + response = [] + for path in paths: + response.append(cwd + "/./" + os.path.relpath(path, cwd)) + return response def recursive_get_conflicts(input_array, cwd, dest): - conflicts = [] - non_conflicts = [] - for source in input_array: - if os.path.isdir(source): - child_nodes = os.listdir(source) - child_paths = [] - for node in child_nodes: - child_paths.append(source + "/" + node) - (more_conflicts, more_non_conflicts) = recursive_get_conflicts(child_paths, cwd, dest) - conflicts += more_conflicts - non_conflicts += more_non_conflicts - continue - dest_path = dest + "/" + os.path.relpath(source, cwd) - if os.path.exists(dest_path): - conflicts.append((source, dest_path)) - else: - non_conflicts.append(source) - return (conflicts, non_conflicts) + conflicts = [] + non_conflicts = [] + for source in input_array: + if os.path.isdir(source): + child_nodes = os.listdir(source) + child_paths = [] + for node in child_nodes: + child_paths.append(source + "/" + node) + (more_conflicts, more_non_conflicts) = recursive_get_conflicts(child_paths, cwd, dest) + conflicts += more_conflicts + non_conflicts += more_non_conflicts + continue + dest_path = dest + "/" + os.path.relpath(source, cwd) + if os.path.exists(dest_path): + conflicts.append((source, dest_path)) + else: + non_conflicts.append(source) + return (conflicts, non_conflicts) def filter_existing(args, cwd): - sources = args[:-1] - dest = args[-1] - (conflicts, non_conflicts) = recursive_get_conflicts(sources, cwd, dest) - if len(conflicts): - conflicts = prompt_user("Overwrite?", True, conflicts) - non_conflicts.extend(conflicts) - if not len(non_conflicts): - sys.exit(0) # exit if nothing to copy - filtered_args = [*split_paths_at_cwd(non_conflicts, cwd), dest] - return filtered_args + sources = args[:-1] + dest = args[-1] + (conflicts, non_conflicts) = recursive_get_conflicts(sources, cwd, dest) + if len(conflicts): + choice = prompt_user("Conflicts Found", True, choices=[("skip-conflicts", "Skip Conflicts"), ("select", "Overwrite Selectively"), ("overwrite", "Overwrite All")]) + if choice == "overwrite": + non_conflicts.extend(map(lambda x: x[0], conflicts)) + elif choice == "select": + conflicts = prompt_user("Overwrite?", True, conflicts) + non_conflicts.extend(conflicts) + elif choice == "skip-conflicts": + pass + else: # cancelled + sys.exit(0) + if not len(non_conflicts): + sys.exit(0) # exit if nothing to copy + filtered_args = [*split_paths_at_cwd(non_conflicts, cwd), dest] + return filtered_args def paste(cmd, args): - try: - child = subprocess.Popen( - [*cmd, *args], - stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True - ) - except Exception as e: - prompt_user(str(e), False) - sys.exit(1) - child.wait() - if child.returncode: - stdout, stderr = child.communicate() - prompt_user(stdout + stderr, False) - sys.exit(child.returncode) + try: + child = subprocess.Popen( + [*cmd, *args], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True + ) + except Exception as e: + prompt_user(str(e), False) + sys.exit(1) + child.wait() + if child.returncode: + stdout, stderr = child.communicate() + prompt_user(stdout + stderr, False) + sys.exit(child.returncode) def main(): - parser = OptionParser() - parser.add_option("-m", "--move", help="remove source files", action="store_true", dest="move", default=False) - (options, args) = parser.parse_args() - cwd = args[0] - filtered_args = filter_existing(args[1:], cwd) - if options.move: - paste(["rsync", "-aI", "--relative", "--remove-source-files"], filtered_args) - else: - paste(["rsync", "-aI", "--relative"], filtered_args) - sys.exit(0) - + parser = OptionParser() + parser.add_option("-m", "--move", help="remove source files", action="store_true", dest="move", default=False) + (options, args) = parser.parse_args() + cwd = args[0] + filtered_args = filter_existing(args[1:], cwd) + if options.move: + paste(["rsync", "-aI", "--relative", "--remove-source-files"], filtered_args) + else: + paste(["rsync", "-aI", "--relative"], filtered_args) + sys.exit(0) + if __name__ == "__main__": - main() \ No newline at end of file + main()