From fd401956b8361de6e4f931f627f2a250d5316c62 Mon Sep 17 00:00:00 2001 From: Lars Hvam Date: Mon, 3 Jan 2022 10:55:06 +0100 Subject: [PATCH] Refactoring: Prioritization/sequence of deserialization (#5198) --- .../zcl_abapgit_file_deserialize.clas.abap | 213 ++++++++++-------- ...git_file_deserialize.clas.testclasses.abap | 14 +- .../core/zcl_abapgit_item_graph.clas.abap | 104 +++++++++ ...l_abapgit_item_graph.clas.testclasses.abap | 60 +++++ .../core/zcl_abapgit_item_graph.clas.xml | 17 ++ 5 files changed, 310 insertions(+), 98 deletions(-) create mode 100644 src/objects/core/zcl_abapgit_item_graph.clas.abap create mode 100644 src/objects/core/zcl_abapgit_item_graph.clas.testclasses.abap create mode 100644 src/objects/core/zcl_abapgit_item_graph.clas.xml diff --git a/src/objects/core/zcl_abapgit_file_deserialize.clas.abap b/src/objects/core/zcl_abapgit_file_deserialize.clas.abap index 6359c6e4c..fb0abb50a 100644 --- a/src/objects/core/zcl_abapgit_file_deserialize.clas.abap +++ b/src/objects/core/zcl_abapgit_file_deserialize.clas.abap @@ -21,18 +21,23 @@ CLASS zcl_abapgit_file_deserialize DEFINITION !it_results TYPE zif_abapgit_definitions=>ty_results_tt !ii_log TYPE REF TO zif_abapgit_log OPTIONAL RETURNING - VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt. + VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt . CLASS-METHODS prioritize_deser IMPORTING + !ii_log TYPE REF TO zif_abapgit_log !it_results TYPE zif_abapgit_definitions=>ty_results_tt RETURNING - VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt. - + VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt . + CLASS-METHODS map_results_to_items + IMPORTING + !it_results TYPE zif_abapgit_definitions=>ty_results_tt + RETURNING + VALUE(rt_items) TYPE zif_abapgit_definitions=>ty_items_tt . ENDCLASS. -CLASS zcl_abapgit_file_deserialize IMPLEMENTATION. +CLASS ZCL_ABAPGIT_FILE_DESERIALIZE IMPLEMENTATION. METHOD filter_files_to_deserialize. @@ -126,108 +131,126 @@ CLASS zcl_abapgit_file_deserialize IMPLEMENTATION. METHOD get_results. + DATA lt_results TYPE zif_abapgit_definitions=>ty_results_tt. + + lt_results = filter_files_to_deserialize( + it_results = zcl_abapgit_file_status=>status( io_repo ) + ii_log = ii_log ). + rt_results = prioritize_deser( - filter_files_to_deserialize( - it_results = zcl_abapgit_file_status=>status( io_repo ) - ii_log = ii_log ) ). + ii_log = ii_log + it_results = lt_results ). + + ENDMETHOD. + + + METHOD map_results_to_items. + + DATA ls_item LIKE LINE OF rt_items. + FIELD-SYMBOLS: TYPE zif_abapgit_definitions=>ty_result. + + LOOP AT it_results ASSIGNING . + ls_item-devclass = -package. + ls_item-obj_type = -obj_type. + ls_item-obj_name = -obj_name. + INSERT ls_item INTO TABLE rt_items. + ENDLOOP. ENDMETHOD. METHOD prioritize_deser. -* todo, refactor this method #3536 + DATA lt_items TYPE zif_abapgit_definitions=>ty_items_tt. + DATA ls_item LIKE LINE OF lt_items. + DATA lt_requires TYPE zif_abapgit_definitions=>ty_items_tt. + DATA ls_require LIKE LINE OF lt_requires. + DATA ls_result LIKE LINE OF it_results. + DATA lo_graph TYPE REF TO zcl_abapgit_item_graph. - FIELD-SYMBOLS: LIKE LINE OF it_results. + lt_items = map_results_to_items( it_results ). -* WEBI has to be handled before SPRX. - LOOP AT it_results ASSIGNING WHERE obj_type = 'WEBI'. - APPEND TO rt_results. + CREATE OBJECT lo_graph EXPORTING it_items = lt_items. + + LOOP AT lt_items INTO ls_item. + CLEAR lt_requires. + +* TODO: BEGIN extract to object handler method in ZIF_ABAPGIT_OBJECT: +* METHODS get_deserialize_order +* IMPORTING +* it_items TYPE ty_items_tt +* RETURNING +* VALUE(rt_requries) TYPE ty_items_tt + + CASE ls_item-obj_type. + WHEN 'SPRX'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'WEBI'. + WHEN 'CLAS'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'SPRX' + AND obj_type <> 'XSLT'. + WHEN 'PROG'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'XSLT'. + WHEN 'INTF'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'SPRX'. + WHEN 'TABL'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'SPRX'. + WHEN 'ISRP'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'IASP'. + WHEN 'DCLS'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'DDLS'. + WHEN 'ODSO'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'IOBJ'. + WHEN 'SCP1'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'TOBJ'. + WHEN 'CHAR'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'OTGR'. + WHEN 'PINF'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'CLAS' + AND obj_type <> 'INTF' + AND obj_type <> 'TABL' + AND obj_type <> 'DOMA' + AND obj_type <> 'DTEL'. + WHEN 'DEVC'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'PINF'. + WHEN 'ENHC'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'ENHO'. + WHEN 'ENHO'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'ENSC'. + WHEN 'ENSC'. + lt_requires = lt_items. + DELETE lt_requires WHERE obj_type <> 'ENHS'. + ENDCASE. +* TODO: END extract to object handler method + + LOOP AT lt_requires INTO ls_require. + lo_graph->add_edge( + is_from = ls_require + is_to = ls_item ). + ENDLOOP. ENDLOOP. -* SPRX has to be handled before depended objects CLAS/INFT/TABL etc. - LOOP AT it_results ASSIGNING WHERE obj_type = 'SPRX'. - APPEND TO rt_results. - ENDLOOP. - -* XSLT has to be handled before CLAS/PROG - LOOP AT it_results ASSIGNING WHERE obj_type = 'XSLT'. - APPEND TO rt_results. - ENDLOOP. - -* PROG before internet services, as the services might use the screens - LOOP AT it_results ASSIGNING WHERE obj_type = 'PROG'. - APPEND TO rt_results. - ENDLOOP. - -* ISAP has to be handled before ISRP - LOOP AT it_results ASSIGNING WHERE obj_type = 'IASP'. - APPEND TO rt_results. - ENDLOOP. - -* DDLS has to be handled before DCLS - LOOP AT it_results ASSIGNING WHERE obj_type = 'DDLS'. - APPEND TO rt_results. - ENDLOOP. - -* IOBJ has to be handled before ODSO - LOOP AT it_results ASSIGNING WHERE obj_type = 'IOBJ'. - APPEND TO rt_results. - ENDLOOP. - -* TOBJ has to be handled before SCP1 - LOOP AT it_results ASSIGNING WHERE obj_type = 'TOBJ'. - APPEND TO rt_results. - ENDLOOP. - -* OTGR has to be handled before CHAR - LOOP AT it_results ASSIGNING WHERE obj_type = 'OTGR'. - APPEND TO rt_results. - ENDLOOP. - - LOOP AT it_results ASSIGNING - WHERE obj_type <> 'IASP' - AND obj_type <> 'PROG' - AND obj_type <> 'XSLT' - AND obj_type <> 'PINF' - AND obj_type <> 'DEVC' - AND obj_type <> 'ENHS' - AND obj_type <> 'ENHO' - AND obj_type <> 'ENHC' - AND obj_type <> 'ENSC' - AND obj_type <> 'DDLS' - AND obj_type <> 'SPRX' - AND obj_type <> 'WEBI' - AND obj_type <> 'IOBJ' - AND obj_type <> 'TOBJ' - AND obj_type <> 'OTGR'. - APPEND TO rt_results. - ENDLOOP. - -* Enhancements might refer to other objects of the repo so create them after -* Order: spots, composite spots, implementations, composite implementations - LOOP AT it_results ASSIGNING WHERE obj_type = 'ENHS'. - APPEND TO rt_results. - ENDLOOP. - LOOP AT it_results ASSIGNING WHERE obj_type = 'ENSC'. - APPEND TO rt_results. - ENDLOOP. - LOOP AT it_results ASSIGNING WHERE obj_type = 'ENHO'. - APPEND TO rt_results. - ENDLOOP. - LOOP AT it_results ASSIGNING WHERE obj_type = 'ENHC'. - APPEND TO rt_results. - ENDLOOP. - -* PINF after everything as it can expose objects - LOOP AT it_results ASSIGNING WHERE obj_type = 'PINF'. - APPEND TO rt_results. - ENDLOOP. - -* DEVC after PINF, as it can refer for package interface usage - LOOP AT it_results ASSIGNING WHERE obj_type = 'DEVC'. - APPEND TO rt_results. - ENDLOOP. + WHILE lo_graph->has_vertices( ) = abap_true. + ls_item = lo_graph->get_next( ii_log ). + READ TABLE it_results INTO ls_result WITH KEY + obj_name = ls_item-obj_name + obj_type = ls_item-obj_type. + ASSERT sy-subrc = 0. + APPEND ls_result TO rt_results. + ENDWHILE. ENDMETHOD. ENDCLASS. diff --git a/src/objects/core/zcl_abapgit_file_deserialize.clas.testclasses.abap b/src/objects/core/zcl_abapgit_file_deserialize.clas.testclasses.abap index e3a966f9a..888fa6f06 100644 --- a/src/objects/core/zcl_abapgit_file_deserialize.clas.testclasses.abap +++ b/src/objects/core/zcl_abapgit_file_deserialize.clas.testclasses.abap @@ -248,6 +248,7 @@ CLASS ltcl_prio_deserialization DEFINITION FINAL FOR TESTING mo_objects TYPE REF TO zcl_abapgit_file_deserialize, mt_input TYPE zif_abapgit_definitions=>ty_results_tt, mt_output TYPE zif_abapgit_definitions=>ty_results_tt, + mv_counter TYPE i, mv_exp_output_tabix TYPE i. ENDCLASS. @@ -387,17 +388,24 @@ CLASS ltcl_prio_deserialization IMPLEMENTATION. METHOD given. - DATA: ls_input LIKE LINE OF mt_input. - + DATA ls_input LIKE LINE OF mt_input. ls_input-obj_type = iv_object_type. + ls_input-obj_name = mv_counter. INSERT ls_input INTO TABLE mt_input. + mv_counter = mv_counter + 1. ENDMETHOD. METHOD when_deser_is_priorized. - mt_output = mo_objects->prioritize_deser( mt_input ). + DATA lo_log TYPE REF TO zcl_abapgit_log. + + CREATE OBJECT lo_log. + + mt_output = mo_objects->prioritize_deser( + ii_log = lo_log + it_results = mt_input ). ENDMETHOD. diff --git a/src/objects/core/zcl_abapgit_item_graph.clas.abap b/src/objects/core/zcl_abapgit_item_graph.clas.abap new file mode 100644 index 000000000..f7adc6e42 --- /dev/null +++ b/src/objects/core/zcl_abapgit_item_graph.clas.abap @@ -0,0 +1,104 @@ +CLASS zcl_abapgit_item_graph DEFINITION + PUBLIC + CREATE PUBLIC . + + PUBLIC SECTION. + + METHODS constructor + IMPORTING + !it_items TYPE zif_abapgit_definitions=>ty_items_tt . + METHODS add_edge + IMPORTING + !is_from TYPE zif_abapgit_definitions=>ty_item + !is_to TYPE zif_abapgit_definitions=>ty_item . + METHODS has_vertices + RETURNING + VALUE(rv_bool) TYPE abap_bool . + METHODS get_next + IMPORTING + !ii_log TYPE REF TO zif_abapgit_log + RETURNING + VALUE(rs_item) TYPE zif_abapgit_definitions=>ty_item . + PRIVATE SECTION. + TYPES: BEGIN OF ty_edge, + from TYPE zif_abapgit_definitions=>ty_item, + to TYPE zif_abapgit_definitions=>ty_item, + END OF ty_edge. + + DATA mt_vertices TYPE STANDARD TABLE OF zif_abapgit_definitions=>ty_item WITH DEFAULT KEY. + DATA mt_edges TYPE STANDARD TABLE OF ty_edge WITH DEFAULT KEY. + DATA mv_warning TYPE abap_bool. + + METHODS remove_vertex IMPORTING iv_index TYPE i. + +ENDCLASS. + + + +CLASS ZCL_ABAPGIT_ITEM_GRAPH IMPLEMENTATION. + + + METHOD add_edge. + DATA ls_edge LIKE LINE OF mt_edges. + ASSERT is_from IS NOT INITIAL. + ASSERT is_to IS NOT INITIAL. + ls_edge-from = is_from. + ls_edge-to = is_to. + APPEND ls_edge TO mt_edges. + ENDMETHOD. + + + METHOD constructor. + INSERT LINES OF it_items INTO TABLE mt_vertices. + ENDMETHOD. + + + METHOD get_next. +* find a vertex with no inbound edges, if it does not exist pick anything + + DATA ls_vertex LIKE LINE OF mt_vertices. + DATA lv_index TYPE i. + + LOOP AT mt_vertices INTO ls_vertex. + lv_index = sy-tabix. + READ TABLE mt_edges WITH KEY + to-obj_type = ls_vertex-obj_type + to-obj_name = ls_vertex-obj_name + TRANSPORTING NO FIELDS. + IF sy-subrc <> 0. + remove_vertex( lv_index ). + rs_item = ls_vertex. + RETURN. + ENDIF. + ENDLOOP. + + IF mv_warning = abap_false. +* only issue the warning once per graph + ii_log->add_warning( |Cycle detected in item graph| ). + mv_warning = abap_true. + ENDIF. + + READ TABLE mt_vertices INTO rs_item INDEX 1. + ASSERT sy-subrc = 0. + remove_vertex( 1 ). + + ENDMETHOD. + + + METHOD has_vertices. + rv_bool = boolc( lines( mt_vertices ) > 0 ). + ENDMETHOD. + + + METHOD remove_vertex. + DATA ls_vertex LIKE LINE OF mt_vertices. + + READ TABLE mt_vertices INDEX iv_index INTO ls_vertex. + ASSERT sy-subrc = 0. + + DELETE mt_vertices INDEX iv_index. + DELETE mt_edges WHERE + from-obj_type = ls_vertex-obj_type AND + from-obj_name = ls_vertex-obj_name. + ENDMETHOD. +ENDCLASS. diff --git a/src/objects/core/zcl_abapgit_item_graph.clas.testclasses.abap b/src/objects/core/zcl_abapgit_item_graph.clas.testclasses.abap new file mode 100644 index 000000000..660fa90e5 --- /dev/null +++ b/src/objects/core/zcl_abapgit_item_graph.clas.testclasses.abap @@ -0,0 +1,60 @@ +CLASS ltcl_test DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS FINAL. + + PRIVATE SECTION. + METHODS basic FOR TESTING RAISING cx_static_check. + +ENDCLASS. + + +CLASS ltcl_test IMPLEMENTATION. + + METHOD basic. + + DATA lo_graph TYPE REF TO zcl_abapgit_item_graph. + DATA li_log TYPE REF TO zif_abapgit_log. + DATA lt_items TYPE zif_abapgit_definitions=>ty_items_tt. + DATA ls_item1 LIKE LINE OF lt_items. + DATA ls_item2 LIKE LINE OF lt_items. + DATA ls_next LIKE LINE OF lt_items. + + CREATE OBJECT li_log TYPE zcl_abapgit_log. + + ls_item1-obj_type = 'TYPE'. + ls_item1-obj_type = '1111'. + APPEND ls_item1 TO lt_items. + + ls_item2-obj_type = 'TYPE'. + ls_item2-obj_type = '2222'. + APPEND ls_item2 TO lt_items. + + CREATE OBJECT lo_graph EXPORTING it_items = lt_items. + + lo_graph->add_edge( + is_from = ls_item1 + is_to = ls_item2 ). + + cl_abap_unit_assert=>assert_equals( + act = lo_graph->has_vertices( ) + exp = abap_true ). + + ls_next = lo_graph->get_next( li_log ). + cl_abap_unit_assert=>assert_equals( + act = ls_next-obj_name + exp = ls_item1-obj_name ). + + cl_abap_unit_assert=>assert_equals( + act = lo_graph->has_vertices( ) + exp = abap_true ). + + ls_next = lo_graph->get_next( li_log ). + cl_abap_unit_assert=>assert_equals( + act = ls_next-obj_name + exp = ls_item2-obj_name ). + + cl_abap_unit_assert=>assert_equals( + act = lo_graph->has_vertices( ) + exp = abap_false ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/objects/core/zcl_abapgit_item_graph.clas.xml b/src/objects/core/zcl_abapgit_item_graph.clas.xml new file mode 100644 index 000000000..7cffa386f --- /dev/null +++ b/src/objects/core/zcl_abapgit_item_graph.clas.xml @@ -0,0 +1,17 @@ + + + + + + ZCL_ABAPGIT_ITEM_GRAPH + E + abapGit - Item graph + 1 + X + X + X + X + + + +