From 31727c352ed16fcb63cc6960547332cd2f8c593f Mon Sep 17 00:00:00 2001 From: sbcgua Date: Mon, 7 Nov 2016 13:47:26 +0200 Subject: [PATCH] new status implementation --- src/zabapgit_definitions.prog.abap | 10 +- src/zabapgit_file_status.prog.abap | 238 +++++++++++++++++++++++++++-- src/zabapgit_repo.prog.abap | 2 + src/zabapgit_repo_impl.prog.abap | 10 ++ src/zabapgit_tadir.prog.abap | 15 +- src/zabapgit_unit_test.prog.abap | 83 ++++++---- 6 files changed, 311 insertions(+), 47 deletions(-) diff --git a/src/zabapgit_definitions.prog.abap b/src/zabapgit_definitions.prog.abap index d63f0e06a..72c1a1015 100644 --- a/src/zabapgit_definitions.prog.abap +++ b/src/zabapgit_definitions.prog.abap @@ -14,12 +14,14 @@ TYPES: BEGIN OF ty_file_signature, sha1 TYPE ty_sha1, END OF ty_file_signature. +TYPES: ty_file_signatures_tt TYPE STANDARD TABLE OF ty_file_signature WITH DEFAULT KEY. +TYPES: ty_file_signatures_ts TYPE SORTED TABLE OF ty_file_signature WITH UNIQUE KEY path filename.. + TYPES: BEGIN OF ty_file. INCLUDE TYPE ty_file_signature. TYPES: data TYPE xstring, END OF ty_file. TYPES: ty_files_tt TYPE STANDARD TABLE OF ty_file WITH DEFAULT KEY. -TYPES: ty_file_signatures_tt TYPE STANDARD TABLE OF ty_file_signature WITH DEFAULT KEY. TYPES: ty_string_tt TYPE STANDARD TABLE OF string WITH DEFAULT KEY. TYPES: tt_w3urls TYPE STANDARD TABLE OF w3url WITH DEFAULT KEY. @@ -34,7 +36,9 @@ TYPES: BEGIN OF ty_item, obj_type TYPE tadir-object, obj_name TYPE tadir-obj_name, devclass TYPE devclass, - END OF ty_item. + END OF ty_item, + ty_items_tt TYPE STANDARD TABLE OF ty_item WITH DEFAULT KEY, + ty_items_ts TYPE SORTED TABLE OF ty_item WITH UNIQUE KEY obj_type obj_name. TYPES: BEGIN OF ty_file_item, file TYPE ty_file, @@ -102,8 +106,8 @@ TYPES: BEGIN OF ty_result, filename TYPE string, package TYPE devclass, match TYPE sap_bool, - rstate TYPE char1, lstate TYPE char1, + rstate TYPE char1, END OF ty_result. TYPES: ty_results_tt TYPE STANDARD TABLE OF ty_result WITH DEFAULT KEY. diff --git a/src/zabapgit_file_status.prog.abap b/src/zabapgit_file_status.prog.abap index 9a51f9333..1de7381d3 100644 --- a/src/zabapgit_file_status.prog.abap +++ b/src/zabapgit_file_status.prog.abap @@ -36,9 +36,27 @@ CLASS lcl_file_status DEFINITION FINAL IMPORTING it_local TYPE ty_files_item_tt it_remote TYPE ty_files_tt it_cur_state TYPE ty_file_signatures_tt - iv_starting_folder TYPE string RETURNING VALUE(rt_results) TYPE ty_results_tt. + CLASS-METHODS: + build_existing + IMPORTING is_local TYPE ty_file_item + is_remote TYPE ty_file + it_state TYPE ty_file_signatures_ts + RETURNING VALUE(rs_result) TYPE ty_result, + build_new_local + IMPORTING is_local TYPE ty_file_item + RETURNING VALUE(rs_result) TYPE ty_result, + build_new_remote + IMPORTING is_remote TYPE ty_file + it_items TYPE ty_items_ts + it_state TYPE ty_file_signatures_ts + RETURNING VALUE(rs_result) TYPE ty_result, + identify_object + IMPORTING iv_filename TYPE string + EXPORTING es_item TYPE ty_item + ev_is_xml TYPE abap_bool. + ENDCLASS. "lcl_file_status DEFINITION *----------------------------------------------------------------------* @@ -60,32 +78,31 @@ CLASS lcl_file_status IMPLEMENTATION. METHOD status. - DATA: lt_local TYPE ty_files_item_tt, - lt_remote TYPE ty_files_tt, - lt_tadir TYPE ty_tadir_tt, - lv_index LIKE sy-tabix, + DATA: lv_index LIKE sy-tabix, lo_dot_abapgit TYPE REF TO lcl_dot_abapgit. FIELD-SYMBOLS LIKE LINE OF rt_results. - lt_remote = io_repo->get_files_remote( ). - lt_local = io_repo->get_files_local( io_log ). lo_dot_abapgit = io_repo->get_dot_abapgit( ). - lt_tadir = lcl_tadir=>read( io_repo->get_package( ) ). - rt_results = calculate_status_old( - it_local = lt_local - it_remote = lt_remote - it_tadir = lt_tadir - iv_starting_folder = lo_dot_abapgit->get_starting_folder( ) ). +* rt_results = calculate_status_old( +* it_local = io_repo->get_files_local( io_log ) +* it_remote = io_repo->get_files_remote( ) +* it_tadir = lcl_tadir=>read( io_repo->get_package( ) ) +* iv_starting_folder = lo_dot_abapgit->get_starting_folder( ) ). + + rt_results = calculate_status_new( + it_local = io_repo->get_files_local( io_log ) + it_remote = io_repo->get_files_remote( ) + it_cur_state = io_repo->get_local_checksums_per_file( ) ). " Remove ignored files, fix .abapgit LOOP AT rt_results ASSIGNING . lv_index = sy-tabix. " Crutch for .abapgit -> it is always match as generated dynamically - " However this is probably the place to compare it when local editing - " of it will be implemented + " However this is probably the place to compare it when .abapgit editing + " tool will be implemented IF -path = gc_root_dir AND -filename = gc_dot_abapgit. -match = abap_true. CLEAR: -lstate, -rstate. @@ -108,8 +125,199 @@ CLASS lcl_file_status IMPLEMENTATION. ENDMETHOD. "status METHOD calculate_status_new. + + DATA: lt_remote LIKE it_remote, + lt_items TYPE ty_items_tt, + ls_item LIKE LINE OF lt_items, + lv_is_xml TYPE abap_bool, + lt_items_idx TYPE ty_items_ts, + lt_state_idx TYPE ty_file_signatures_ts. " Sorted by path+filename + + FIELD-SYMBOLS: LIKE LINE OF it_remote, + LIKE LINE OF rt_results, + LIKE LINE OF it_local. + + lt_state_idx = it_cur_state. " Force sort it + lt_remote = it_remote. + SORT lt_remote BY path filename. + + " Process local files and new local files + LOOP AT it_local ASSIGNING . + APPEND INITIAL LINE TO rt_results ASSIGNING . + APPEND -item TO lt_items. " Collect for item index + + READ TABLE lt_remote ASSIGNING + WITH KEY path = -file-path filename = -file-filename + BINARY SEARCH. + IF sy-subrc = 0. " Exist L and R + = build_existing( + is_local = + is_remote = + it_state = lt_state_idx ). + ASSERT -sha1 IS NOT INITIAL. + CLEAR -sha1. " Mark as processed + ELSE. " Only L exists + = build_new_local( is_local = ). + ENDIF. + ENDLOOP. + + " Complete item index for unmarked remote files + LOOP AT lt_remote ASSIGNING WHERE sha1 IS NOT INITIAL. + identify_object( EXPORTING iv_filename = -filename + IMPORTING es_item = ls_item + ev_is_xml = lv_is_xml ). + + CHECK lv_is_xml = abap_true. " Skip all but obj definitions + + ls_item-devclass = lcl_tadir=>get_object_package( + iv_object = ls_item-obj_type + iv_obj_name = ls_item-obj_name ). + APPEND ls_item TO lt_items. + ENDLOOP. + + SORT lt_items. " Default key - type, name, pkg + DELETE ADJACENT DUPLICATES FROM lt_items. + lt_items_idx = lt_items. " Self protection + UNIQUE records assertion + + " Process new remote files (marked above with empty SHA1) + LOOP AT lt_remote ASSIGNING WHERE sha1 IS NOT INITIAL. + APPEND INITIAL LINE TO rt_results ASSIGNING . + = build_new_remote( is_remote = + it_items = lt_items_idx + it_state = lt_state_idx ). + ENDLOOP. + + SORT rt_results BY + obj_type ASCENDING + obj_name ASCENDING + filename ASCENDING. + ENDMETHOD. "calculate_status_new. + METHOD identify_object. + + DATA: lv_name TYPE tadir-obj_name, + lv_type TYPE string, + lv_ext TYPE string. + + " Guess object type and name + SPLIT to_upper( iv_filename ) AT '.' INTO lv_name lv_type lv_ext. + + " Handle namespaces + REPLACE ALL OCCURRENCES OF '#' IN lv_name WITH '/'. + + CLEAR es_item. + es_item-obj_type = lv_type. + es_item-obj_name = lv_name. + ev_is_xml = boolc( lv_ext = 'XML' AND strlen( lv_type ) = 4 ). + + ENDMETHOD. "identify_object. + + METHOD build_existing. + + DATA: ls_file_sig LIKE LINE OF it_state. + + " Item + rs_result-obj_type = is_local-item-obj_type. + rs_result-obj_name = is_local-item-obj_name. + rs_result-package = is_local-item-devclass. + + " File + rs_result-path = is_local-file-path. + rs_result-filename = is_local-file-filename. + + " Match against current state + READ TABLE it_state INTO ls_file_sig + WITH KEY path = is_local-file-path filename = is_local-file-filename + BINARY SEARCH. + + IF sy-subrc = 0. + IF ls_file_sig-sha1 <> is_local-file-sha1. + rs_result-lstate = gc_state-modified. + ENDIF. + IF ls_file_sig-sha1 <> is_remote-sha1. + rs_result-rstate = gc_state-modified. + ENDIF. + rs_result-match = boolc( rs_result-lstate IS INITIAL AND rs_result-rstate IS INITIAL ). + ELSE. + " This is a strange situation. As both local and remote exist + " the state should also be present. Maybe this is a first run of the code. + " In this case just compare hashes directly and mark both changed + " the user will presumably decide what to do after checking the actual diff + rs_result-match = boolc( is_local-file-sha1 = is_remote-sha1 ). + IF rs_result-match = abap_false. + rs_result-lstate = gc_state-modified. + rs_result-rstate = gc_state-modified. + ENDIF. + ENDIF. + + ENDMETHOD. "build_existing + + METHOD build_new_local. + + " Item + rs_result-obj_type = is_local-item-obj_type. + rs_result-obj_name = is_local-item-obj_name. + rs_result-package = is_local-item-devclass. + + " File + rs_result-path = is_local-file-path. + rs_result-filename = is_local-file-filename. + + " Match + rs_result-match = abap_false. + rs_result-lstate = gc_state-added. + + ENDMETHOD. "build_new_local + + METHOD build_new_remote. + + DATA: ls_item LIKE LINE OF it_items, + ls_file_sig LIKE LINE OF it_state. + + " Common and default part + rs_result-path = is_remote-path. + rs_result-filename = is_remote-filename. + rs_result-match = abap_false. + rs_result-rstate = gc_state-added. + + identify_object( EXPORTING iv_filename = is_remote-filename + IMPORTING es_item = ls_item ). + + " Check if in item index + get package + READ TABLE it_items INTO ls_item + WITH KEY obj_type = ls_item-obj_type obj_name = ls_item-obj_name + BINARY SEARCH. + + IF sy-subrc = 0. + + " Completely new (xml, abap) and new file in an existing object + rs_result-obj_type = ls_item-obj_type. + rs_result-obj_name = ls_item-obj_name. + rs_result-package = ls_item-devclass. + + READ TABLE it_state INTO ls_file_sig + WITH KEY path = is_remote-path filename = is_remote-filename + BINARY SEARCH. + + " Existing file but from another package + " was not added during local file proc as was not in tadir for repo package + IF sy-subrc = 0. + IF ls_file_sig-sha1 = is_remote-sha1. + rs_result-match = abap_true. + CLEAR rs_result-rstate. + ELSE. + rs_result-rstate = gc_state-modified. + ENDIF. + ENDIF. + + ELSE. " Completely unknown file, probably non-abapgit + " No action, just follow defaults + ASSERT 1 = 1. + ENDIF. + + ENDMETHOD. "build_new_remote + METHOD calculate_status_old. DATA: lv_pre TYPE tadir-obj_name, diff --git a/src/zabapgit_repo.prog.abap b/src/zabapgit_repo.prog.abap index 8d680bee6..a3fe6b19c 100644 --- a/src/zabapgit_repo.prog.abap +++ b/src/zabapgit_repo.prog.abap @@ -22,6 +22,8 @@ CLASS lcl_repo DEFINITION ABSTRACT FRIENDS lcl_repo_srv. RAISING lcx_exception, get_local_checksums RETURNING VALUE(rt_checksums) TYPE lcl_persistence_repo=>ty_local_checksum_tt, + get_local_checksums_per_file + RETURNING VALUE(rt_checksums) TYPE ty_file_signatures_tt, get_files_remote RETURNING VALUE(rt_files) TYPE ty_files_tt RAISING lcx_exception, diff --git a/src/zabapgit_repo_impl.prog.abap b/src/zabapgit_repo_impl.prog.abap index 052f5725e..fb011d10b 100644 --- a/src/zabapgit_repo_impl.prog.abap +++ b/src/zabapgit_repo_impl.prog.abap @@ -389,6 +389,16 @@ CLASS lcl_repo IMPLEMENTATION. rt_checksums = ms_data-local_checksums. ENDMETHOD. + METHOD get_local_checksums_per_file. + + FIELD-SYMBOLS LIKE LINE OF ms_data-local_checksums. + + LOOP AT ms_data-local_checksums ASSIGNING . + APPEND LINES OF -files TO rt_checksums. + ENDLOOP. + + ENDMETHOD. + METHOD get_files_local. DATA: lt_tadir TYPE ty_tadir_tt, diff --git a/src/zabapgit_tadir.prog.abap b/src/zabapgit_tadir.prog.abap index d2dab066f..1632b6866 100644 --- a/src/zabapgit_tadir.prog.abap +++ b/src/zabapgit_tadir.prog.abap @@ -19,7 +19,12 @@ CLASS lcl_tadir DEFINITION FINAL. IMPORTING iv_pgmid TYPE tadir-pgmid DEFAULT 'R3TR' iv_object TYPE tadir-object iv_obj_name TYPE tadir-obj_name - RETURNING VALUE(rs_tadir) TYPE tadir. + RETURNING VALUE(rs_tadir) TYPE tadir, + get_object_package + IMPORTING iv_pgmid TYPE tadir-pgmid DEFAULT 'R3TR' + iv_object TYPE tadir-object + iv_obj_name TYPE tadir-obj_name + RETURNING VALUE(rv_devclass) TYPE tadir-devclass. PRIVATE SECTION. CLASS-METHODS: @@ -60,6 +65,14 @@ CLASS lcl_tadir IMPLEMENTATION. ENDMETHOD. "read_single + METHOD get_object_package. + + rv_devclass = read_single( iv_pgmid = iv_pgmid + iv_object = iv_object + iv_obj_name = iv_obj_name )-devclass. + + ENDMETHOD. "get_object_package. + METHOD check_exists. DATA: lv_exists TYPE abap_bool, diff --git a/src/zabapgit_unit_test.prog.abap b/src/zabapgit_unit_test.prog.abap index fb09a4fcd..4dc95569b 100644 --- a/src/zabapgit_unit_test.prog.abap +++ b/src/zabapgit_unit_test.prog.abap @@ -1778,9 +1778,9 @@ CLASS ltcl_file_status IMPLEMENTATION. DEFINE _append_state. APPEND INITIAL LINE TO lt_state ASSIGNING . - -path = '/'. - -filename = &1. - -sha1 = &2. + -path = '/'. + -filename = &1. + -sha1 = &2. END-OF-DEFINITION. DEFINE _append_tadir. @@ -1818,58 +1818,85 @@ CLASS ltcl_file_status IMPLEMENTATION. LIKE LINE OF lt_tadir. "STATE FILE SHA1 + _append_state 'zclass1.clas.xml' 'C1_F1'. + " class1 testclasses is new locally, abap is new remotely + " class2 is completely new remotely _append_state 'zdoma1.doma.xml' 'D1'. _append_state 'zdoma2.doma.xml' 'D2'. _append_state 'zdoma3.doma.xml' 'D3'. - _append_state 'zclass1.clas.xml' 'C1_F1'. - _append_state 'zclass1.clas.testclasses.abap' 'C1_F3'. - _append_state 'zdoma5.doma.xml' 'D5'. + " doma4 is new locally + " doma5 is new remotely _append_state 'zdoma6.doma.xml' 'D6'. + " doma7 is not in state - emulate brocken cache + " doma8 is not in state - emulate brocken cache + _append_state 'xfeld.doma.xml' 'XFELD'. " from different package + _append_state 'num01.doma.xml' 'NUM01'. " another from different package "LOCAL TYPE NAME FILE SHA1 + _append_local 'CLAS' 'ZCLASS1' 'zclass1.clas.testclasses.abap' 'C1_F3'. + _append_local 'CLAS' 'ZCLASS1' 'zclass1.clas.xml' 'C1_F1'. _append_local 'DOMA' 'ZDOMA1' 'zdoma1.doma.xml' 'D1'. _append_local 'DOMA' 'ZDOMA2' 'zdoma2.doma.xml' 'D2_CHANGED_L'. _append_local 'DOMA' 'ZDOMA3' 'zdoma3.doma.xml' 'D3'. - _append_local 'CLAS' 'ZCLASS1' 'zclass1.clas.xml' 'C1_F1'. - _append_local 'CLAS' 'ZCLASS1' 'zclass1.clas.testclasses.abap' 'C1_F3'. - _append_local 'DOMA' 'ZDOMA5' 'zdoma5.doma.xml' 'D5'. + _append_local 'DOMA' 'ZDOMA4' 'zdoma4.doma.xml' 'D4'. _append_local 'DOMA' 'ZDOMA6' 'zdoma6.doma.xml' 'D6_CHANGED_L'. + _append_local 'DOMA' 'ZDOMA7' 'zdoma7.doma.xml' 'D7'. + _append_local 'DOMA' 'ZDOMA8' 'zdoma8.doma.xml' 'D8'. "REMOTE FILE SHA1 + _append_remote 'textfile.txt' 'T1'. + _append_remote 'zclass1.clas.abap' 'C1_F2'. " Must be before xml for tougher test + _append_remote 'zclass1.clas.xml' 'C1_F1'. + _append_remote 'zclass2.clas.abap' 'C1_F2'. " Must be before xml for tougher test + _append_remote 'zclass2.clas.xml' 'C1_F1'. _append_remote 'zdoma1.doma.xml' 'D1'. _append_remote 'zdoma2.doma.xml' 'D2'. _append_remote 'zdoma3.doma.xml' 'D3_CHANGED_R'. - _append_remote 'zclass1.clas.xml' 'C1_F1'. - _append_remote 'zclass1.clas.abap' 'C1_F2'. - _append_remote 'zdoma4.doma.xml' 'D4'. + _append_remote 'zdoma5.doma.xml' 'D5'. _append_remote 'zdoma6.doma.xml' 'D6_CHANGED_R'. - _append_remote 'textfile.txt' 'T1'. + _append_remote 'zdoma7.doma.xml' 'D7'. + _append_remote 'zdoma8.doma.xml' 'D8_CHANGED_R'. " This one is changed + _append_remote 'xfeld.doma.xml' 'XFELD'. " Object from different package + _append_remote 'num01.doma.xml' 'NUM01_CHANGED'. " Changed object from different package "TADIR TYPE NAME _append_tadir 'DOMA' 'ZDOMA1'. _append_tadir 'DOMA' 'ZDOMA2'. _append_tadir 'DOMA' 'ZDOMA3'. _append_tadir 'CLAS' 'ZCLASS1'. - _append_tadir 'DOMA' 'ZDOMA5'. + _append_tadir 'DOMA' 'ZDOMA4'. _append_tadir 'DOMA' 'ZDOMA6'. + _append_tadir 'DOMA' 'ZDOMA7'. + _append_tadir 'DOMA' 'ZDOMA8'. - "EXP RESULT TYPE NAME MATCH LST RST PKG FILE - _append_result '' '' '' '' 'A' '' 'textfile.txt'. - _append_result 'CLAS' 'ZCLASS1' '' 'R' 'L' '$Z$' 'zclass1.clas.abap'. - _append_result 'CLAS' 'ZCLASS1' '' 'L' 'R' '$Z$' 'zclass1.clas.testclasses.abap'. - _append_result 'CLAS' 'ZCLASS1' 'X' '' '' '$Z$' 'zclass1.clas.xml'. - _append_result 'DOMA' 'ZDOMA1' 'X' '' '' '$Z$' 'zdoma1.doma.xml'. - _append_result 'DOMA' 'ZDOMA2' '' 'M' '' '$Z$' 'zdoma2.doma.xml'. - _append_result 'DOMA' 'ZDOMA3' '' '' 'M' '$Z$' 'zdoma3.doma.xml'. - _append_result 'DOMA' 'ZDOMA4' '' '' 'A' '$Z$' 'zdoma4.doma.xml'. - _append_result 'DOMA' 'ZDOMA5' '' 'A' '' '$Z$' 'zdoma5.doma.xml'. - _append_result 'DOMA' 'ZDOMA6' '' 'M' 'M' '$Z$' 'zdoma6.doma.xml'. + "EXP RESULT TYPE NAME MATCH LST RST PKG FILE + _append_result '' '' ' ' ' ' 'A' '' 'textfile.txt'. + _append_result 'CLAS' 'ZCLASS1' ' ' ' ' 'A' '$Z$' 'zclass1.clas.abap'. + _append_result 'CLAS' 'ZCLASS1' ' ' 'A' ' ' '$Z$' 'zclass1.clas.testclasses.abap'. + _append_result 'CLAS' 'ZCLASS1' 'X' ' ' ' ' '$Z$' 'zclass1.clas.xml'. + _append_result 'CLAS' 'ZCLASS2' ' ' ' ' 'A' '' 'zclass2.clas.abap'. + _append_result 'CLAS' 'ZCLASS2' ' ' ' ' 'A' '' 'zclass2.clas.xml'. + _append_result 'DOMA' 'NUM01' ' ' ' ' 'M' 'SUTI' 'num01.doma.xml'. + _append_result 'DOMA' 'XFELD' 'X' ' ' ' ' 'SUTI' 'xfeld.doma.xml'. + _append_result 'DOMA' 'ZDOMA1' 'X' ' ' ' ' '$Z$' 'zdoma1.doma.xml'. + _append_result 'DOMA' 'ZDOMA2' ' ' 'M' ' ' '$Z$' 'zdoma2.doma.xml'. + _append_result 'DOMA' 'ZDOMA3' ' ' ' ' 'M' '$Z$' 'zdoma3.doma.xml'. + _append_result 'DOMA' 'ZDOMA4' ' ' 'A' ' ' '$Z$' 'zdoma4.doma.xml'. + _append_result 'DOMA' 'ZDOMA5' ' ' ' ' 'A' '' 'zdoma5.doma.xml'. + _append_result 'DOMA' 'ZDOMA6' ' ' 'M' 'M' '$Z$' 'zdoma6.doma.xml'. + _append_result 'DOMA' 'ZDOMA7' 'X' ' ' ' ' '$Z$' 'zdoma7.doma.xml'. + _append_result 'DOMA' 'ZDOMA8' ' ' 'M' 'M' '$Z$' 'zdoma8.doma.xml'. - lt_results = lcl_file_status=>calculate_status_old( +* lt_results = lcl_file_status=>calculate_status_old( +* it_local = lt_local +* it_remote = lt_remote +* it_tadir = lt_tadir +* iv_starting_folder = '/' ). + + lt_results = lcl_file_status=>calculate_status_new( it_local = lt_local it_remote = lt_remote - it_tadir = lt_tadir - iv_starting_folder = '/' ). + it_cur_state = lt_state ). assert_equals( act = lt_results exp = lt_results_exp ).