CLASS zcl_abapgit_objects_activation DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS add
      IMPORTING
        !iv_type   TYPE trobjtype
        !iv_name   TYPE clike
        !iv_delete TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS add_item
      IMPORTING
        !is_item TYPE zif_abapgit_definitions=>ty_item
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS activate
      IMPORTING
        !iv_ddic TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS clear .
  PROTECTED SECTION.
  PRIVATE SECTION.

    CLASS-DATA:
      gt_classes TYPE STANDARD TABLE OF seoclsname WITH DEFAULT KEY .
    CLASS-DATA:
      gt_objects TYPE TABLE OF dwinactiv .

    CLASS-METHODS update_where_used .
    CLASS-METHODS use_new_activation_logic
      RETURNING
        VALUE(rv_use_new_activation_logic) TYPE abap_bool .
    CLASS-METHODS activate_new
      IMPORTING
        !iv_ddic TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS activate_old
      IMPORTING
        !iv_ddic TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS activate_ddic
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS show_activation_errors
      IMPORTING
        !iv_logname TYPE ddmass-logname
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_OBJECTS_ACTIVATION IMPLEMENTATION.

  METHOD activate.

    IF use_new_activation_logic( ) = abap_true.
      activate_new( iv_ddic ).
    ELSE.
      activate_old( iv_ddic ).
    ENDIF.

    update_where_used( ).

  ENDMETHOD.

  METHOD activate_ddic.

    DATA: lt_gentab     TYPE STANDARD TABLE OF dcgentb,
          lv_rc         TYPE sy-subrc,
          ls_gentab     LIKE LINE OF lt_gentab,
          lt_deltab     TYPE STANDARD TABLE OF dcdeltb,
          lt_action_tab TYPE STANDARD TABLE OF dctablres,
          lv_logname    TYPE ddmass-logname.

    FIELD-SYMBOLS: <ls_object> LIKE LINE OF gt_objects.

    LOOP AT gt_objects ASSIGNING <ls_object>.
      ls_gentab-tabix = sy-tabix.
      ls_gentab-type = <ls_object>-object.
      ls_gentab-name = <ls_object>-obj_name.
      IF ls_gentab-type = 'INDX'.
        CALL FUNCTION 'DD_E071_TO_DD'
          EXPORTING
            object   = <ls_object>-object
            obj_name = <ls_object>-obj_name
          IMPORTING
            name     = ls_gentab-name
            id       = ls_gentab-indx.
      ENDIF.
      INSERT ls_gentab INTO TABLE lt_gentab.
    ENDLOOP.

    IF lt_gentab IS NOT INITIAL.

      lv_logname = |ABAPGIT_{ sy-datum }_{ sy-uzeit }|.

      CALL FUNCTION 'DD_MASS_ACT_C3'
        EXPORTING
          ddmode         = 'O'
          medium         = 'T' " transport order
          device         = 'T' " saves to table DDRPH?
          version        = 'M' " activate newest
          logname        = lv_logname
          write_log      = abap_true
          log_head_tail  = abap_true
          t_on           = space
          prid           = 1
        IMPORTING
          act_rc         = lv_rc
        TABLES
          gentab         = lt_gentab
          deltab         = lt_deltab
          cnvtab         = lt_action_tab
        EXCEPTIONS
          access_failure = 1
          no_objects     = 2
          locked         = 3
          internal_error = 4
          OTHERS         = 5.

      IF sy-subrc <> 0.
        zcx_abapgit_exception=>raise( 'error from DD_MASS_ACT_C3' ).
      ENDIF.

      IF lv_rc > 0.
        show_activation_errors( lv_logname ).
      ENDIF.

    ENDIF.

  ENDMETHOD.

  METHOD activate_new.

    DATA: li_progress TYPE REF TO zif_abapgit_progress.

    IF gt_objects IS INITIAL.
      RETURN.
    ENDIF.

    li_progress = zcl_abapgit_progress=>get_instance( 100 ).

    IF iv_ddic = abap_true.

      li_progress->show( iv_current = 98
                         iv_text    = 'Activating DDIC' ).

      activate_ddic( ).

    ELSE.

      li_progress->show( iv_current = 98
                         iv_text    = 'Activating non DDIC' ).

      activate_old( ).

    ENDIF.

  ENDMETHOD.

  METHOD activate_old.

    DATA: lv_popup TYPE abap_bool,
          lv_no_ui TYPE abap_bool.

    IF gt_objects IS NOT INITIAL.

      IF zcl_abapgit_ui_factory=>get_gui_functions( )->gui_is_available( ) = abap_true.
        IF zcl_abapgit_persist_settings=>get_instance( )->read( )->get_activate_wo_popup( ) = abap_true.
          lv_popup = abap_false.
        ELSE.
          lv_popup = abap_true.
        ENDIF.
      ELSE.
        lv_popup = abap_false.
      ENDIF.

      lv_no_ui = boolc( lv_popup = abap_false ).

      TRY.
          CALL FUNCTION 'RS_WORKING_OBJECTS_ACTIVATE'
            EXPORTING
              activate_ddic_objects  = iv_ddic
              with_popup             = lv_popup
              ui_decoupled           = lv_no_ui
            TABLES
              objects                = gt_objects
            EXCEPTIONS
              excecution_error       = 1
              cancelled              = 2
              insert_into_corr_error = 3
              OTHERS                 = 4 ##SUBRC_OK.
        CATCH cx_sy_dyn_call_param_not_found.
          CALL FUNCTION 'RS_WORKING_OBJECTS_ACTIVATE'
            EXPORTING
              activate_ddic_objects  = iv_ddic
              with_popup             = lv_popup
            TABLES
              objects                = gt_objects
            EXCEPTIONS
              excecution_error       = 1
              cancelled              = 2
              insert_into_corr_error = 3
              OTHERS                 = 4 ##SUBRC_OK.
      ENDTRY.
      CASE sy-subrc.
        WHEN 1 OR 3 OR 4.
          zcx_abapgit_exception=>raise_t100( ).
        WHEN 2.
          zcx_abapgit_exception=>raise( 'Activation cancelled. Check the inactive objects.' ).
      ENDCASE.

    ENDIF.

  ENDMETHOD.

  METHOD add.

* function group SEWORKINGAREA
* function module RS_INSERT_INTO_WORKING_AREA
* class CL_WB_ACTIVATION_WORK_AREA

    FIELD-SYMBOLS: <ls_object> TYPE dwinactiv.

    IF iv_type = 'CLAS'.
      APPEND iv_name TO gt_classes.
    ELSE.
      APPEND INITIAL LINE TO gt_objects ASSIGNING <ls_object>.
      <ls_object>-object     = iv_type.
      <ls_object>-obj_name   = iv_name.
      <ls_object>-delet_flag = iv_delete.
    ENDIF.

  ENDMETHOD.

  METHOD add_item.
    add( iv_type = is_item-obj_type
         iv_name = is_item-obj_name ).
  ENDMETHOD.

  METHOD clear.
    CLEAR gt_objects.
    CLEAR gt_classes.
  ENDMETHOD.

  METHOD show_activation_errors.

    DATA: lt_lines      TYPE STANDARD TABLE OF trlog,
          lv_logname_db TYPE ddprh-protname,
          li_log        TYPE REF TO zif_abapgit_log.

    FIELD-SYMBOLS: <ls_line> LIKE LINE OF lt_lines.

    lv_logname_db = iv_logname.

    CALL FUNCTION 'TR_READ_LOG'
      EXPORTING
        iv_log_type   = 'DB'
        iv_logname_db = lv_logname_db
      TABLES
        et_lines      = lt_lines
      EXCEPTIONS
        invalid_input = 1
        access_error  = 2
        OTHERS        = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from TR_READ_LOG' ).
    ENDIF.

    DELETE lt_lines WHERE severity <> 'E'.

    CREATE OBJECT li_log TYPE zcl_abapgit_log.

    LOOP AT lt_lines ASSIGNING <ls_line>.
      li_log->add( <ls_line>-line ).
    ENDLOOP.

    IF li_log->count( ) > 0.
      zcl_abapgit_log_viewer=>show_log( iv_header_text = 'Activation Errors'
                                        ii_log         = li_log ).
    ENDIF.

  ENDMETHOD.

  METHOD update_where_used.

    DATA: lv_class    LIKE LINE OF gt_classes,
          lo_cross    TYPE REF TO cl_wb_crossreference,
          lv_include  TYPE programm,
          li_progress TYPE REF TO zif_abapgit_progress.

    li_progress = zcl_abapgit_progress=>get_instance( lines( gt_classes ) ).

    LOOP AT gt_classes INTO lv_class.
      IF sy-tabix MOD 20 = 0.
        li_progress->show(
          iv_current = sy-tabix
          iv_text    = 'Updating where-used lists' ).
      ENDIF.

      lv_include = cl_oo_classname_service=>get_classpool_name( lv_class ).

      CREATE OBJECT lo_cross
        EXPORTING
          p_name    = lv_include
          p_include = lv_include.

      lo_cross->index_actualize( ).
    ENDLOOP.

  ENDMETHOD.

  METHOD use_new_activation_logic.

    CALL FUNCTION 'FUNCTION_EXISTS'
      EXPORTING
        funcname           = 'DD_MASS_ACT_C3'
      EXCEPTIONS
        function_not_exist = 1
        OTHERS             = 2.
    IF sy-subrc = 0.
      rv_use_new_activation_logic = abap_true.
    ENDIF.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_objects_activation DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS add
      IMPORTING
        !iv_type   TYPE trobjtype
        !iv_name   TYPE clike
        !iv_delete TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS add_item
      IMPORTING
        !is_item TYPE zif_abapgit_definitions=>ty_item
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS activate
      IMPORTING
        !iv_ddic TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS clear .
  PROTECTED SECTION.
  PRIVATE SECTION.

    CLASS-DATA:
      gt_classes TYPE STANDARD TABLE OF seoclsname WITH DEFAULT KEY .
    CLASS-DATA:
      gt_objects TYPE TABLE OF dwinactiv .

    CLASS-METHODS update_where_used .
    CLASS-METHODS use_new_activation_logic
      RETURNING
        VALUE(rv_use_new_activation_logic) TYPE abap_bool .
    CLASS-METHODS activate_new
      IMPORTING
        !iv_ddic TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS activate_old
      IMPORTING
        !iv_ddic TYPE abap_bool DEFAULT abap_false
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS activate_ddic
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS show_activation_errors
      IMPORTING
        !iv_logname TYPE ddmass-logname
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS is_ddic_type
      IMPORTING
        !iv_obj_type     TYPE trobjtype
      RETURNING
        VALUE(rv_result) TYPE abap_bool .
ENDCLASS.

CLASS zcl_abapgit_objects_activation IMPLEMENTATION.

  METHOD activate.

    IF use_new_activation_logic( ) = abap_true.
      activate_new( iv_ddic ).
    ELSE.
      activate_old( iv_ddic ).
    ENDIF.

    update_where_used( ).

  ENDMETHOD.

  METHOD activate_ddic.

    DATA: lt_gentab     TYPE STANDARD TABLE OF dcgentb,
          lv_rc         TYPE sy-subrc,
          ls_gentab     LIKE LINE OF lt_gentab,
          lt_deltab     TYPE STANDARD TABLE OF dcdeltb,
          lt_action_tab TYPE STANDARD TABLE OF dctablres,
          lv_logname    TYPE ddmass-logname.

    FIELD-SYMBOLS: <ls_object> LIKE LINE OF gt_objects.

    LOOP AT gt_objects ASSIGNING <ls_object>.
      " Filter types supported by mass activation
      IF is_ddic_type( <ls_object>-object ) = abap_false.
        CONTINUE.
      ENDIF.
      ls_gentab-tabix = sy-tabix.
      ls_gentab-type = <ls_object>-object.
      ls_gentab-name = <ls_object>-obj_name.
      IF ls_gentab-type = 'INDX' OR ls_gentab-type = 'XINX' OR ls_gentab-type = 'MCID'.
        CALL FUNCTION 'DD_E071_TO_DD'
          EXPORTING
            object   = <ls_object>-object
            obj_name = <ls_object>-obj_name
          IMPORTING
            name     = ls_gentab-name
            id       = ls_gentab-indx.
      ENDIF.
      INSERT ls_gentab INTO TABLE lt_gentab.
    ENDLOOP.

    IF lt_gentab IS NOT INITIAL.

      lv_logname = |ABAPGIT_{ sy-datum }_{ sy-uzeit }|.

      CALL FUNCTION 'DD_MASS_ACT_C3'
        EXPORTING
          ddmode         = 'O'
          medium         = 'T' " transport order
          device         = 'T' " saves to table DDRPH?
          version        = 'M' " activate newest
          logname        = lv_logname
          write_log      = abap_true
          log_head_tail  = abap_true
          t_on           = space
          prid           = 1
        IMPORTING
          act_rc         = lv_rc
        TABLES
          gentab         = lt_gentab
          deltab         = lt_deltab
          cnvtab         = lt_action_tab
        EXCEPTIONS
          access_failure = 1
          no_objects     = 2
          locked         = 3
          internal_error = 4
          OTHERS         = 5.

      IF sy-subrc <> 0.
        zcx_abapgit_exception=>raise( 'error from DD_MASS_ACT_C3' ).
      ENDIF.

      IF lv_rc > 0.
        show_activation_errors( lv_logname ).
      ENDIF.

      " Remove objects from activation queue to avoid double activation in activate_old
      LOOP AT lt_gentab INTO ls_gentab.
        DELETE gt_objects WHERE object = ls_gentab-type AND obj_name = ls_gentab-name.
      ENDLOOP.
      DELETE gt_objects WHERE object = 'INDX' OR object = 'XINX' OR object = 'MCID'.

    ENDIF.

  ENDMETHOD.

  METHOD activate_new.

    DATA: li_progress TYPE REF TO zif_abapgit_progress.

    IF gt_objects IS INITIAL.
      RETURN.
    ENDIF.

    li_progress = zcl_abapgit_progress=>get_instance( 100 ).

    IF iv_ddic = abap_true.

      li_progress->show( iv_current = 98
                         iv_text    = 'Activating DDIC' ).

      activate_ddic( ).

    ELSE.

      li_progress->show( iv_current = 98
                         iv_text    = 'Activating non DDIC' ).

      activate_old( ).

    ENDIF.

  ENDMETHOD.

  METHOD activate_old.

    DATA: lv_popup TYPE abap_bool,
          lv_no_ui TYPE abap_bool.

    IF gt_objects IS NOT INITIAL.

      IF zcl_abapgit_ui_factory=>get_gui_functions( )->gui_is_available( ) = abap_true.
        IF zcl_abapgit_persist_settings=>get_instance( )->read( )->get_activate_wo_popup( ) = abap_true.
          lv_popup = abap_false.
        ELSE.
          lv_popup = abap_true.
        ENDIF.
      ELSE.
        lv_popup = abap_false.
      ENDIF.

      lv_no_ui = boolc( lv_popup = abap_false ).

      TRY.
          CALL FUNCTION 'RS_WORKING_OBJECTS_ACTIVATE'
            EXPORTING
              activate_ddic_objects  = iv_ddic
              with_popup             = lv_popup
              ui_decoupled           = lv_no_ui
            TABLES
              objects                = gt_objects
            EXCEPTIONS
              excecution_error       = 1
              cancelled              = 2
              insert_into_corr_error = 3
              OTHERS                 = 4 ##SUBRC_OK.
        CATCH cx_sy_dyn_call_param_not_found.
          CALL FUNCTION 'RS_WORKING_OBJECTS_ACTIVATE'
            EXPORTING
              activate_ddic_objects  = iv_ddic
              with_popup             = lv_popup
            TABLES
              objects                = gt_objects
            EXCEPTIONS
              excecution_error       = 1
              cancelled              = 2
              insert_into_corr_error = 3
              OTHERS                 = 4 ##SUBRC_OK.
      ENDTRY.
      CASE sy-subrc.
        WHEN 1 OR 3 OR 4.
          zcx_abapgit_exception=>raise_t100( ).
        WHEN 2.
          zcx_abapgit_exception=>raise( 'Activation cancelled. Check the inactive objects.' ).
      ENDCASE.

    ENDIF.

  ENDMETHOD.

  METHOD add.

* function group SEWORKINGAREA
* function module RS_INSERT_INTO_WORKING_AREA
* class CL_WB_ACTIVATION_WORK_AREA

    FIELD-SYMBOLS: <ls_object> TYPE dwinactiv.

    IF iv_type = 'CLAS'.
      APPEND iv_name TO gt_classes.
    ELSE.
      APPEND INITIAL LINE TO gt_objects ASSIGNING <ls_object>.
      <ls_object>-object     = iv_type.
      <ls_object>-obj_name   = iv_name.
      <ls_object>-delet_flag = iv_delete.
    ENDIF.

  ENDMETHOD.

  METHOD add_item.
    add( iv_type = is_item-obj_type
         iv_name = is_item-obj_name ).
  ENDMETHOD.

  METHOD clear.
    CLEAR gt_objects.
    CLEAR gt_classes.
  ENDMETHOD.

  METHOD is_ddic_type.

    " Determine if object can be handled by mass activation (see RADMASUTC form ma_tab_check)

    CONSTANTS:
      lc_domain     TYPE c LENGTH 9  VALUE 'DOMA DOMD',
      lc_types      TYPE c LENGTH 50 VALUE 'DTEL DTED TABL TABD SQLT SQLD TTYP TTYD VIEW VIED',
      lc_technset   TYPE c LENGTH 24 VALUE 'TABT VIET SQTT INDX XINX',
      lc_f4_objects TYPE c LENGTH 35 VALUE 'SHLP SHLD MCOB MCOD MACO MACD MCID',
      lc_enqueue    TYPE c LENGTH 9  VALUE 'ENQU ENQD',
      lc_sqsc       TYPE c LENGTH 4  VALUE 'SQSC',
      lc_stob       TYPE c LENGTH 4  VALUE 'STOB',
      lc_ntab       TYPE c LENGTH 14 VALUE 'NTTT NTTB NTDT',
      lc_ddls       TYPE c LENGTH 4  VALUE 'DDLS',
      lc_switches   TYPE c LENGTH 24 VALUE 'SF01 SF02 SFSW SFBS SFBF',
      lc_enhd       TYPE c LENGTH 4  VALUE 'ENHD'.

    rv_result = abap_true.
    IF lc_domain   NS iv_obj_type AND lc_types      NS iv_obj_type AND
       lc_technset NS iv_obj_type AND lc_f4_objects NS iv_obj_type AND
       lc_enqueue  NS iv_obj_type AND lc_sqsc       NS iv_obj_type AND
       lc_stob     NS iv_obj_type AND lc_ntab       NS iv_obj_type AND
       lc_ddls     NS iv_obj_type AND
       lc_switches NS iv_obj_type AND iv_obj_type <> lc_enhd.
      rv_result = abap_false.
    ENDIF.

  ENDMETHOD.

  METHOD show_activation_errors.

    DATA: lt_lines      TYPE STANDARD TABLE OF trlog,
          lv_logname_db TYPE ddprh-protname,
          li_log        TYPE REF TO zif_abapgit_log.

    FIELD-SYMBOLS: <ls_line> LIKE LINE OF lt_lines.

    lv_logname_db = iv_logname.

    CALL FUNCTION 'TR_READ_LOG'
      EXPORTING
        iv_log_type   = 'DB'
        iv_logname_db = lv_logname_db
      TABLES
        et_lines      = lt_lines
      EXCEPTIONS
        invalid_input = 1
        access_error  = 2
        OTHERS        = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from TR_READ_LOG' ).
    ENDIF.

    DELETE lt_lines WHERE severity <> 'E'.

    CREATE OBJECT li_log TYPE zcl_abapgit_log.

    LOOP AT lt_lines ASSIGNING <ls_line>.
      li_log->add( <ls_line>-line ).
    ENDLOOP.

    IF li_log->count( ) > 0.
      zcl_abapgit_log_viewer=>show_log( iv_header_text = 'Activation Errors'
                                        ii_log         = li_log ).
    ENDIF.

  ENDMETHOD.

  METHOD update_where_used.

    DATA: lv_class    LIKE LINE OF gt_classes,
          lo_cross    TYPE REF TO cl_wb_crossreference,
          lv_include  TYPE programm,
          li_progress TYPE REF TO zif_abapgit_progress.

    li_progress = zcl_abapgit_progress=>get_instance( lines( gt_classes ) ).

    LOOP AT gt_classes INTO lv_class.
      IF sy-tabix MOD 20 = 0.
        li_progress->show(
          iv_current = sy-tabix
          iv_text    = 'Updating where-used lists' ).
      ENDIF.

      lv_include = cl_oo_classname_service=>get_classpool_name( lv_class ).

      CREATE OBJECT lo_cross
        EXPORTING
          p_name    = lv_include
          p_include = lv_include.

      lo_cross->index_actualize( ).
    ENDLOOP.

  ENDMETHOD.

  METHOD use_new_activation_logic.

    CALL FUNCTION 'FUNCTION_EXISTS'
      EXPORTING
        funcname           = 'DD_MASS_ACT_C3'
      EXCEPTIONS
        function_not_exist = 1
        OTHERS             = 2.
    IF sy-subrc = 0.
      rv_use_new_activation_logic = abap_true.
    ENDIF.

  ENDMETHOD.
ENDCLASS.

Fix DDIC activation issues (#4111)

Fix DDIC activation issues (#4111)

* Fix DDIC activation issues

- Avoid double activation of DDIC objects in case of "LATE" processing
- Derive DDIC id for XINX and MCID (same as for INDX)

Closes #4103

* Lint

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


CLASS zcl_abapgit_object_para DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES zif_abapgit_object.
    ALIASES mo_files FOR zif_abapgit_object~mo_files.

ENDCLASS.

CLASS zcl_abapgit_object_para IMPLEMENTATION.

  METHOD zif_abapgit_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.
* looks like "changed by user" is not stored in the database
    rv_user = c_user_unknown.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
* Data elements can refer to PARA objects
    rs_metadata-ddic = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA: lv_paramid TYPE tpara-paramid.

    SELECT SINGLE paramid FROM tpara INTO lv_paramid
      WHERE paramid = ms_item-obj_name.                 "#EC CI_GENBUFF
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: ls_tpara  TYPE tpara,
          ls_tparat TYPE tparat.

    SELECT SINGLE * FROM tpara INTO ls_tpara
      WHERE paramid = ms_item-obj_name.                 "#EC CI_GENBUFF
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    SELECT SINGLE * FROM tparat INTO ls_tparat
      WHERE paramid = ms_item-obj_name
      AND sprache = mv_language.          "#EC CI_GENBUFF "#EC CI_SUBRC

    io_xml->add( iv_name = 'TPARA'
                 ig_data = ls_tpara ).
    io_xml->add( iv_name = 'TPARAT'
                 ig_data = ls_tparat ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.
* see fm RS_PARAMETER_ADD and RS_PARAMETER_EDIT

    DATA: lv_mode   TYPE c LENGTH 1,
          ls_tpara  TYPE tpara,
          ls_tparat TYPE tparat.

    SELECT SINGLE * FROM tpara INTO ls_tpara
      WHERE paramid = ms_item-obj_name.                 "#EC CI_GENBUFF
    IF sy-subrc = 0.
      lv_mode = 'M'.
    ELSE.
      lv_mode = 'I'.
    ENDIF.

    io_xml->read( EXPORTING iv_name = 'TPARA'
                  CHANGING cg_data = ls_tpara ).
    io_xml->read( EXPORTING iv_name = 'TPARAT'
                  CHANGING cg_data = ls_tparat ).

    CALL FUNCTION 'RS_CORR_INSERT'
      EXPORTING
        object              = ms_item-obj_name
        object_class        = 'PARA'
        mode                = lv_mode
        global_lock         = abap_true
        devclass            = iv_package
        master_language     = mv_language
      EXCEPTIONS
        cancelled           = 1
        permission_failure  = 2
        unknown_objectclass = 3
        OTHERS              = 4.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from RS_CORR_INSERT, PARA' ).
    ENDIF.

    MODIFY tpara FROM ls_tpara.                           "#EC CI_SUBRC
    ASSERT sy-subrc = 0.

    MODIFY tparat FROM ls_tparat.                         "#EC CI_SUBRC
    ASSERT sy-subrc = 0.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    " We can't use FM RS_PARAMETER_DELETE because of the popup to confirm
    "Therefore we have to reimplement most of the FMs logic

    DATA: lv_paramid   TYPE tpara-paramid,
          ls_transpkey TYPE trkey.

    lv_paramid = ms_item-obj_name.

    CALL FUNCTION 'RS_ACCESS_PERMISSION'
      EXPORTING
        global_lock              = abap_true
        language_upd_exit        = 'RS_PARAMETER_LANGUAGE_EXIT'    " Name FuBa for maintenance language change
        object                   = lv_paramid
        object_class             = ms_item-obj_type
        suppress_language_check  = space
      EXCEPTIONS
        canceled_in_corr         = 1
        enqueued_by_user         = 2
        enqueue_system_failure   = 3
        illegal_parameter_values = 4
        locked_by_author         = 5
        no_modify_permission     = 6
        no_show_permission       = 7
        permission_failure       = 8
        request_language_denied  = 9
        OTHERS                   = 10.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from RS_PRAMETER_DELETE' ).
    ENDIF.

    SELECT COUNT(*) FROM cross WHERE ( type = 'P' OR
                               type = 'Q' )
                              AND name   = lv_paramid.
    IF sy-subrc = 0.
      zcx_abapgit_exception=>raise( 'PARA: Parameter is still used' ).
    ELSE.
      SELECT COUNT(*) FROM dd04l BYPASSING BUFFER
      WHERE  memoryid = lv_paramid
      AND as4local = 'A'.
      IF sy-subrc = 0.
        zcx_abapgit_exception=>raise( 'PARA: Parameter is still used' ).
      ENDIF.
    ENDIF.
    CALL FUNCTION 'RS_CORR_INSERT'
      EXPORTING
        global_lock         = abap_true
        object              = lv_paramid
        object_class        = 'PARA'
        mode                = 'D'
      IMPORTING
        transport_key       = ls_transpkey
      EXCEPTIONS
        cancelled           = 01
        permission_failure  = 02
        unknown_objectclass = 03.

    IF sy-subrc = 0.
      DELETE FROM tpara WHERE paramid = lv_paramid.
      DELETE FROM tparat WHERE paramid = lv_paramid.

      IF sy-subrc = 0.
        CALL FUNCTION 'RS_TREE_OBJECT_PLACEMENT'
          EXPORTING
            object    = lv_paramid
            operation = 'DELETE'
            type      = 'CR'.
      ENDIF.
    ELSE.
      zcx_abapgit_exception=>raise( 'error from RS_PRAMETER_DELETE' ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = 'PARA'
        in_new_window = abap_true.

  ENDMETHOD.

  METHOD zif_abapgit_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = abap_false.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_active.
    rv_active = is_active( ).
  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_object_para DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES zif_abapgit_object.
    ALIASES mo_files FOR zif_abapgit_object~mo_files.

ENDCLASS.

CLASS zcl_abapgit_object_para IMPLEMENTATION.

  METHOD zif_abapgit_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.
* looks like "changed by user" is not stored in the database
    rv_user = c_user_unknown.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
* Data elements can refer to PARA objects
    rs_metadata-ddic = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA: lv_paramid TYPE tpara-paramid.

    SELECT SINGLE paramid FROM tpara INTO lv_paramid
      WHERE paramid = ms_item-obj_name.                 "#EC CI_GENBUFF
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: ls_tpara  TYPE tpara,
          ls_tparat TYPE tparat.

    SELECT SINGLE * FROM tpara INTO ls_tpara
      WHERE paramid = ms_item-obj_name.                 "#EC CI_GENBUFF
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    SELECT SINGLE * FROM tparat INTO ls_tparat
      WHERE paramid = ms_item-obj_name
      AND sprache = mv_language.          "#EC CI_GENBUFF "#EC CI_SUBRC

    io_xml->add( iv_name = 'TPARA'
                 ig_data = ls_tpara ).
    io_xml->add( iv_name = 'TPARAT'
                 ig_data = ls_tparat ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.
* see fm RS_PARAMETER_ADD and RS_PARAMETER_EDIT

    DATA: lv_mode   TYPE c LENGTH 1,
          ls_tpara  TYPE tpara,
          ls_tparat TYPE tparat.

    SELECT SINGLE * FROM tpara INTO ls_tpara
      WHERE paramid = ms_item-obj_name.                 "#EC CI_GENBUFF
    IF sy-subrc = 0.
      lv_mode = 'M'.
    ELSE.
      lv_mode = 'I'.
    ENDIF.

    io_xml->read( EXPORTING iv_name = 'TPARA'
                  CHANGING cg_data = ls_tpara ).
    io_xml->read( EXPORTING iv_name = 'TPARAT'
                  CHANGING cg_data = ls_tparat ).

    CALL FUNCTION 'RS_CORR_INSERT'
      EXPORTING
        object              = ms_item-obj_name
        object_class        = 'PARA'
        mode                = lv_mode
        global_lock         = abap_true
        devclass            = iv_package
        master_language     = mv_language
      EXCEPTIONS
        cancelled           = 1
        permission_failure  = 2
        unknown_objectclass = 3
        OTHERS              = 4.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from RS_CORR_INSERT, PARA' ).
    ENDIF.

    MODIFY tpara FROM ls_tpara.                           "#EC CI_SUBRC
    ASSERT sy-subrc = 0.

    MODIFY tparat FROM ls_tparat.                         "#EC CI_SUBRC
    ASSERT sy-subrc = 0.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    " We can't use FM RS_PARAMETER_DELETE because of the popup to confirm
    "Therefore we have to reimplement most of the FMs logic

    DATA: lv_paramid   TYPE tpara-paramid,
          ls_transpkey TYPE trkey.

    lv_paramid = ms_item-obj_name.

    CALL FUNCTION 'RS_ACCESS_PERMISSION'
      EXPORTING
        global_lock              = abap_true
        language_upd_exit        = 'RS_PARAMETER_LANGUAGE_EXIT'    " Name FuBa for maintenance language change
        object                   = lv_paramid
        object_class             = ms_item-obj_type
        suppress_language_check  = space
      EXCEPTIONS
        canceled_in_corr         = 1
        enqueued_by_user         = 2
        enqueue_system_failure   = 3
        illegal_parameter_values = 4
        locked_by_author         = 5
        no_modify_permission     = 6
        no_show_permission       = 7
        permission_failure       = 8
        request_language_denied  = 9
        OTHERS                   = 10.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |error from RS_ACCESS_PERMISSION. SUBRC={ sy-subrc }| ).
    ENDIF.

    SELECT COUNT(*) FROM cross WHERE ( type = 'P' OR
                               type = 'Q' )
                              AND name   = lv_paramid.
    IF sy-subrc = 0.
      zcx_abapgit_exception=>raise( 'PARA: Parameter is still used' ).
    ELSE.
      SELECT COUNT(*) FROM dd04l BYPASSING BUFFER
      WHERE  memoryid = lv_paramid
      AND as4local = 'A'.
      IF sy-subrc = 0.
        zcx_abapgit_exception=>raise( 'PARA: Parameter is still used' ).
      ENDIF.
    ENDIF.
    CALL FUNCTION 'RS_CORR_INSERT'
      EXPORTING
        global_lock         = abap_true
        object              = lv_paramid
        object_class        = 'PARA'
        mode                = 'D'
      IMPORTING
        transport_key       = ls_transpkey
      EXCEPTIONS
        cancelled           = 01
        permission_failure  = 02
        unknown_objectclass = 03.

    IF sy-subrc = 0.
      DELETE FROM tpara WHERE paramid = lv_paramid.
      DELETE FROM tparat WHERE paramid = lv_paramid.

      IF sy-subrc = 0.
        CALL FUNCTION 'RS_TREE_OBJECT_PLACEMENT'
          EXPORTING
            object    = lv_paramid
            operation = 'DELETE'
            type      = 'CR'.
      ENDIF.
    ELSE.
      zcx_abapgit_exception=>raise( 'error from RS_CORR_INSERT' ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = 'PARA'
        in_new_window = abap_true.

  ENDMETHOD.

  METHOD zif_abapgit_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE zcl_abapgit_comparison_null.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = abap_false.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_active.
    rv_active = is_active( ).
  ENDMETHOD.
ENDCLASS.

fix error handling

PARA: fix error handling


REPORT zags_migration_01.
* Migration, add REPO key in ZAGS_OBJECTS, old data is not deleted

DATA: gt_objects TYPE zags_objects_tt.

START-OF-SELECTION.
  PERFORM run.

CLASS lcl_visitor DEFINITION FINAL.

  PUBLIC SECTION.
    CLASS-METHODS: visit
      IMPORTING it_sha1        TYPE zags_sha1_tt
      RETURNING VALUE(rt_sha1) TYPE zags_sha1_tt.

ENDCLASS.

CLASS lcl_visitor IMPLEMENTATION.

  METHOD visit.

    DATA: ls_commit TYPE zcl_ags_obj_commit=>ty_commit,
          lt_tree   TYPE zcl_ags_obj_tree=>ty_tree_tt.

    FIELD-SYMBOLS: <lv_sha1>   LIKE LINE OF it_sha1,
                   <ls_tree>   LIKE LINE OF lt_tree,
                   <ls_object> LIKE LINE OF gt_objects.

    rt_sha1 = it_sha1.

    LOOP AT rt_sha1 ASSIGNING <lv_sha1>.
      READ TABLE gt_objects WITH KEY
        repo = '' sha1 = <lv_sha1>
        ASSIGNING <ls_object>.
      ASSERT sy-subrc = 0.

      CASE <ls_object>-type.
        WHEN zif_ags_constants=>c_type-tree.
          CALL METHOD ('\PROGRAM=ZABAPGIT\CLASS=LCL_GIT_PACK')=>decode_tree
            EXPORTING
              iv_data  = <ls_object>-data_raw
            RECEIVING
              rt_nodes = lt_tree.
          LOOP AT lt_tree ASSIGNING <ls_tree>.
            APPEND <ls_tree>-sha1 TO rt_sha1.
          ENDLOOP.
        WHEN zif_ags_constants=>c_type-commit.
          CALL METHOD ('\PROGRAM=ZABAPGIT\CLASS=LCL_GIT_PACK')=>decode_commit
            EXPORTING
              iv_data   = <ls_object>-data_raw
            RECEIVING
              rs_commit = ls_commit.
          IF NOT ls_commit-parent IS INITIAL.
            APPEND ls_commit-parent TO rt_sha1.
          ENDIF.
          IF NOT ls_commit-parent2 IS INITIAL.
            APPEND ls_commit-parent2 TO rt_sha1.
          ENDIF.
          APPEND ls_commit-tree TO rt_sha1.
        WHEN zif_ags_constants=>c_type-blob.
          CONTINUE.
        WHEN OTHERS.
          ASSERT 0 = 1.
      ENDCASE.

    ENDLOOP.

  ENDMETHOD.

ENDCLASS.

FORM run RAISING zcx_ags_error.

  DATA: lt_repos    TYPE zags_repos_tt,
        lt_sha1     TYPE zags_sha1_tt,
        lt_result   TYPE zags_sha1_tt,
        lt_branches TYPE zcl_ags_repo=>ty_branches_tt.

  FIELD-SYMBOLS: <ls_repo>   LIKE LINE OF lt_repos,
                 <lo_branch> LIKE LINE OF lt_branches.

  gt_objects = zcl_ags_db=>get_objects( )->list( ).

  lt_repos = zcl_ags_repo=>list( ).

  LOOP AT lt_repos ASSIGNING <ls_repo>.
    CLEAR lt_sha1.

    lt_branches = zcl_ags_repo=>get_instance( <ls_repo>-name )->list_branches( ).
    LOOP AT lt_branches ASSIGNING <lo_branch>.
      APPEND <lo_branch>->get_data( )-sha1 TO lt_sha1.
    ENDLOOP.

    CLEAR lt_result.
    lt_result = lcl_visitor=>visit( lt_sha1 ).
    PERFORM save USING <ls_repo>-repo lt_result.
  ENDLOOP.

  WRITE: / 'Done'(001).

ENDFORM.

FORM save USING pv_repo TYPE zags_repos-repo
                pt_sha1 TYPE zags_sha1_tt.

  DATA: ls_object TYPE zags_objects.

  FIELD-SYMBOLS: <lv_sha1>   LIKE LINE OF pt_sha1,
                 <ls_object> LIKE LINE OF gt_objects.

  SORT pt_sha1 ASCENDING.
  DELETE ADJACENT DUPLICATES FROM pt_sha1.

  ASSERT NOT pv_repo IS INITIAL.

  LOOP AT pt_sha1 ASSIGNING <lv_sha1>.
    READ TABLE gt_objects ASSIGNING <ls_object>
      WITH KEY repo = '' sha1 = <lv_sha1>.
    ASSERT sy-subrc = 0.

* note that in the old setup an object could be shared between repos
    CLEAR ls_object.
    ls_object = <ls_object>.
    ls_object-repo = pv_repo.

    zcl_ags_db=>get_objects( )->modify( ls_object ).
  ENDLOOP.

ENDFORM.

REPORT zags_migration_01.
* Migration, add REPO key in ZAGS_OBJECTS, old data is not deleted

DATA: gt_objects TYPE zags_objects_tt.

START-OF-SELECTION.
  PERFORM run.

CLASS lcl_visitor DEFINITION FINAL.

  PUBLIC SECTION.
    CLASS-METHODS: visit
      IMPORTING it_sha1        TYPE zags_sha1_tt
      RETURNING VALUE(rt_sha1) TYPE zags_sha1_tt
      RAISING   zcx_abapgit_exception.

ENDCLASS.

CLASS lcl_visitor IMPLEMENTATION.

  METHOD visit.

    DATA: ls_commit TYPE zcl_ags_obj_commit=>ty_commit,
          lt_tree   TYPE zcl_ags_obj_tree=>ty_tree_tt.

    FIELD-SYMBOLS: <lv_sha1>   LIKE LINE OF it_sha1,
                   <ls_tree>   LIKE LINE OF lt_tree,
                   <ls_object> LIKE LINE OF gt_objects.

    rt_sha1 = it_sha1.

    LOOP AT rt_sha1 ASSIGNING <lv_sha1>.
      READ TABLE gt_objects WITH KEY
        repo = '' sha1 = <lv_sha1>
        ASSIGNING <ls_object>.
      IF sy-subrc <> 0.
        CONTINUE.
      ENDIF.

      CASE <ls_object>-type.
        WHEN zif_ags_constants=>c_type-tree.
          lt_tree = zcl_abapgit_git_pack=>decode_tree( <ls_object>-data_raw ).
          LOOP AT lt_tree ASSIGNING <ls_tree>.
            APPEND <ls_tree>-sha1 TO rt_sha1.
          ENDLOOP.
        WHEN zif_ags_constants=>c_type-commit.
          ls_commit = zcl_abapgit_git_pack=>decode_commit( <ls_object>-data_raw ).
          IF NOT ls_commit-parent IS INITIAL.
            APPEND ls_commit-parent TO rt_sha1.
          ENDIF.
          IF NOT ls_commit-parent2 IS INITIAL.
            APPEND ls_commit-parent2 TO rt_sha1.
          ENDIF.
          APPEND ls_commit-tree TO rt_sha1.
        WHEN zif_ags_constants=>c_type-blob.
          CONTINUE.
        WHEN OTHERS.
          ASSERT 0 = 1.
      ENDCASE.

    ENDLOOP.

  ENDMETHOD.

ENDCLASS.

FORM run RAISING zcx_ags_error zcx_abapgit_exception.

  DATA: lt_repos    TYPE zags_repos_tt,
        lt_sha1     TYPE zags_sha1_tt,
        lt_result   TYPE zags_sha1_tt,
        lt_branches TYPE zcl_ags_repo=>ty_branches_tt.

  FIELD-SYMBOLS: <ls_repo>   LIKE LINE OF lt_repos,
                 <lo_branch> LIKE LINE OF lt_branches.

  gt_objects = zcl_ags_db=>get_objects( )->list( ).

  lt_repos = zcl_ags_repo=>list( ).

  LOOP AT lt_repos ASSIGNING <ls_repo>.
    CLEAR lt_sha1.

    lt_branches = zcl_ags_repo=>get_instance( <ls_repo>-name )->list_branches( ).
    LOOP AT lt_branches ASSIGNING <lo_branch>.
      APPEND <lo_branch>->get_data( )-sha1 TO lt_sha1.
    ENDLOOP.

    CLEAR lt_result.
    lt_result = lcl_visitor=>visit( lt_sha1 ).
    PERFORM save USING <ls_repo>-repo lt_result.
  ENDLOOP.

  WRITE: / 'Done'(001).

ENDFORM.

FORM save USING pv_repo TYPE zags_repos-repo
                pt_sha1 TYPE zags_sha1_tt.

  DATA: ls_object TYPE zags_objects.

  FIELD-SYMBOLS: <lv_sha1>   LIKE LINE OF pt_sha1,
                 <ls_object> LIKE LINE OF gt_objects.

  SORT pt_sha1 ASCENDING.
  DELETE ADJACENT DUPLICATES FROM pt_sha1.

  ASSERT NOT pv_repo IS INITIAL.

  LOOP AT pt_sha1 ASSIGNING <lv_sha1>.
    READ TABLE gt_objects ASSIGNING <ls_object>
      WITH KEY repo = '' sha1 = <lv_sha1>.
    IF sy-subrc <> 0.
      CONTINUE.
    ENDIF.

* note that in the old setup an object could be shared between repos
    CLEAR ls_object.
    ls_object = <ls_object>.
    ls_object-repo = pv_repo.

    zcl_ags_db=>get_objects( )->modify( ls_object ).
  ENDLOOP.

ENDFORM.

fix #102

fix #102


CLASS ltcl_transport_objects DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    METHODS:
      add_new_to_local_files         FOR TESTING RAISING cx_static_check,
      modified_to_new_local_files    FOR TESTING RAISING cx_static_check,
      transport_not_in_repository    FOR TESTING RAISING cx_static_check,
      object_not_in_local_files      FOR TESTING RAISING cx_static_check,
      cant_be_added_with_del_flag    FOR TESTING RAISING cx_static_check,
      cant_be_modified_with_del_flag FOR TESTING RAISING cx_static_check,
      deleted_to_removed_files       FOR TESTING RAISING cx_static_check,
      shouldnt_remove_no_delflag FOR TESTING RAISING cx_static_check,
      should_add_all_local_files FOR TESTING RAISING cx_static_check,
      should_delete_all_related  FOR TESTING RAISING cx_static_check,
      setup,
      given_the_transport_object
        IMPORTING iv_obj_name TYPE string
                  iv_obj_type TYPE string
                  iv_delflag  TYPE abap_bool OPTIONAL,
      given_the_object_status
        IMPORTING
          iv_obj_name TYPE string OPTIONAL
          iv_obj_type TYPE string OPTIONAL
          iv_filename TYPE string OPTIONAL
          iv_path     TYPE string OPTIONAL
          iv_lstate   TYPE char1,
      given_the_local_file
        IMPORTING iv_obj_name          TYPE string
                  iv_obj_type          TYPE string
                  iv_filename          TYPE string
                  iv_path              TYPE string
                  iv_data              TYPE string
        RETURNING VALUE(rs_local_file) TYPE zif_abapgit_definitions=>ty_file_item,
      when_staging
        RAISING zcx_abapgit_exception,
      then_file_should_be_added
        IMPORTING
          is_local_file TYPE zif_abapgit_definitions=>ty_file_item,
      then_it_should_raise_exception
        IMPORTING
          with_text TYPE string,
      then_it_should_remove_at_stage
        IMPORTING
          iv_filename TYPE string
          iv_path     TYPE string.

    DATA: mo_transport_objects TYPE REF TO zcl_abapgit_transport_objects,
          mt_transport_objects TYPE scts_tadir,
          mt_object_statuses   TYPE zif_abapgit_definitions=>ty_results_tt,
          ms_stage_objects     TYPE zif_abapgit_definitions=>ty_stage_files,
          mo_stage             TYPE REF TO zcl_abapgit_stage.

ENDCLASS.       "ltcl_Transport_Objects

CLASS ltcl_transport_objects IMPLEMENTATION.

  METHOD setup.
    CREATE OBJECT mo_stage
      EXPORTING
        iv_branch_name = 'A_branch_name'
        iv_branch_sha1 = 'Branch_SH1'.
  ENDMETHOD.
  METHOD add_new_to_local_files.
    DATA ls_local_file TYPE zif_abapgit_definitions=>ty_file_item.

    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    ls_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    when_staging( ).

    then_file_should_be_added( ls_local_file ).
  ENDMETHOD.
  METHOD modified_to_new_local_files.
    DATA ls_local_file TYPE zif_abapgit_definitions=>ty_file_item.
    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    ls_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    when_staging( ).

    then_file_should_be_added( ls_local_file ).
  ENDMETHOD.
  METHOD should_add_all_local_files.
    "Not only .abap, but also .xml and other includes
    DATA ls_abap_local_file TYPE zif_abapgit_definitions=>ty_file_item.
    DATA ls_xml_local_file  TYPE zif_abapgit_definitions=>ty_file_item.

    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.xml'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    ls_abap_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    ls_xml_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.xml'
      iv_path     = '/path'
      iv_data     = 'data' ).

    when_staging( ).

    then_file_should_be_added( ls_abap_local_file ).
    then_file_should_be_added( ls_xml_local_file ).
  ENDMETHOD.
  METHOD transport_not_in_repository.
    given_the_transport_object(
      iv_obj_name   = 'CL_A_CLASS_NOT_IN_REPO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    then_it_should_raise_exception(
      with_text = 'Object CL_A_CLASS_NOT_IN_REPO not found in the local repository files' ).
  ENDMETHOD.

  METHOD object_not_in_local_files.

    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    given_the_local_file(
      iv_obj_name = 'CL_ANOTHER_LOCAL_FILE'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    then_it_should_raise_exception(
      with_text = 'Object CL_FOO not found in the local repository files' ).
  ENDMETHOD.

  METHOD cant_be_added_with_del_flag.
    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    then_it_should_raise_exception(
      with_text = 'Object CL_FOO should be added/modified, but has deletion flag in transport' ).
  ENDMETHOD.

  METHOD cant_be_modified_with_del_flag.
    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    then_it_should_raise_exception(
      with_text = 'Object CL_FOO should be added/modified, but has deletion flag in transport' ).
  ENDMETHOD.
  METHOD deleted_to_removed_files.
    given_the_transport_object(
     iv_obj_name   = 'CL_FOO'
     iv_obj_type   = 'CLAS'
     iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    when_staging( ).

    then_it_should_remove_at_stage(
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/a_path' ).
  ENDMETHOD.

  METHOD should_delete_all_related.
    "i.e. Should also delete the XMLs related to the transport objects
    given_the_transport_object(
     iv_obj_name   = 'CL_FOO'
     iv_obj_type   = 'CLAS'
     iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.xml'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    when_staging( ).

    then_it_should_remove_at_stage(
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/a_path' ).

    then_it_should_remove_at_stage(
      iv_filename = 'CL_FOO.xml'
      iv_path     = '/a_path' ).
  ENDMETHOD.

  METHOD shouldnt_remove_no_delflag.
    given_the_transport_object(
       iv_obj_name   = 'CL_FOO'
       iv_obj_type   = 'CLAS'
       iv_delflag    = abap_false ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    then_it_should_raise_exception(
         with_text = 'Object CL_FOO should be removed, but has NO deletion flag in transport' ).
  ENDMETHOD.

  METHOD given_the_transport_object.
    DATA ls_transport_object TYPE tadir.
    ls_transport_object-obj_name = iv_obj_name.
    ls_transport_object-object   = iv_obj_type.
    ls_transport_object-delflag  = iv_delflag.
    APPEND ls_transport_object TO mt_transport_objects.
  ENDMETHOD.

  METHOD given_the_object_status.
    DATA ls_object_status TYPE zif_abapgit_definitions=>ty_result.
    ls_object_status-obj_name = iv_obj_name.
    ls_object_status-obj_type = iv_obj_type.
    ls_object_status-filename = iv_filename.
    ls_object_status-path     = iv_path.
    ls_object_status-lstate   = iv_lstate.
    APPEND ls_object_status  TO mt_object_statuses.
  ENDMETHOD.

  METHOD given_the_local_file.
    rs_local_file-item-obj_name = iv_obj_name.
    rs_local_file-item-obj_type = iv_obj_type.
    rs_local_file-file-filename = iv_filename.
    rs_local_file-file-path     = iv_path.
    rs_local_file-file-data     = iv_data.
    APPEND rs_local_file TO ms_stage_objects-local.
  ENDMETHOD.

  METHOD when_staging.
    CREATE OBJECT mo_transport_objects
      EXPORTING
        it_transport_objects = mt_transport_objects.
    mo_transport_objects->to_stage(
      io_stage           = mo_stage
      is_stage_objects   = ms_stage_objects
      it_object_statuses = mt_object_statuses ).
  ENDMETHOD.

  METHOD then_file_should_be_added.
    DATA: lt_staged_objects TYPE zcl_abapgit_stage=>ty_stage_tt.
    lt_staged_objects = mo_stage->get_all( ).

    READ TABLE lt_staged_objects TRANSPORTING NO FIELDS
    WITH KEY file-filename = is_local_file-file-filename
            file-path      = is_local_file-file-path
            file-data      = is_local_file-file-data
            method         = zcl_abapgit_stage=>c_method-add.
    IF sy-subrc <> 0.
      cl_abap_unit_assert=>fail( |Object { is_local_file-file-filename } not added to stage| ).
    ENDIF.
  ENDMETHOD.

  METHOD then_it_should_raise_exception.
    DATA: lx_exception TYPE REF TO zcx_abapgit_exception.

    TRY.
        when_staging( ).
        cl_abap_unit_assert=>fail( 'Should have raised exception').
      CATCH zcx_abapgit_exception INTO lx_exception.
        cl_abap_unit_assert=>assert_equals(
          act = lx_exception->text
          exp = with_text ).
    ENDTRY.
  ENDMETHOD.

  METHOD then_it_should_remove_at_stage.

    DATA: lt_staged_objects TYPE zcl_abapgit_stage=>ty_stage_tt.

    lt_staged_objects = mo_stage->get_all( ).

    READ TABLE lt_staged_objects TRANSPORTING NO FIELDS
    WITH KEY file-filename  = iv_filename
             file-path      = iv_path.
    IF sy-subrc <> 0.
      cl_abap_unit_assert=>fail( |Object { iv_filename } not removed in stage| ).
    ENDIF.
  ENDMETHOD.

ENDCLASS.

CLASS ltcl_transport_objects DEFINITION FOR TESTING DURATION SHORT RISK LEVEL HARMLESS.

  PRIVATE SECTION.
    METHODS:
      add_new_to_local_files         FOR TESTING RAISING cx_static_check,
      modified_to_new_local_files    FOR TESTING RAISING cx_static_check,
      transport_not_in_repository    FOR TESTING RAISING cx_static_check,
      object_not_in_local_files      FOR TESTING RAISING cx_static_check,
      cant_be_added_with_del_flag    FOR TESTING RAISING cx_static_check,
      cant_be_modified_with_del_flag FOR TESTING RAISING cx_static_check,
      deleted_to_removed_files       FOR TESTING RAISING cx_static_check,
      shouldnt_remove_no_delflag FOR TESTING RAISING cx_static_check,
      should_add_all_local_files FOR TESTING RAISING cx_static_check,
      should_delete_all_related  FOR TESTING RAISING cx_static_check,
      setup,
      given_the_transport_object
        IMPORTING iv_obj_name TYPE string
                  iv_obj_type TYPE string
                  iv_delflag  TYPE abap_bool OPTIONAL,
      given_the_object_status
        IMPORTING
          iv_obj_name TYPE string OPTIONAL
          iv_obj_type TYPE string OPTIONAL
          iv_filename TYPE string OPTIONAL
          iv_path     TYPE string OPTIONAL
          iv_lstate   TYPE char1,
      given_the_local_file
        IMPORTING iv_obj_name          TYPE string
                  iv_obj_type          TYPE string
                  iv_filename          TYPE string
                  iv_path              TYPE string
                  iv_data              TYPE string
        RETURNING VALUE(rs_local_file) TYPE zif_abapgit_definitions=>ty_file_item,
      when_staging
        RAISING zcx_abapgit_exception,
      then_file_should_be_added
        IMPORTING
          is_local_file TYPE zif_abapgit_definitions=>ty_file_item,
      then_it_should_raise_exception
        IMPORTING
          with_text TYPE string,
      then_it_should_remove_at_stage
        IMPORTING
          iv_filename TYPE string
          iv_path     TYPE string.

    DATA: mo_transport_objects TYPE REF TO zcl_abapgit_transport_objects,
          mt_transport_objects TYPE scts_tadir,
          mt_object_statuses   TYPE zif_abapgit_definitions=>ty_results_tt,
          ms_stage_objects     TYPE zif_abapgit_definitions=>ty_stage_files,
          mo_stage             TYPE REF TO zcl_abapgit_stage.

ENDCLASS.       "ltcl_Transport_Objects

CLASS ltcl_transport_objects IMPLEMENTATION.

  METHOD setup.
    CREATE OBJECT mo_stage
      EXPORTING
        iv_branch_name = 'A_branch_name'
        iv_branch_sha1 = 'Branch_SH1'.
  ENDMETHOD.
  METHOD add_new_to_local_files.
    DATA ls_local_file TYPE zif_abapgit_definitions=>ty_file_item.

    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    ls_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    when_staging( ).

    then_file_should_be_added( ls_local_file ).
  ENDMETHOD.
  METHOD modified_to_new_local_files.
    DATA ls_local_file TYPE zif_abapgit_definitions=>ty_file_item.
    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    ls_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    when_staging( ).

    then_file_should_be_added( ls_local_file ).
  ENDMETHOD.
  METHOD should_add_all_local_files.
    "Not only .abap, but also .xml and other includes
    DATA ls_abap_local_file TYPE zif_abapgit_definitions=>ty_file_item.
    DATA ls_xml_local_file  TYPE zif_abapgit_definitions=>ty_file_item.

    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.xml'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    ls_abap_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    ls_xml_local_file = given_the_local_file(
      iv_obj_name = 'CL_FOO'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.xml'
      iv_path     = '/path'
      iv_data     = 'data' ).

    when_staging( ).

    then_file_should_be_added( ls_abap_local_file ).
    then_file_should_be_added( ls_xml_local_file ).
  ENDMETHOD.
  METHOD transport_not_in_repository.
    given_the_transport_object(
      iv_obj_name   = 'CL_A_CLASS_NOT_IN_REPO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    then_it_should_raise_exception(
      with_text = 'Object CL_A_CLASS_NOT_IN_REPO not found in the local repository files' ).
  ENDMETHOD.

  METHOD object_not_in_local_files.

    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS' ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    given_the_local_file(
      iv_obj_name = 'CL_ANOTHER_LOCAL_FILE'
      iv_obj_type = 'CLAS'
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/path'
      iv_data     = 'data' ).

    then_it_should_raise_exception(
      with_text = 'Object CL_FOO not found in the local repository files' ).
  ENDMETHOD.

  METHOD cant_be_added_with_del_flag.
    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-added ).

    then_it_should_raise_exception(
      with_text = 'Object CL_FOO should be added/modified, but has deletion flag in transport' ).
  ENDMETHOD.

  METHOD cant_be_modified_with_del_flag.
    given_the_transport_object(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_lstate     = zif_abapgit_definitions=>gc_state-modified ).

    then_it_should_raise_exception(
      with_text = 'Object CL_FOO should be added/modified, but has deletion flag in transport' ).
  ENDMETHOD.
  METHOD deleted_to_removed_files.
    given_the_transport_object(
     iv_obj_name   = 'CL_FOO'
     iv_obj_type   = 'CLAS'
     iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    when_staging( ).

    then_it_should_remove_at_stage(
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/a_path' ).
  ENDMETHOD.

  METHOD should_delete_all_related.
    "i.e. Should also delete the XMLs related to the transport objects
    given_the_transport_object(
     iv_obj_name   = 'CL_FOO'
     iv_obj_type   = 'CLAS'
     iv_delflag    = abap_true ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.xml'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    when_staging( ).

    then_it_should_remove_at_stage(
      iv_filename = 'CL_FOO.abap'
      iv_path     = '/a_path' ).

    then_it_should_remove_at_stage(
      iv_filename = 'CL_FOO.xml'
      iv_path     = '/a_path' ).
  ENDMETHOD.

  METHOD shouldnt_remove_no_delflag.
    given_the_transport_object(
       iv_obj_name   = 'CL_FOO'
       iv_obj_type   = 'CLAS'
       iv_delflag    = abap_false ).

    given_the_object_status(
      iv_obj_name   = 'CL_FOO'
      iv_obj_type   = 'CLAS'
      iv_filename   = 'CL_FOO.abap'
      iv_path       = '/a_path'
      iv_lstate     = zif_abapgit_definitions=>gc_state-deleted ).

    then_it_should_raise_exception(
         with_text = 'Object CL_FOO should be removed, but has NO deletion flag in transport' ).
  ENDMETHOD.

  METHOD given_the_transport_object.
    DATA ls_transport_object TYPE tadir.
    ls_transport_object-obj_name = iv_obj_name.
    ls_transport_object-object   = iv_obj_type.
    ls_transport_object-delflag  = iv_delflag.
    APPEND ls_transport_object TO mt_transport_objects.
  ENDMETHOD.

  METHOD given_the_object_status.
    DATA ls_object_status TYPE zif_abapgit_definitions=>ty_result.
    ls_object_status-obj_name = iv_obj_name.
    ls_object_status-obj_type = iv_obj_type.
    ls_object_status-filename = iv_filename.
    ls_object_status-path     = iv_path.
    ls_object_status-lstate   = iv_lstate.
    APPEND ls_object_status  TO mt_object_statuses.
  ENDMETHOD.

  METHOD given_the_local_file.
    rs_local_file-item-obj_name = iv_obj_name.
    rs_local_file-item-obj_type = iv_obj_type.
    rs_local_file-file-filename = iv_filename.
    rs_local_file-file-path     = iv_path.
    rs_local_file-file-data     = iv_data.
    APPEND rs_local_file TO ms_stage_objects-local.
  ENDMETHOD.

  METHOD when_staging.
    CREATE OBJECT mo_transport_objects
      EXPORTING
        it_transport_objects = mt_transport_objects.
    mo_transport_objects->to_stage(
      io_stage           = mo_stage
      is_stage_objects   = ms_stage_objects
      it_object_statuses = mt_object_statuses ).
  ENDMETHOD.

  METHOD then_file_should_be_added.
    DATA: lt_staged_objects TYPE zcl_abapgit_stage=>ty_stage_tt.
    lt_staged_objects = mo_stage->get_all( ).

    READ TABLE lt_staged_objects TRANSPORTING NO FIELDS
    WITH KEY file-filename = is_local_file-file-filename
            file-path      = is_local_file-file-path
            file-data      = is_local_file-file-data
            method         = zcl_abapgit_stage=>c_method-add.
    IF sy-subrc <> 0.
      cl_abap_unit_assert=>fail( |Object { is_local_file-file-filename } not added to stage| ).
    ENDIF.
  ENDMETHOD.

  METHOD then_it_should_raise_exception.
    DATA: lx_exception TYPE REF TO zcx_abapgit_exception.

    TRY.
        when_staging( ).
        cl_abap_unit_assert=>fail( 'Should have raised exception').
      CATCH zcx_abapgit_exception INTO lx_exception.
        cl_abap_unit_assert=>assert_equals(
          act = lx_exception->get_text( )
          exp = with_text ).
    ENDTRY.
  ENDMETHOD.

  METHOD then_it_should_remove_at_stage.

    DATA: lt_staged_objects TYPE zcl_abapgit_stage=>ty_stage_tt.

    lt_staged_objects = mo_stage->get_all( ).

    READ TABLE lt_staged_objects TRANSPORTING NO FIELDS
    WITH KEY file-filename  = iv_filename
             file-path      = iv_path.
    IF sy-subrc <> 0.
      cl_abap_unit_assert=>fail( |Object { iv_filename } not removed in stage| ).
    ENDIF.
  ENDMETHOD.

ENDCLASS.

Adjust transport unit test

Adjust transport unit test


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_WAPA
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_wapa DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_wapa DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_page,
             attributes     TYPE o2pagattr,
             event_handlers TYPE o2pagevh_tabletype,
             parameters     TYPE o2pagpar_tabletype,
             types          TYPE rswsourcet,
           END OF ty_page.

    TYPES: ty_pages_tt TYPE STANDARD TABLE OF ty_page WITH DEFAULT KEY.

    CONSTANTS: c_active TYPE so2_version VALUE 'A'.

    METHODS:
      get_page_content
        IMPORTING io_page           TYPE REF TO cl_o2_api_pages
        RETURNING VALUE(rv_content) TYPE xstring,
      to_page_content
        IMPORTING iv_content        TYPE xstring
        RETURNING VALUE(rt_content) TYPE o2pageline_table,
      read_page
        IMPORTING is_page        TYPE o2pagattr
        RETURNING VALUE(rs_page) TYPE ty_page
        RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_TRAN DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_wapa IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_wapa IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    DATA: lv_name   TYPE o2applname,
          lt_pages  TYPE STANDARD TABLE OF o2pagdir WITH DEFAULT KEY,
          ls_latest LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    SELECT * FROM o2pagdir INTO TABLE lt_pages WHERE applname = lv_name.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
      RETURN.
    ENDIF.

    SORT lt_pages BY changedon DESCENDING changetime DESCENDING.

    READ TABLE lt_pages INDEX 1 INTO ls_latest.
    ASSERT sy-subrc = 0.

    rv_user = ls_latest-changedby.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: lv_name TYPE o2applname.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = ms_item-obj_type
        in_new_window = abap_true.

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_name    TYPE o2applname,
          lo_bsp     TYPE REF TO cl_o2_api_application,
          ls_pagekey TYPE o2pagkey,
          lv_object  TYPE seu_objkey,
          lt_pages   TYPE o2pagelist.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      IMPORTING
        p_application       = lo_bsp
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    ASSERT sy-subrc = 0.

    lo_bsp->set_changeable(
      p_changeable           = abap_true
      p_complete_application = abap_true ).

    cl_o2_api_pages=>get_all_pages(
      EXPORTING
        p_applname = lv_name
        p_version  = c_active
      IMPORTING
        p_pages    = lt_pages ).

    LOOP AT lt_pages ASSIGNING <ls_page>.
      CLEAR ls_pagekey.
      ls_pagekey-applname = lv_name.
      ls_pagekey-pagekey  = <ls_page>-pagekey.

      cl_o2_page=>delete_page_for_application(
        EXPORTING
          p_pagekey           = ls_pagekey
        EXCEPTIONS
          object_not_existing = 1
          error_occured       = 2 ).
      ASSERT sy-subrc = 0.
    ENDLOOP.

    lo_bsp->delete( ).

* release lock
    lv_object = lv_name.
    cl_o2_api_application=>call_access_permission(
      p_mode                 = 'FREE'
      p_object               = lv_object
      p_complete_application = abap_true ).

  ENDMETHOD.                    "delete

  METHOD lif_object~deserialize.

    DATA: lo_bsp        TYPE REF TO cl_o2_api_application,
          lv_name       TYPE o2applname,
          ls_attributes TYPE o2applattr,
          lt_nodes      TYPE o2applnode_table,
          lt_navgraph   TYPE o2applgrap_table,
          lv_objkey     TYPE seu_objkey,
          ls_item       LIKE ms_item,
          lv_extra      TYPE string,
          lv_content    TYPE xstring,
          lv_ext        TYPE string,
          lo_page       TYPE REF TO cl_o2_api_pages,
          lt_pages_info TYPE ty_pages_tt.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages_info.

    lv_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'ATTRIBUTES'
                  CHANGING cg_data = ls_attributes ).
    io_xml->read( EXPORTING iv_name = 'NAVGRAPH'
                  CHANGING cg_data = lt_navgraph ).
    io_xml->read( EXPORTING iv_name = 'PAGES'
                  CHANGING cg_data = lt_pages_info ).

    ls_attributes-devclass = iv_package.

* todo: overwrite existing
    cl_o2_api_application=>create_new(
      EXPORTING
        p_application_data      = ls_attributes
        p_nodes                 = lt_nodes
        p_navgraph              = lt_navgraph
      IMPORTING
        p_application           = lo_bsp
      EXCEPTIONS
        object_already_existing = 1
        object_just_created     = 2
        not_authorized          = 3
        undefined_name          = 4
        author_not_existing     = 5
        action_cancelled        = 6
        error_occured           = 7
        invalid_parameter       = 8 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( |WAPA - error from create_new: { sy-subrc }| ).
    ENDIF.

    lo_bsp->save( ).

    lo_bsp->set_changeable(
      p_changeable           = abap_false
      p_complete_application = abap_true ).

    ls_item-obj_type = 'WAPD'.
    ls_item-obj_name = ms_item-obj_name.
    lcl_objects_activation=>add_item( ls_item ).

    lv_objkey = ls_item-obj_name.
* todo, hmm, the WAPD is not added to the worklist during activation
    cl_o2_api_application=>activate( lv_objkey ).

    LOOP AT lt_pages_info ASSIGNING <ls_page>.
      cl_o2_api_pages=>create_new_page(
        EXPORTING
          p_pageattrs = <ls_page>-attributes
        IMPORTING
          p_page      = lo_page ).

      SPLIT <ls_page>-attributes-pagename AT '.' INTO lv_extra lv_ext.
      REPLACE ALL OCCURRENCES OF '_-' IN lv_extra WITH '/'.
      lv_content = mo_files->read_raw( iv_extra = lv_extra
                                       iv_ext   = lv_ext ).
      lo_page->set_page( to_page_content( lv_content ) ).

      lo_page->set_event_handlers( <ls_page>-event_handlers ).
      lo_page->set_parameters( <ls_page>-parameters ).
      lo_page->set_type_source( <ls_page>-types ).

      lo_page->save( p_with_all_texts = abap_true ).

      ls_item-obj_type = 'WAPP'.
      ls_item-obj_name = cl_wb_object_type=>get_concatenated_key_from_id(
        p_key_component1 = <ls_page>-attributes-applname
        p_key_component2 = <ls_page>-attributes-pagekey
        p_external_id    = 'WG ' ).
      lcl_objects_activation=>add_item( ls_item ).
    ENDLOOP.

  ENDMETHOD.                    "deserialize

  METHOD lif_object~serialize.

    DATA: lv_name       TYPE o2applname,
          ls_attributes TYPE o2applattr,
          lt_navgraph   TYPE o2applgrap_table,
          lt_pages      TYPE o2pagelist,
          lt_pages_info TYPE ty_pages_tt,
          lo_bsp        TYPE REF TO cl_o2_api_application.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      IMPORTING
        p_application       = lo_bsp
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    lo_bsp->get_attributes(
      EXPORTING
        p_version    = c_active
      IMPORTING
        p_attributes = ls_attributes ).

    CLEAR: ls_attributes-author,
           ls_attributes-createdon,
           ls_attributes-changedby,
           ls_attributes-changedon,
           ls_attributes-devclass.

    io_xml->add( iv_name = 'ATTRIBUTES'
                 ig_data = ls_attributes ).

    lo_bsp->get_navgraph(
      EXPORTING
        p_version  = c_active
      IMPORTING
        p_navgraph = lt_navgraph ).

    io_xml->add( iv_name = 'NAVGRAPH'
                 ig_data = lt_navgraph ).

    cl_o2_api_pages=>get_all_pages(
      EXPORTING
        p_applname = lv_name
        p_version  = c_active
      IMPORTING
        p_pages    = lt_pages ).

    LOOP AT lt_pages ASSIGNING <ls_page>.
      APPEND read_page( <ls_page> ) TO lt_pages_info.
    ENDLOOP.

    io_xml->add( iv_name = 'PAGES'
                 ig_data = lt_pages_info ).

  ENDMETHOD.                    "serialize

  METHOD read_page.

    DATA: lv_name    TYPE o2applname,
          ls_pagekey TYPE o2pagkey,
          lv_content TYPE xstring,
          lv_extra   TYPE string,
          lv_ext     TYPE string,
          lo_page    TYPE REF TO cl_o2_api_pages.

    lv_name = ms_item-obj_name.

    ls_pagekey-applname = lv_name.
    ls_pagekey-pagekey = is_page-pagekey.

    cl_o2_api_pages=>load(
      EXPORTING
        p_pagekey = ls_pagekey
      IMPORTING
        p_page    = lo_page ).

    lo_page->get_event_handlers(
      IMPORTING
        p_ev_handler = rs_page-event_handlers
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2 ).
    ASSERT sy-subrc = 0.

    lo_page->get_parameters(
      IMPORTING
        p_parameters = rs_page-parameters
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2
        OTHERS       = 3 ).
    ASSERT sy-subrc = 0.

    lo_page->get_type_source(
      IMPORTING
        p_source     = rs_page-types
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2
        OTHERS       = 3 ).
    ASSERT sy-subrc = 0.

    lv_content = get_page_content( lo_page ).
    SPLIT is_page-pagename AT '.' INTO lv_extra lv_ext.
    REPLACE ALL OCCURRENCES OF '/' IN lv_extra WITH '_-'.
    mo_files->add_raw(
      iv_extra = lv_extra
      iv_ext   = lv_ext
      iv_data  = lv_content ).

    rs_page-attributes = is_page.

    CLEAR: rs_page-attributes-author,
           rs_page-attributes-createdon,
           rs_page-attributes-changedby,
           rs_page-attributes-changedon,
           rs_page-attributes-implclass,
           rs_page-attributes-gendate,
           rs_page-attributes-gentime.

  ENDMETHOD.

  METHOD to_page_content.

    DATA: lv_string TYPE string.

    lv_string = lcl_convert=>xstring_to_string_utf8( iv_content ).

    SPLIT lv_string AT gc_newline INTO TABLE rt_content.

  ENDMETHOD.

  METHOD get_page_content.

    DATA: lt_content TYPE o2pageline_table,
          lv_string  TYPE string.

    io_page->get_page(
      IMPORTING
        p_content = lt_content ).

    CONCATENATE LINES OF lt_content INTO lv_string SEPARATED BY gc_newline RESPECTING BLANKS.

    rv_content = lcl_convert=>string_to_xstring_utf8( lv_string ).

  ENDMETHOD.

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_null_comparison_result.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_tran IMPLEMENTATION

Update zabapgit_object_wapa.prog.abap

Update zabapgit_object_wapa.prog.abap


CLASS zcl_abapgit_tadir DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS read
      IMPORTING
        !iv_package            TYPE tadir-devclass
        !iv_ignore_subpackages TYPE abap_bool DEFAULT abap_false
        !iv_only_local_objects TYPE abap_bool DEFAULT abap_false
        !io_dot                TYPE REF TO zcl_abapgit_dot_abapgit OPTIONAL
        !io_log                TYPE REF TO zcl_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_tadir)        TYPE zif_abapgit_definitions=>ty_tadir_tt
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS read_single
      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
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS 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
      RAISING
        zcx_abapgit_exception .
  PRIVATE SECTION.

    CLASS-METHODS check_exists
      IMPORTING
        !it_tadir       TYPE zif_abapgit_definitions=>ty_tadir_tt
      RETURNING
        VALUE(rt_tadir) TYPE zif_abapgit_definitions=>ty_tadir_tt
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS build
      IMPORTING
        !iv_package            TYPE tadir-devclass
        !iv_top                TYPE tadir-devclass
        !io_dot                TYPE REF TO zcl_abapgit_dot_abapgit
        !iv_ignore_subpackages TYPE abap_bool DEFAULT abap_false
        !iv_only_local_objects TYPE abap_bool
        !io_log                TYPE REF TO zcl_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_tadir)        TYPE zif_abapgit_definitions=>ty_tadir_tt
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_TADIR IMPLEMENTATION.

  METHOD build.

    DATA: lt_tadir        TYPE zif_abapgit_definitions=>ty_tadir_tt,
          lt_tdevc        TYPE STANDARD TABLE OF tdevc,
          lv_path         TYPE string,
          lo_skip_objects TYPE REF TO zcl_abapgit_skip_objects,
          lt_excludes     TYPE RANGE OF trobjtype,
          lt_srcsystem    TYPE RANGE OF tadir-srcsystem,
          ls_srcsystem    LIKE LINE OF lt_srcsystem,
          ls_exclude      LIKE LINE OF lt_excludes.

    FIELD-SYMBOLS: <ls_tdevc> LIKE LINE OF lt_tdevc,
                   <ls_tadir> LIKE LINE OF rt_tadir.

    ls_exclude-sign = 'I'.
    ls_exclude-option = 'EQ'.

    ls_exclude-low = 'SOTR'.
    APPEND ls_exclude TO lt_excludes.
    ls_exclude-low = 'SFB1'.
    APPEND ls_exclude TO lt_excludes.
    ls_exclude-low = 'SFB2'.
    APPEND ls_exclude TO lt_excludes.
    ls_exclude-low = 'STOB'. " auto generated by core data services
    APPEND ls_exclude TO lt_excludes.

    IF iv_only_local_objects = abap_true.
      ls_srcsystem-sign   = 'I'.
      ls_srcsystem-option = 'EQ'.
      ls_srcsystem-low    = sy-sysid.
      APPEND ls_srcsystem TO lt_srcsystem.
    ENDIF.

    SELECT * FROM tadir
      INTO CORRESPONDING FIELDS OF TABLE rt_tadir
      WHERE devclass = iv_package
      AND pgmid = 'R3TR'
      AND object NOT IN lt_excludes
      AND delflag = abap_false
      AND srcsystem IN lt_srcsystem
      ORDER BY PRIMARY KEY.               "#EC CI_GENBUFF "#EC CI_SUBRC

    CREATE OBJECT lo_skip_objects.
    rt_tadir = lo_skip_objects->skip_sadl_generated_objects(
      it_tadir = rt_tadir
      io_log   = io_log ).

    " Local packages are not in TADIR, only in TDEVC, act as if they were
    IF iv_package CP '$*'. " OR iv_package CP 'T*' ).
      APPEND INITIAL LINE TO rt_tadir ASSIGNING <ls_tadir>.
      <ls_tadir>-pgmid    = 'R3TR'.
      <ls_tadir>-object   = 'DEVC'.
      <ls_tadir>-obj_name = iv_package.
      <ls_tadir>-devclass = iv_package.
    ENDIF.

    IF NOT io_dot IS INITIAL.
      lv_path = zcl_abapgit_folder_logic=>package_to_path(
        iv_top     = iv_top
        io_dot     = io_dot
        iv_package = iv_package ).
    ENDIF.

    LOOP AT rt_tadir ASSIGNING <ls_tadir>.
      <ls_tadir>-path = lv_path.

      CASE <ls_tadir>-object.
        WHEN 'SICF'.
* replace the internal GUID with a hash of the path
          <ls_tadir>-obj_name+15 = zcl_abapgit_object_sicf=>read_sicf_url( <ls_tadir>-obj_name ).
      ENDCASE.
    ENDLOOP.

* look for subpackages
    IF iv_ignore_subpackages = abap_false.
      SELECT * FROM tdevc INTO TABLE lt_tdevc
        WHERE parentcl = iv_package
        ORDER BY PRIMARY KEY.             "#EC CI_SUBRC "#EC CI_GENBUFF
    ENDIF.

    LOOP AT lt_tdevc ASSIGNING <ls_tdevc>.
      lt_tadir = build( iv_package            = <ls_tdevc>-devclass
                        iv_only_local_objects = iv_only_local_objects
                        iv_top                = iv_top
                        io_dot                = io_dot
                        io_log                = io_log ).
      APPEND LINES OF lt_tadir TO rt_tadir.
    ENDLOOP.

  ENDMETHOD.                    "build

  METHOD check_exists.

    DATA: lv_exists   TYPE abap_bool,
          lo_progress TYPE REF TO zcl_abapgit_progress,
          ls_item     TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_tadir> LIKE LINE OF it_tadir.

    CREATE OBJECT lo_progress
      EXPORTING
        iv_total = lines( it_tadir ).

* rows from database table TADIR are not removed for
* transportable objects until the transport is released
    LOOP AT it_tadir ASSIGNING <ls_tadir>.
      IF sy-tabix MOD 200 = 0.
        lo_progress->show(
          iv_current = sy-tabix
          iv_text    = |Check object exists { <ls_tadir>-object } { <ls_tadir>-obj_name }| ).
      ENDIF.

      ls_item-obj_type = <ls_tadir>-object.
      ls_item-obj_name = <ls_tadir>-obj_name.
      ls_item-devclass = <ls_tadir>-devclass.

      IF zcl_abapgit_objects=>is_supported( ls_item ) = abap_true.
        lv_exists = zcl_abapgit_objects=>exists( ls_item ).
        IF lv_exists = abap_true.
          APPEND <ls_tadir> TO rt_tadir.
        ENDIF.
      ELSE.
        APPEND <ls_tadir> TO rt_tadir.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.                    "check_exists

  METHOD get_object_package.

    DATA ls_tadir TYPE tadir.

    ls_tadir = read_single( iv_pgmid    = iv_pgmid
                            iv_object   = iv_object
                            iv_obj_name = iv_obj_name ).

    IF ls_tadir-delflag = 'X'.
      RETURN. "Mark for deletion -> return nothing
    ENDIF.

    rv_devclass = ls_tadir-devclass.

  ENDMETHOD.  "get_object_package.

  METHOD read.

* start recursion
* hmm, some problems here, should TADIR also build path?
    rt_tadir = build( iv_package            = iv_package
                      iv_top                = iv_package
                      io_dot                = io_dot
                      iv_ignore_subpackages = iv_ignore_subpackages
                      iv_only_local_objects = iv_only_local_objects
                      io_log                = io_log ).

    rt_tadir = check_exists( rt_tadir ).

  ENDMETHOD.                    "read

  METHOD read_single.

    IF iv_object = 'SICF'.
      rs_tadir = zcl_abapgit_object_sicf=>read_tadir_sicf(
        iv_pgmid    = iv_pgmid
        iv_obj_name = iv_obj_name ).
    ELSE.
      SELECT SINGLE * FROM tadir INTO rs_tadir
        WHERE pgmid = iv_pgmid
        AND object = iv_object
        AND obj_name = iv_obj_name.                       "#EC CI_SUBRC
    ENDIF.

  ENDMETHOD.                    "read_single
ENDCLASS.

CLASS zcl_abapgit_tadir DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS read
      IMPORTING
        !iv_package            TYPE tadir-devclass
        !iv_ignore_subpackages TYPE abap_bool DEFAULT abap_false
        !iv_only_local_objects TYPE abap_bool DEFAULT abap_false
        !io_dot                TYPE REF TO zcl_abapgit_dot_abapgit OPTIONAL
        !io_log                TYPE REF TO zcl_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_tadir)        TYPE zif_abapgit_definitions=>ty_tadir_tt
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS read_single
      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
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS 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
      RAISING
        zcx_abapgit_exception .

  PRIVATE SECTION.

    CLASS-METHODS exists
      IMPORTING
        is_item          TYPE zif_abapgit_definitions=>ty_item
      RETURNING
        VALUE(rv_exists) TYPE abap_bool.
    CLASS-METHODS check_exists
      IMPORTING
        !it_tadir       TYPE zif_abapgit_definitions=>ty_tadir_tt
      RETURNING
        VALUE(rt_tadir) TYPE zif_abapgit_definitions=>ty_tadir_tt
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS build
      IMPORTING
        !iv_package            TYPE tadir-devclass
        !iv_top                TYPE tadir-devclass
        !io_dot                TYPE REF TO zcl_abapgit_dot_abapgit
        !iv_ignore_subpackages TYPE abap_bool DEFAULT abap_false
        !iv_only_local_objects TYPE abap_bool
        !io_log                TYPE REF TO zcl_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_tadir)        TYPE zif_abapgit_definitions=>ty_tadir_tt
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS zcl_abapgit_tadir IMPLEMENTATION.

  METHOD build.

    DATA: lt_tadir        TYPE zif_abapgit_definitions=>ty_tadir_tt,
          lt_tdevc        TYPE STANDARD TABLE OF tdevc,
          lv_path         TYPE string,
          lo_skip_objects TYPE REF TO zcl_abapgit_skip_objects,
          lt_excludes     TYPE RANGE OF trobjtype,
          lt_srcsystem    TYPE RANGE OF tadir-srcsystem,
          ls_srcsystem    LIKE LINE OF lt_srcsystem,
          ls_exclude      LIKE LINE OF lt_excludes.

    FIELD-SYMBOLS: <ls_tdevc> LIKE LINE OF lt_tdevc,
                   <ls_tadir> LIKE LINE OF rt_tadir.

    ls_exclude-sign = 'I'.
    ls_exclude-option = 'EQ'.

    ls_exclude-low = 'SOTR'.
    APPEND ls_exclude TO lt_excludes.
    ls_exclude-low = 'SFB1'.
    APPEND ls_exclude TO lt_excludes.
    ls_exclude-low = 'SFB2'.
    APPEND ls_exclude TO lt_excludes.
    ls_exclude-low = 'STOB'. " auto generated by core data services
    APPEND ls_exclude TO lt_excludes.

    IF iv_only_local_objects = abap_true.
      ls_srcsystem-sign   = 'I'.
      ls_srcsystem-option = 'EQ'.
      ls_srcsystem-low    = sy-sysid.
      APPEND ls_srcsystem TO lt_srcsystem.
    ENDIF.

    SELECT * FROM tadir
      INTO CORRESPONDING FIELDS OF TABLE rt_tadir
      WHERE devclass = iv_package
      AND pgmid = 'R3TR'
      AND object NOT IN lt_excludes
      AND delflag = abap_false
      AND srcsystem IN lt_srcsystem
      ORDER BY PRIMARY KEY.               "#EC CI_GENBUFF "#EC CI_SUBRC

    CREATE OBJECT lo_skip_objects.
    rt_tadir = lo_skip_objects->skip_sadl_generated_objects(
      it_tadir = rt_tadir
      io_log   = io_log ).

    " Local packages are not in TADIR, only in TDEVC, act as if they were
    IF iv_package CP '$*'. " OR iv_package CP 'T*' ).
      APPEND INITIAL LINE TO rt_tadir ASSIGNING <ls_tadir>.
      <ls_tadir>-pgmid    = 'R3TR'.
      <ls_tadir>-object   = 'DEVC'.
      <ls_tadir>-obj_name = iv_package.
      <ls_tadir>-devclass = iv_package.
    ENDIF.

    IF NOT io_dot IS INITIAL.
      lv_path = zcl_abapgit_folder_logic=>package_to_path(
        iv_top     = iv_top
        io_dot     = io_dot
        iv_package = iv_package ).
    ENDIF.

    LOOP AT rt_tadir ASSIGNING <ls_tadir>.
      <ls_tadir>-path = lv_path.

      CASE <ls_tadir>-object.
        WHEN 'SICF'.
* replace the internal GUID with a hash of the path
          <ls_tadir>-obj_name+15 = zcl_abapgit_object_sicf=>read_sicf_url( <ls_tadir>-obj_name ).
      ENDCASE.
    ENDLOOP.

* look for subpackages
    IF iv_ignore_subpackages = abap_false.
      SELECT * FROM tdevc INTO TABLE lt_tdevc
        WHERE parentcl = iv_package
        ORDER BY PRIMARY KEY.             "#EC CI_SUBRC "#EC CI_GENBUFF
    ENDIF.

    LOOP AT lt_tdevc ASSIGNING <ls_tdevc>.
      lt_tadir = build( iv_package            = <ls_tdevc>-devclass
                        iv_only_local_objects = iv_only_local_objects
                        iv_top                = iv_top
                        io_dot                = io_dot
                        io_log                = io_log ).
      APPEND LINES OF lt_tadir TO rt_tadir.
    ENDLOOP.

  ENDMETHOD.                    "build

  METHOD check_exists.

    DATA: lv_exists   TYPE abap_bool,
          lo_progress TYPE REF TO zcl_abapgit_progress,
          ls_item     TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_tadir> LIKE LINE OF it_tadir.

    CREATE OBJECT lo_progress
      EXPORTING
        iv_total = lines( it_tadir ).

* rows from database table TADIR are not removed for
* transportable objects until the transport is released
    LOOP AT it_tadir ASSIGNING <ls_tadir>.
      IF sy-tabix MOD 200 = 0.
        lo_progress->show(
          iv_current = sy-tabix
          iv_text    = |Check object exists { <ls_tadir>-object } { <ls_tadir>-obj_name }| ).
      ENDIF.

      ls_item-obj_type = <ls_tadir>-object.
      ls_item-obj_name = <ls_tadir>-obj_name.
      ls_item-devclass = <ls_tadir>-devclass.

      IF exists( ls_item ) = abap_true.
        APPEND <ls_tadir> TO rt_tadir.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.                    "check_exists

  METHOD exists.

    IF zcl_abapgit_objects=>is_supported( is_item ) = abap_false.
      rv_exists = abap_true.
      RETURN.
    ENDIF.

    rv_exists = zcl_abapgit_objects=>exists( is_item ).

  ENDMETHOD.

  METHOD get_object_package.

    DATA: ls_tadir TYPE tadir,
          ls_item  TYPE zif_abapgit_definitions=>ty_item.

    ls_tadir = read_single( iv_pgmid    = iv_pgmid
                            iv_object   = iv_object
                            iv_obj_name = iv_obj_name ).

    IF ls_tadir-delflag = 'X'.
      RETURN. "Mark for deletion -> return nothing
    ENDIF.

    ls_item-obj_type = ls_tadir-object.
    ls_item-obj_name = ls_tadir-obj_name.
    ls_item-devclass = ls_tadir-devclass.
    IF exists( ls_item ) = abap_false.
      RETURN.
    ENDIF.

    rv_devclass = ls_tadir-devclass.

  ENDMETHOD.  "get_object_package.

  METHOD read.

* start recursion
* hmm, some problems here, should TADIR also build path?
    rt_tadir = build( iv_package            = iv_package
                      iv_top                = iv_package
                      io_dot                = io_dot
                      iv_ignore_subpackages = iv_ignore_subpackages
                      iv_only_local_objects = iv_only_local_objects
                      io_log                = io_log ).

    rt_tadir = check_exists( rt_tadir ).

  ENDMETHOD.                    "read

  METHOD read_single.

    IF iv_object = 'SICF'.
      rs_tadir = zcl_abapgit_object_sicf=>read_tadir_sicf(
        iv_pgmid    = iv_pgmid
        iv_obj_name = iv_obj_name ).
    ELSE.
      SELECT SINGLE * FROM tadir INTO rs_tadir
        WHERE pgmid = iv_pgmid
        AND object = iv_object
        AND obj_name = iv_obj_name.                       "#EC CI_SUBRC
    ENDIF.

  ENDMETHOD.                    "read_single
ENDCLASS.

set devclass to blank if obj does not exist #1356