class LIBRARY_MIGRATION_COMMAND

(source code)

description

Tool to migrate librares to newer compiler version by copying classes one by one to new library structure starting with classes that do not depend on other classes within the library

note
	description: "[
		Tool to migrate librares to newer compiler version by copying classes one by one to new library structure
		starting with classes that do not depend on other classes within the library
	]"

	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-20 9:16:01 GMT (Friday 20th September 2024)"
	revision: "31"

class
	LIBRARY_MIGRATION_COMMAND

inherit
	SOURCE_MANIFEST_COMMAND
		rename
			make as make_command
		redefine
			execute, read_manifest_files
		end

	EL_MODULE_DIRECTORY; EL_MODULE_FILE; EL_MODULE_OS; EL_MODULE_USER_INPUT

	EL_FILE_OPEN_ROUTINES

create
	make

feature {EL_COMMAND_CLIENT} -- Initialization

	make (manifest_path: FILE_PATH; a_home_dir: DIR_PATH; suffix: STRING)
		require
			home_dir_exists: a_home_dir.exists
			suffix_not_empty: suffix.count > 0
		do
			home_dir := a_home_dir; destination_dir := a_home_dir.parent #+ (a_home_dir.base + suffix)
			make_command (manifest_path)
			create class_list.make (0)
			create library_set.make_equal (0)
			create class_path_table.make (0)
		end

feature -- Constants

	Description: STRING = "Move library contents class by class in order of lowest dependency count"

feature -- Basic operations

	execute
		local
			reference_set, removal_set: EL_HASH_SET [STRING]
			i: INTEGER; destination_path, source_path: FILE_PATH
			name_array: ARRAY [STRING]
		do
			Precursor
			bind_circular

			create removal_set.make_equal (0)
			from until class_list.is_empty or i > 10 loop
				i := i + 1
				print_iteration (i)
				removal_set.wipe_out
				across class_list as list loop
					reference_set := list.item.class_reference_set
					reference_set.intersect (library_set)
					print_class_heading (list.item.name)
					if reference_set.count = 0 then
						print_line ("No dependencies")
						if attached list.item.circular_dependent as dependent then
							name_array := << list.item.name, dependent.name >>
						else
							name_array := << list.item.name >>
						end
						prompt_user (name_array)
						across name_array as name loop
							removal_set.put (name.item)
							source_path := class_path_table [name.item]
							destination_path := destination_dir + source_path.relative_path (home_dir)
							File_system.make_directory (destination_path.parent)
							OS.copy_file (source_path, destination_path)
						end
					else
						across reference_set as set loop
							print_line (set.item)
						end
					end
					print_tab_left
				end
				class_list.prune_those (agent in_set (?, removal_set))
				library_set.subtract (removal_set)
			end
		end

feature {NONE} -- Implementation

	bind_circular
		local
			circular_set: EL_HASH_SET [STRING]
		do
			create circular_set.make_equal (10)
			across class_list as list loop
				if not circular_set.has (list.item.name) then
					across class_list as l_class until attached list.item.circular_dependent loop
						if l_class.item /= list.item then
							list.item.try_bind (l_class.item)
							if attached list.item.circular_dependent as dependent then
								circular_set.put (dependent.name)
							end
						end
					end
				end
			end
			class_list.prune_those (agent in_set (?, circular_set))
			library_set.subtract (circular_set)
		end

	do_with_file (source_path: FILE_PATH)
		local
			name: STRING
		do
			if not source_path.has_step (Excluded_imp_step) then
				class_list.extend (create {LIBRARY_CLASS}.make (source_path))
				name := source_path.base_name; name.to_upper
				class_path_table.extend (source_path, name)
				library_set.put (name)
			end
		end

	in_set (a_class: LIBRARY_CLASS; removal_set: EL_HASH_SET [STRING]): BOOLEAN
		do
			Result := removal_set.has (a_class.name)
		end

	print_iteration (i: INTEGER)
		do
		end

	print_class_heading (name: STRING)
		do
		end

	print_line (line: STRING)
		do
		end

	print_tab_left
		do
		end

	prompt_user (name_array: ARRAY [STRING])
		local
			s: EL_STRING_8_ROUTINES
		do
			if attached User_input.line ("Press <Enter> to copy file " + s.joined_list_with (name_array, " and ")) then
			end
		end

	read_manifest_files
		do
			Precursor
			class_list.grow (manifest.file_count)
			library_set.accommodate (manifest.file_count)
			class_path_table.accommodate (manifest.file_count)
		end

feature {NONE} -- Internal attributes

	class_list: EL_ARRAYED_LIST [LIBRARY_CLASS]

	class_path_table: HASH_TABLE [FILE_PATH, STRING]

	destination_dir: DIR_PATH

	home_dir: DIR_PATH

	library_set: EL_HASH_SET [STRING]

feature {NONE} -- Constants

	Excluded_imp_step: ZSTRING
		once
			Result := if {PLATFORM}.is_unix then "imp_mswin" else "imp_unix" end
		end
end