class DUPLICITY_RESTORE

(source code)

description

Restore files from a backup made using the duplicity utility and configured from a file in Pyxis format. See class DUPLICITY_CONFIG for details.

note
	description: "[
		Restore files from a backup made using the [http://duplicity.nongnu.org/ duplicity] utility
		and configured from a file in Pyxis format. See class ${DUPLICITY_CONFIG} for details.
	]"

	author: "Finnian Reilly"
	copyright: "Copyright (c) 2001-2022 Finnian Reilly"
	contact: "finnian at eiffel hyphen loop dot com"

	license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
	date: "2024-09-22 16:42:52 GMT (Sunday 22nd September 2024)"
	revision: "36"

class
	DUPLICITY_RESTORE

inherit
	DUPLICITY_CONFIG
		rename
			backup_dir as backup_root_dir
		redefine
			make_default
		end

	EL_APPLICATION_COMMAND
		redefine
			description
		end

	EL_STRING_GENERAL_ROUTINES

	DUPLICITY_CONSTANTS

	EL_CHARACTER_8_CONSTANTS

create
	make

feature {NONE} -- Initialization

	make_default
		do
			Precursor
			create backup_dir
		end

feature -- Constants

	Description: STRING = "Restore files from a duplicity backup"

feature -- Basic operations

	 execute
		do
			if restore_dir.is_empty then
				lio.put_labeled_string ("ERROR", "No restore directory specified in configuration")
				lio.put_new_line
			else
				lio.put_labeled_string ("Restore", target_dir.base)
				lio.put_new_line_x2
				create backup_dir.make_from_dir_path (backup_root_dir #+ target_dir_base)
				new_shell.run_command_loop
			end
		end

feature {NONE} -- Implementation

	year_string (date_string: ZSTRING): ZSTRING
		local
			index: INTEGER
		do
			index := date_string.last_index_of (' ', date_string.count)
			if index > 0 then
				Result := date_string.substring_end (index + 1)
			else
				create Result.make_filled ('0', 4)
			end
		end

	restore_date (a_time: DATE_TIME)
		local
			cmd: DUPLICITY_LISTING_OS_CMD; restore_cmd: DUPLICITY_RESTORE_ALL_OS_CMD
			path_list: EL_FILE_PATH_LIST; input: EL_USER_INPUT_VALUE [INTEGER]
			i: INTEGER; integer: EL_INTEGER_MATH; padding_format: STRING
		do
			lio.put_line ("(%"library/%" to search for directory library)")
			create cmd.make (a_time, backup_dir, User_input.line ("Enter search string"))
			lio.put_new_line
			create path_list.make (cmd.path_list.count)
			path_list.extend (target_dir_base)
			across cmd.path_list as path loop
				path_list.extend (path.item)
			end
			padding_format := char ('9') * integer.digit_count (path_list.count)
			across path_list as path loop
				lio.put_index_labeled_string (path, padding_format, path.item)
				lio.put_new_line
			end
			lio.put_new_line
			lio.put_line (User_input.Esc_to_quit)
			create input.make_valid ("Enter a file option", "No such option number", agent (1 |..| path_list.count).has)
			i := input.value

			if input.escape_pressed then
				do_nothing -- exit
			else
				if not encryption_key.is_empty and then not attached Execution_environment.item (Var_passphrase) then
					Execution_environment.put (User_input.line ("Enter passphrase"), Var_passphrase)
					lio.put_new_line
				end
				if attached path_list [i] as file_path then
					if i = 1 then
						create restore_cmd.make (Current, a_time, file_path)
					else
						create {DUPLICITY_RESTORE_FILE_OS_CMD} restore_cmd.make (Current, a_time, file_path)
					end
				end
				restore_cmd.execute
			end
		end

feature {NONE} -- Factory

	new_date_time (str: ZSTRING): DATE_TIME
		-- DATE_TIME formatting is broken so we need to do time and date separately
		local
			parts: EL_ZSTRING_LIST; time: TIME; l_date: DATE
		do
			create parts.make_word_split (str.as_canonically_spaced)
			create time.make_from_string (parts.i_th (3), Format.time)
			parts [3] := parts [4]
			parts.finish
			parts.remove
			create l_date.make_from_string (parts.joined ('-'), Format.date)
			create Result.make_by_date_time (l_date, time)
		end

	new_shell: EL_COMMAND_SHELL
		local
			collection: DUPLICITY_COLLECTION_STATUS_OS_CMD
			year_group_table: EL_FUNCTION_GROUPED_SET_TABLE [ZSTRING, ZSTRING]
			item_table: EL_PROCEDURE_TABLE [ZSTRING]
			backup_shell: like new_backup_shell
		do
			create collection.make (backup_dir)
			create year_group_table.make_from_list (agent year_string, collection.backup_list)
			inspect year_group_table.count
				when 0, 1 then
					Result := new_backup_shell (collection.backup_list)
			else
				create item_table.make (year_group_table.count)
				across year_group_table as table loop
					backup_shell := new_backup_shell (table.item)
					item_table [table.key] := agent backup_shell.run_command_loop
				end
				create Result.make ("BACKUPS BY YEAR", item_table, 10)
			end
		end

	new_backup_shell (date_list: LIST [ZSTRING]): EL_COMMAND_SHELL
		local
			item_table: EL_PROCEDURE_TABLE [ZSTRING]; year: ZSTRING
		do
			create item_table.make (date_list.count)
			year := if date_list.is_empty then ZSTRING ("0000") else year_string (date_list.first) end
			across date_list as list loop
				if list.is_last then
					item_table [list.item] := agent restore_date (Time_now)
				else
					item_table [list.item] := agent restore_date (new_date_time (list.item))
				end
			end
			create Result.make ("BACKUPS for " + year, item_table, 30)
		end

feature {DUPLICITY_RESTORE_ALL_OS_CMD} -- Internal attributes

	backup_dir: EL_DIR_URI_PATH

	pass_phrase: ZSTRING

feature {NONE} -- Constants

	Format: TUPLE [date, time: STRING]
		once
			create Result
			Tuple.fill (Result, "mmm-[0]dd-yyyy, [0]hh24:[0]mi:[0]ss")
		end

	Var_passphrase: STRING
		once
			Result := "PASSPHRASE"
		end

end