CLASS zcl_abapgit_object_char DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_objects_super
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES zif_abapgit_object .

  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_char,
        cls_attribute   TYPE cls_attribute,
        cls_attributet  TYPE STANDARD TABLE OF cls_attributet WITH DEFAULT KEY,
        cls_attr_value  TYPE STANDARD TABLE OF cls_attr_value WITH DEFAULT KEY,
        cls_attr_valuet TYPE STANDARD TABLE OF cls_attr_valuet WITH DEFAULT KEY,
      END OF ty_char .

    METHODS instantiate_char
      IMPORTING
        !iv_type_group TYPE cls_object_type_group
      RETURNING
        VALUE(ro_char) TYPE REF TO cl_cls_attribute
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_OBJECT_CHAR IMPLEMENTATION.

  METHOD instantiate_char.

    DATA: lv_new  TYPE abap_bool,
          lv_name TYPE cls_attribute_name.

    SELECT SINGLE name FROM cls_attribute INTO lv_name WHERE name = ms_item-obj_name.
    lv_new = boolc( sy-subrc <> 0 ).
    lv_name = ms_item-obj_name.

    TRY.
        CREATE OBJECT ro_char
          EXPORTING
            im_name       = lv_name
            im_type_group = iv_type_group
            im_new        = lv_new.
      CATCH cx_pak_invalid_data
          cx_pak_not_authorized
          cx_pak_invalid_state
          cx_pak_wb_object_locked.
        zcx_abapgit_exception=>raise( 'Error while instantiating CL_CLS_ATTRIBUTE' ).
    ENDTRY.

    IF lv_new = abap_false.
      TRY.
          ro_char->if_pak_wb_object~lock_and_refresh( ).
        CATCH cx_pak_wb_object_locked.
          zcx_abapgit_exception=>raise( |Could not aquire lock, CHAR { lv_name }| ).
      ENDTRY.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE changed_by FROM cls_attribute INTO rv_user
      WHERE name = ms_item-obj_name
      AND activation_state = 'A'.

    IF rv_user IS INITIAL.
      SELECT SINGLE created_by FROM cls_attribute INTO rv_user
        WHERE name = ms_item-obj_name
        AND activation_state = 'A'.
    ENDIF.

    IF rv_user IS INITIAL.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

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

  METHOD zif_abapgit_object~delete.

    DATA: lo_char       TYPE REF TO cl_cls_attribute,
          lv_type_group TYPE cls_attribute-type_group.

    SELECT SINGLE type_group FROM cls_attribute INTO lv_type_group
      WHERE name = ms_item-obj_name
      AND activation_state = 'A'.

    lo_char = instantiate_char( lv_type_group ).

    lo_char->if_pak_wb_object~delete( ).

    lo_char->if_pak_wb_object~save( ).

    lo_char->if_pak_wb_object_internal~unlock( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

    DATA: ls_char        TYPE ty_char,
          lv_request     TYPE trkorr,
          ls_description LIKE LINE OF ls_char-cls_attributet,
          lo_char        TYPE REF TO cl_cls_attribute.

    io_xml->read( EXPORTING iv_name = 'CHAR'
                  CHANGING cg_data = ls_char ).

    tadir_insert( iv_package ).

    lo_char = instantiate_char( ls_char-cls_attribute-type_group ).

    lo_char->if_cls_attribute~set_kind( ls_char-cls_attribute-kind ).
    lo_char->if_cls_attribute~set_single_valued( ls_char-cls_attribute-is_single_valued ).
    lo_char->if_cls_attribute~set_aspect(
      im_aspect_for   = ls_char-cls_attribute-is_aspect_for
      im_aspect_value = ls_char-cls_attribute-aspect_value ).
    lo_char->if_cls_attribute~set_default_flag( ls_char-cls_attribute-default_flag ).
    lo_char->if_cls_attribute~set_default_value( ls_char-cls_attribute-default_value ).
    lo_char->if_cls_attribute~set_sub_object_treatment( ls_char-cls_attribute-sub_obj_treatm ).
    lo_char->if_cls_attribute~set_automatic_changes_allowed( ls_char-cls_attribute-automatic_change ).
    lo_char->if_cls_attribute~set_manual_changes_allowed( ls_char-cls_attribute-manu_chag_allow ).
    lo_char->if_cls_attribute~set_implicit_changes_allowed( ls_char-cls_attribute-implicit_change ).
    lo_char->if_cls_attribute~set_expl_values_dominate_links( ls_char-cls_attribute-weak_links ).
    lo_char->if_cls_attribute~set_assignment_package_rule( ls_char-cls_attribute-assignment_devc ).
    lo_char->if_cls_attribute~set_hide_remark( ls_char-cls_attribute-hide_remark ).
    lo_char->if_cls_attribute~set_visible_in_customer_system( ls_char-cls_attribute-visible_for_cust ).
    lo_char->if_cls_attribute~set_value_table( ls_char-cls_attribute-value_table ).
    lo_char->if_cls_attribute~set_vtable_field( ls_char-cls_attribute-vtable_field ).
    lo_char->if_cls_attribute~set_vtable_icon_f( ls_char-cls_attribute-vtable_icon_f ).
    lo_char->if_cls_attribute~set_vtext_langu_f( ls_char-cls_attribute-vtext_langu_f ).
    lo_char->if_cls_attribute~set_vtext_table( ls_char-cls_attribute-vtext_table ).
    lo_char->if_cls_attribute~set_vtext_text_f( ls_char-cls_attribute-vtext_text_f ).
    lo_char->if_cls_attribute~set_vtext_value_f( ls_char-cls_attribute-vtext_value_f ).
    lo_char->if_cls_attribute~set_existing_objects_only( ls_char-cls_attribute-existing_objects ).
    lo_char->if_cls_attribute~set_objs_of_typegr( ls_char-cls_attribute-objs_of_typegr ).
    lo_char->if_cls_attribute~set_obj_values_have_subtypes( ls_char-cls_attribute-objs_w_subtype ).
    lo_char->if_cls_attribute~set_arbtry_val_type( ls_char-cls_attribute-arbtry_val_type ).

    READ TABLE ls_char-cls_attributet INTO ls_description WITH KEY langu = sy-langu.
    IF sy-subrc <> 0.
      READ TABLE ls_char-cls_attributet INTO ls_description INDEX 1.
    ENDIF.
    lo_char->if_cls_attribute~set_description( ls_description-text ).

    lo_char->if_cls_attribute~set_values(
      im_values   = ls_char-cls_attr_value
      im_values_t = ls_char-cls_attr_valuet ).

* set default package, see function module RS_CORR_INSERT
    SET PARAMETER ID 'EUK' FIELD iv_package.

    lo_char->if_pak_wb_object~save( ).

    SET PARAMETER ID 'EUK' FIELD ''.

    lo_char->if_pak_wb_object~activate( ).

    lo_char->if_pak_wb_object_internal~unlock( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    rv_bool = cl_cls_attribute=>exists_object_attribute( ms_item-obj_name ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.

  METHOD zif_abapgit_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'
        object_name         = ms_item-obj_name
        object_type         = ms_item-obj_type
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |Error from RS_TOOL_ACCESS, CHAR| ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: ls_char TYPE ty_char.

    CONSTANTS: lc_active TYPE c LENGTH 1 VALUE 'A'.

    SELECT SINGLE * FROM cls_attribute INTO ls_char-cls_attribute
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.
* todo, ASSIGNMENT_DEVC?

    CLEAR: ls_char-cls_attribute-created_by,
           ls_char-cls_attribute-created_on,
           ls_char-cls_attribute-changed_by,
           ls_char-cls_attribute-changed_on.

    SELECT * FROM cls_attributet INTO TABLE ls_char-cls_attributet
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.

    SELECT * FROM cls_attr_value INTO TABLE ls_char-cls_attr_value
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.

    SELECT * FROM cls_attr_valuet INTO TABLE ls_char-cls_attr_valuet
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.

    io_xml->add( iv_name = 'CHAR'
                 ig_data = ls_char ).

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_object_char DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_objects_super
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES zif_abapgit_object .

  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_char,
        cls_attribute   TYPE cls_attribute,
        cls_attributet  TYPE STANDARD TABLE OF cls_attributet WITH DEFAULT KEY,
        cls_attr_value  TYPE STANDARD TABLE OF cls_attr_value WITH DEFAULT KEY,
        cls_attr_valuet TYPE STANDARD TABLE OF cls_attr_valuet WITH DEFAULT KEY,
      END OF ty_char .

    METHODS instantiate_char
      IMPORTING
        !iv_type_group TYPE cls_object_type_group
      RETURNING
        VALUE(ro_char) TYPE REF TO cl_cls_attribute
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_OBJECT_CHAR IMPLEMENTATION.

  METHOD instantiate_char.

    DATA: lv_new  TYPE abap_bool,
          lv_name TYPE cls_attribute_name.

    SELECT SINGLE name FROM cls_attribute INTO lv_name WHERE name = ms_item-obj_name.
    lv_new = boolc( sy-subrc <> 0 ).
    lv_name = ms_item-obj_name.

    TRY.
        CREATE OBJECT ro_char
          EXPORTING
            im_name       = lv_name
            im_type_group = iv_type_group
            im_new        = lv_new.
      CATCH cx_pak_invalid_data
          cx_pak_not_authorized
          cx_pak_invalid_state
          cx_pak_wb_object_locked.
        zcx_abapgit_exception=>raise( 'Error while instantiating CL_CLS_ATTRIBUTE' ).
    ENDTRY.

    IF lv_new = abap_false.
      TRY.
          ro_char->if_pak_wb_object~lock_and_refresh( ).
        CATCH cx_pak_wb_object_locked.
          zcx_abapgit_exception=>raise( |Could not aquire lock, CHAR { lv_name }| ).
      ENDTRY.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE changed_by FROM cls_attribute INTO rv_user
      WHERE name = ms_item-obj_name
      AND activation_state = 'A'.

    IF rv_user IS INITIAL.
      SELECT SINGLE created_by FROM cls_attribute INTO rv_user
        WHERE name = ms_item-obj_name
        AND activation_state = 'A'.
    ENDIF.

    IF rv_user IS INITIAL.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

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

  METHOD zif_abapgit_object~delete.

    DATA: lo_char       TYPE REF TO cl_cls_attribute,
          lv_type_group TYPE cls_attribute-type_group.

    SELECT SINGLE type_group FROM cls_attribute INTO lv_type_group
      WHERE name = ms_item-obj_name
      AND activation_state = 'A'.

    lo_char = instantiate_char( lv_type_group ).

    lo_char->if_pak_wb_object~delete( ).

    lo_char->if_pak_wb_object~save( ).

    lo_char->if_pak_wb_object_internal~unlock( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

    DATA: ls_char        TYPE ty_char,
          lv_request     TYPE trkorr,
          ls_description LIKE LINE OF ls_char-cls_attributet,
          lo_char        TYPE REF TO cl_cls_attribute.

    io_xml->read( EXPORTING iv_name = 'CHAR'
                  CHANGING cg_data = ls_char ).

    tadir_insert( iv_package ).

    lo_char = instantiate_char( ls_char-cls_attribute-type_group ).

    lo_char->if_cls_attribute~set_kind( ls_char-cls_attribute-kind ).
    lo_char->if_cls_attribute~set_single_valued( ls_char-cls_attribute-is_single_valued ).
    lo_char->if_cls_attribute~set_aspect(
      im_aspect_for   = ls_char-cls_attribute-is_aspect_for
      im_aspect_value = ls_char-cls_attribute-aspect_value ).
    lo_char->if_cls_attribute~set_default_flag( ls_char-cls_attribute-default_flag ).
    lo_char->if_cls_attribute~set_default_value( ls_char-cls_attribute-default_value ).
    lo_char->if_cls_attribute~set_sub_object_treatment( ls_char-cls_attribute-sub_obj_treatm ).
    lo_char->if_cls_attribute~set_automatic_changes_allowed( ls_char-cls_attribute-automatic_change ).
    lo_char->if_cls_attribute~set_manual_changes_allowed( ls_char-cls_attribute-manu_chag_allow ).
    lo_char->if_cls_attribute~set_implicit_changes_allowed( ls_char-cls_attribute-implicit_change ).
    lo_char->if_cls_attribute~set_expl_values_dominate_links( ls_char-cls_attribute-weak_links ).
    lo_char->if_cls_attribute~set_assignment_package_rule( ls_char-cls_attribute-assignment_devc ).
    lo_char->if_cls_attribute~set_hide_remark( ls_char-cls_attribute-hide_remark ).
    lo_char->if_cls_attribute~set_visible_in_customer_system( ls_char-cls_attribute-visible_for_cust ).
    lo_char->if_cls_attribute~set_value_table( ls_char-cls_attribute-value_table ).
    lo_char->if_cls_attribute~set_vtable_field( ls_char-cls_attribute-vtable_field ).
    lo_char->if_cls_attribute~set_vtable_icon_f( ls_char-cls_attribute-vtable_icon_f ).
    lo_char->if_cls_attribute~set_vtext_langu_f( ls_char-cls_attribute-vtext_langu_f ).
    lo_char->if_cls_attribute~set_vtext_table( ls_char-cls_attribute-vtext_table ).
    lo_char->if_cls_attribute~set_vtext_text_f( ls_char-cls_attribute-vtext_text_f ).
    lo_char->if_cls_attribute~set_vtext_value_f( ls_char-cls_attribute-vtext_value_f ).
    lo_char->if_cls_attribute~set_existing_objects_only( ls_char-cls_attribute-existing_objects ).
    lo_char->if_cls_attribute~set_objs_of_typegr( ls_char-cls_attribute-objs_of_typegr ).
    lo_char->if_cls_attribute~set_obj_values_have_subtypes( ls_char-cls_attribute-objs_w_subtype ).
    lo_char->if_cls_attribute~set_arbtry_val_type( ls_char-cls_attribute-arbtry_val_type ).

    READ TABLE ls_char-cls_attributet INTO ls_description WITH KEY langu = sy-langu.
    IF sy-subrc <> 0.
      READ TABLE ls_char-cls_attributet INTO ls_description INDEX 1.
    ENDIF.
    lo_char->if_cls_attribute~set_description( ls_description-text ).

    lo_char->if_cls_attribute~set_values(
      im_values   = ls_char-cls_attr_value
      im_values_t = ls_char-cls_attr_valuet ).

* set default package, see function module RS_CORR_INSERT
    SET PARAMETER ID 'EUK' FIELD iv_package.

    lo_char->if_pak_wb_object~save( ).

    SET PARAMETER ID 'EUK' FIELD ''.

    lo_char->if_pak_wb_object~activate( ).

    lo_char->if_pak_wb_object_internal~unlock( ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    rv_bool = cl_cls_attribute=>exists_object_attribute( ms_item-obj_name ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.

  METHOD zif_abapgit_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = abap_false.
  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'
        object_name         = ms_item-obj_name
        object_type         = ms_item-obj_type
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( |Error from RS_TOOL_ACCESS, CHAR| ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: ls_char TYPE ty_char.

    CONSTANTS: lc_active TYPE c LENGTH 1 VALUE 'A'.

    SELECT SINGLE * FROM cls_attribute INTO ls_char-cls_attribute
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.
* todo, ASSIGNMENT_DEVC?

    CLEAR: ls_char-cls_attribute-created_by,
           ls_char-cls_attribute-created_on,
           ls_char-cls_attribute-changed_by,
           ls_char-cls_attribute-changed_on.

    SELECT * FROM cls_attributet INTO TABLE ls_char-cls_attributet
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.

    SELECT * FROM cls_attr_value INTO TABLE ls_char-cls_attr_value
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.

    SELECT * FROM cls_attr_valuet INTO TABLE ls_char-cls_attr_valuet
      WHERE name = ms_item-obj_name
      AND activation_state = lc_active.

    io_xml->add( iv_name = 'CHAR'
                 ig_data = ls_char ).

  ENDMETHOD.
ENDCLASS.

implement is_locked

CHAR: implement is_locked


CLASS zcl_abapgit_gui_page_sett_pers DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_gui_component
  FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.

    INTERFACES zif_abapgit_gui_event_handler.
    INTERFACES zif_abapgit_gui_renderable.

    CLASS-METHODS create
      RETURNING
        VALUE(ri_page) TYPE REF TO zif_abapgit_gui_renderable
      RAISING
        zcx_abapgit_exception.
    METHODS constructor
      RAISING
        zcx_abapgit_exception.

  PROTECTED SECTION.
  PRIVATE SECTION.

    CONSTANTS:
      BEGIN OF c_id,
        startup                TYPE string VALUE 'startup',
        show_default_repo      TYPE string VALUE 'show_default_repo',
        ui                     TYPE string VALUE 'ui',
        ui_theme               TYPE string VALUE 'ui_theme',
        icon_scaling           TYPE string VALUE 'icon_scaling',
        max_lines              TYPE string VALUE 'max_lines',
        interaction            TYPE string VALUE 'interaction',
        adt_jump_enabled       TYPE string VALUE 'adt_jump_enabled',
        link_hints_enabled     TYPE string VALUE 'link_hints_enabled',
        link_hint_key          TYPE string VALUE 'link_hint_key',
        hotkeys                TYPE string VALUE 'hotkeys',
        resources              TYPE string VALUE 'resources',
        parallel_proc_disabled TYPE string VALUE 'parallel_proc_disabled',
        hide_sapgui_hint       TYPE string VALUE 'hide_sapgui_hint',
        activate_wo_popup      TYPE string VALUE 'activate_wo_popup',
      END OF c_id.
    CONSTANTS:
      BEGIN OF c_event,
        save TYPE string VALUE 'save',
      END OF c_event.

    DATA mo_form TYPE REF TO zcl_abapgit_html_form.
    DATA mo_form_data TYPE REF TO zcl_abapgit_string_map.
    DATA mo_form_util TYPE REF TO zcl_abapgit_html_form_utils.
    DATA mo_validation_log TYPE REF TO zcl_abapgit_string_map.

    DATA mo_settings TYPE REF TO zcl_abapgit_settings.
    DATA ms_settings TYPE zif_abapgit_definitions=>ty_s_user_settings.

    METHODS validate_form
      IMPORTING
        !io_form_data            TYPE REF TO zcl_abapgit_string_map
      RETURNING
        VALUE(ro_validation_log) TYPE REF TO zcl_abapgit_string_map
      RAISING
        zcx_abapgit_exception.
    METHODS get_form_schema
      RETURNING
        VALUE(ro_form) TYPE REF TO zcl_abapgit_html_form.
    METHODS read_settings
      RAISING
        zcx_abapgit_exception.
    METHODS save_settings
      RAISING
        zcx_abapgit_exception.
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE_SETT_PERS IMPLEMENTATION.

  METHOD constructor.

    super->constructor( ).
    CREATE OBJECT mo_validation_log.
    CREATE OBJECT mo_form_data.
    mo_form = get_form_schema( ).
    mo_form_util = zcl_abapgit_html_form_utils=>create( mo_form ).

    read_settings( ).

  ENDMETHOD.

  METHOD create.

    DATA lo_component TYPE REF TO zcl_abapgit_gui_page_sett_pers.

    CREATE OBJECT lo_component.

    ri_page = zcl_abapgit_gui_page_hoc=>create(
      iv_page_title      = 'Personal Settings'
      io_page_menu       = zcl_abapgit_gui_chunk_lib=>settings_toolbar(
                             zif_abapgit_definitions=>c_action-go_settings_personal )
      ii_child_component = lo_component ).

  ENDMETHOD.

  METHOD get_form_schema.

    ro_form = zcl_abapgit_html_form=>create(
      iv_form_id   = 'personal-setting-form'
      iv_help_page = 'https://docs.abapgit.org/guide-settings-personal.html' ).

    ro_form->start_group(
      iv_name          = c_id-startup
      iv_label         = 'Startup'
    )->checkbox(
      iv_name          = c_id-show_default_repo
      iv_label         = 'Show Last Opened Repository'
      iv_hint          = 'Recommended to check, if you are using ADT'
    )->start_group(
      iv_name          = c_id-ui
      iv_label         = 'User Interface'
    )->radio(
      iv_name          = c_id-ui_theme
      iv_default_value = zcl_abapgit_settings=>c_ui_theme-default
      iv_label         = 'Theme'
    )->option(
      iv_label         = 'Default'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-default
    )->option(
      iv_label         = 'Dark'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-dark
    )->option(
      iv_label         = 'Belize'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-belize
    )->option(
      iv_label         = 'Synced with SAP GUI'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-synced_with_gui
    )->radio(
      iv_name          = c_id-icon_scaling
      iv_default_value = ''
      iv_label         = 'Icon Scaling'
    )->option(
      iv_label         = 'Automatic'
      iv_value         = ''
    )->option(
      iv_label         = 'Small'
      iv_value         = zcl_abapgit_settings=>c_icon_scaling-small
    )->option(
      iv_label         = 'Large'
      iv_value         = zcl_abapgit_settings=>c_icon_scaling-large
    )->number(
      iv_name          = c_id-max_lines
      iv_label         = 'List Size'
      iv_hint          = 'Maximum number of objects listed (0 = All)'
      iv_min           = 0
      iv_max           = 10000
    )->start_group(
      iv_name          = c_id-interaction
      iv_label         = 'Interaction'
    )->checkbox(
      iv_name          = c_id-activate_wo_popup
      iv_label         = 'Activate Objects Without Popup'
      iv_hint          = 'Activates objects automatically without showing popup'
    )->checkbox(
      iv_name          = c_id-adt_jump_enabled
      iv_label         = 'Enable Jump to ABAP Development Tools (If Available)'
      iv_hint          = 'Recommended to check, if you are using ADT'
    )->checkbox(
      iv_name          = c_id-link_hints_enabled
      iv_label         = 'Enable Vimium-like Link Hints'
      iv_hint          = 'When you hit the key, abapGit will identify clickable things and put a label beside it'
    )->text(
      iv_name          = c_id-link_hint_key
      iv_label         = 'Key to Activate Link Hints'
      iv_min           = 0
      iv_max           = 1
    )->start_group(
      iv_name          = c_id-resources
      iv_label         = 'System Resources'
    )->checkbox(
      iv_name          = c_id-parallel_proc_disabled
      iv_label         = 'Disable Parallel Processing'
      iv_hint          = 'If disabled, abapGit will use only a single thread to serialize objects'
    )->command(
      iv_label         = 'Save Settings'
      iv_cmd_type      = zif_abapgit_html_form=>c_cmd_type-input_main
      iv_action        = c_event-save
    )->command(
      iv_label         = 'Back'
      iv_action        = zif_abapgit_definitions=>c_action-go_back ).

    " Not available via this form:
    " - User-specific hotkey settings have been discontinued
    " - hide_sapgui_hint is set via ZCL_ABAPGIT_SERVICES_ABAPGIT-CHECK_SAPGUI

  ENDMETHOD.

  METHOD read_settings.

    " Get settings from DB
    mo_settings = zcl_abapgit_persist_factory=>get_settings( )->read( ).
    ms_settings = mo_settings->get_user_settings( ).

    " Startup
    mo_form_data->set(
      iv_key = c_id-show_default_repo
      iv_val = |{ ms_settings-show_default_repo }| ).

    " UI
    mo_form_data->set(
      iv_key = c_id-ui_theme
      iv_val = ms_settings-ui_theme ).
    mo_form_data->set(
      iv_key = c_id-icon_scaling
      iv_val = |{ ms_settings-icon_scaling }| ).
    mo_form_data->set(
      iv_key = c_id-max_lines
      iv_val = |{ ms_settings-max_lines }| ).

    " Interaction
    mo_form_data->set(
      iv_key = c_id-activate_wo_popup
      iv_val = boolc( ms_settings-activate_wo_popup = abap_true ) ) ##TYPE.
    mo_form_data->set(
      iv_key = c_id-adt_jump_enabled
      iv_val = boolc( ms_settings-adt_jump_enabled = abap_true ) ) ##TYPE.
    mo_form_data->set(
      iv_key = c_id-link_hints_enabled
      iv_val = boolc( ms_settings-link_hints_enabled = abap_true ) ) ##TYPE.
    mo_form_data->set(
      iv_key = c_id-link_hint_key
      iv_val = |{ ms_settings-link_hint_key }| ).

    " Resources
    mo_form_data->set(
      iv_key = c_id-parallel_proc_disabled
      iv_val = boolc( ms_settings-parallel_proc_disabled = abap_true ) ) ##TYPE.

    " Set for is_dirty check
    mo_form_util->set_data( mo_form_data ).

  ENDMETHOD.

  METHOD save_settings.

    DATA li_persistence TYPE REF TO zif_abapgit_persist_settings.

    " Startup
    ms_settings-show_default_repo = mo_form_data->get( c_id-show_default_repo ).

    " UI
    ms_settings-ui_theme = mo_form_data->get( c_id-ui_theme ).
    ms_settings-icon_scaling = mo_form_data->get( c_id-icon_scaling ).
    ms_settings-max_lines = mo_form_data->get( c_id-max_lines ).

    " Interaction
    ms_settings-activate_wo_popup = mo_form_data->get( c_id-activate_wo_popup ).
    ms_settings-adt_jump_enabled = mo_form_data->get( c_id-adt_jump_enabled ).
    ms_settings-link_hints_enabled = mo_form_data->get( c_id-link_hints_enabled ).
    ms_settings-link_hint_key = mo_form_data->get( c_id-link_hint_key ).

    " Resources
    ms_settings-parallel_proc_disabled = mo_form_data->get( c_id-parallel_proc_disabled ).

    " Store in DB
    mo_settings->set_user_settings( ms_settings ).

    li_persistence = zcl_abapgit_persist_factory=>get_settings( ).
    li_persistence->modify( mo_settings ).

    COMMIT WORK AND WAIT.

    MESSAGE 'Settings succesfully saved' TYPE 'S'.

    read_settings( ).

  ENDMETHOD.

  METHOD validate_form.

    ro_validation_log = mo_form_util->validate( io_form_data ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    mo_form_data = mo_form_util->normalize( ii_event->form_data( ) ).

    CASE ii_event->mv_action.
      WHEN zif_abapgit_definitions=>c_action-go_back.
        rs_handled-state = mo_form_util->exit( mo_form_data ).

      WHEN c_event-save.
        " Validate form entries before saving
        mo_validation_log = validate_form( mo_form_data ).

        IF mo_validation_log->is_empty( ) = abap_true.
          save_settings( ).
        ENDIF.

        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_renderable~render.

    gui_services( )->register_event_handler( me ).

    IF mo_form_util->is_empty( mo_form_data ) = abap_true.
      read_settings( ).
    ENDIF.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.
    ri_html->add( '
' ).
    ri_html->add( mo_form->render(
      io_values         = mo_form_data
      io_validation_log = mo_validation_log ) ).
    ri_html->add( '
' ).
  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_gui_page_sett_pers DEFINITION
  PUBLIC
  INHERITING FROM zcl_abapgit_gui_component
  FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.

    INTERFACES zif_abapgit_gui_event_handler.
    INTERFACES zif_abapgit_gui_renderable.

    CLASS-METHODS create
      RETURNING
        VALUE(ri_page) TYPE REF TO zif_abapgit_gui_renderable
      RAISING
        zcx_abapgit_exception.
    METHODS constructor
      RAISING
        zcx_abapgit_exception.

  PROTECTED SECTION.
  PRIVATE SECTION.

    CONSTANTS:
      BEGIN OF c_id,
        startup                TYPE string VALUE 'startup',
        show_default_repo      TYPE string VALUE 'show_default_repo',
        ui                     TYPE string VALUE 'ui',
        ui_theme               TYPE string VALUE 'ui_theme',
        icon_scaling           TYPE string VALUE 'icon_scaling',
        max_lines              TYPE string VALUE 'max_lines',
        interaction            TYPE string VALUE 'interaction',
        adt_jump_enabled       TYPE string VALUE 'adt_jump_enabled',
        link_hints_enabled     TYPE string VALUE 'link_hints_enabled',
        link_hint_key          TYPE string VALUE 'link_hint_key',
        hotkeys                TYPE string VALUE 'hotkeys',
        resources              TYPE string VALUE 'resources',
        parallel_proc_disabled TYPE string VALUE 'parallel_proc_disabled',
        hide_sapgui_hint       TYPE string VALUE 'hide_sapgui_hint',
        activate_wo_popup      TYPE string VALUE 'activate_wo_popup',
      END OF c_id.
    CONSTANTS:
      BEGIN OF c_event,
        save TYPE string VALUE 'save',
      END OF c_event.

    DATA mo_form TYPE REF TO zcl_abapgit_html_form.
    DATA mo_form_data TYPE REF TO zcl_abapgit_string_map.
    DATA mo_form_util TYPE REF TO zcl_abapgit_html_form_utils.
    DATA mo_validation_log TYPE REF TO zcl_abapgit_string_map.

    DATA mo_settings TYPE REF TO zcl_abapgit_settings.
    DATA ms_settings TYPE zif_abapgit_definitions=>ty_s_user_settings.

    METHODS validate_form
      IMPORTING
        !io_form_data            TYPE REF TO zcl_abapgit_string_map
      RETURNING
        VALUE(ro_validation_log) TYPE REF TO zcl_abapgit_string_map
      RAISING
        zcx_abapgit_exception.
    METHODS get_form_schema
      RETURNING
        VALUE(ro_form) TYPE REF TO zcl_abapgit_html_form.
    METHODS read_settings
      RAISING
        zcx_abapgit_exception.
    METHODS save_settings
      RAISING
        zcx_abapgit_exception.
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE_SETT_PERS IMPLEMENTATION.

  METHOD constructor.

    super->constructor( ).
    CREATE OBJECT mo_validation_log.
    CREATE OBJECT mo_form_data.
    mo_form = get_form_schema( ).
    mo_form_util = zcl_abapgit_html_form_utils=>create( mo_form ).

    read_settings( ).

  ENDMETHOD.

  METHOD create.

    DATA lo_component TYPE REF TO zcl_abapgit_gui_page_sett_pers.

    CREATE OBJECT lo_component.

    ri_page = zcl_abapgit_gui_page_hoc=>create(
      iv_page_title      = 'Personal Settings'
      io_page_menu       = zcl_abapgit_gui_chunk_lib=>settings_toolbar(
                             zif_abapgit_definitions=>c_action-go_settings_personal )
      ii_child_component = lo_component ).

  ENDMETHOD.

  METHOD get_form_schema.

    ro_form = zcl_abapgit_html_form=>create(
      iv_form_id   = 'personal-setting-form'
      iv_help_page = 'https://docs.abapgit.org/guide-settings-personal.html' ).

    ro_form->start_group(
      iv_name          = c_id-startup
      iv_label         = 'Startup'
    )->checkbox(
      iv_name          = c_id-show_default_repo
      iv_label         = 'Show Last Opened Repository'
      iv_hint          = 'Recommended to check, if you are using ADT'
    )->start_group(
      iv_name          = c_id-ui
      iv_label         = 'User Interface'
    )->radio(
      iv_name          = c_id-ui_theme
      iv_default_value = zcl_abapgit_settings=>c_ui_theme-default
      iv_label         = 'Theme'
    )->option(
      iv_label         = 'Default'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-default
    )->option(
      iv_label         = 'Dark'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-dark
    )->option(
      iv_label         = 'Belize'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-belize
    )->option(
      iv_label         = 'Synced with SAP GUI'
      iv_value         = zcl_abapgit_settings=>c_ui_theme-synced_with_gui
    )->radio(
      iv_name          = c_id-icon_scaling
      iv_default_value = ''
      iv_label         = 'Icon Scaling (HDPI)'
      iv_hint          = 'Adjust size of icons for High DPI displays'
    )->option(
      iv_label         = 'Automatic'
      iv_value         = ''
    )->option(
      iv_label         = 'Small'
      iv_value         = zcl_abapgit_settings=>c_icon_scaling-small
    )->option(
      iv_label         = 'Large'
      iv_value         = zcl_abapgit_settings=>c_icon_scaling-large
    )->number(
      iv_name          = c_id-max_lines
      iv_label         = 'List Size'
      iv_hint          = 'Maximum number of objects listed (0 = All)'
      iv_min           = 0
      iv_max           = 10000
    )->start_group(
      iv_name          = c_id-interaction
      iv_label         = 'Interaction'
    )->checkbox(
      iv_name          = c_id-activate_wo_popup
      iv_label         = 'Activate Objects Without Popup'
      iv_hint          = 'Activates objects automatically without showing popup'
    )->checkbox(
      iv_name          = c_id-adt_jump_enabled
      iv_label         = 'Enable Jump to ABAP Development Tools (If Available)'
      iv_hint          = 'Recommended to check, if you are using ADT'
    )->checkbox(
      iv_name          = c_id-link_hints_enabled
      iv_label         = 'Enable Vimium-like Link Hints'
      iv_hint          = 'When you hit the key, abapGit will identify clickable things and put a label beside it'
    )->text(
      iv_name          = c_id-link_hint_key
      iv_label         = 'Key to Activate Link Hints'
      iv_min           = 0
      iv_max           = 1
    )->start_group(
      iv_name          = c_id-resources
      iv_label         = 'System Resources'
    )->checkbox(
      iv_name          = c_id-parallel_proc_disabled
      iv_label         = 'Disable Parallel Processing'
      iv_hint          = 'If disabled, abapGit will use only a single thread to serialize objects'
    )->command(
      iv_label         = 'Save Settings'
      iv_cmd_type      = zif_abapgit_html_form=>c_cmd_type-input_main
      iv_action        = c_event-save
    )->command(
      iv_label         = 'Back'
      iv_action        = zif_abapgit_definitions=>c_action-go_back ).

    " Not available via this form:
    " - User-specific hotkey settings have been discontinued
    " - hide_sapgui_hint is set via ZCL_ABAPGIT_SERVICES_ABAPGIT-CHECK_SAPGUI

  ENDMETHOD.

  METHOD read_settings.

    " Get settings from DB
    mo_settings = zcl_abapgit_persist_factory=>get_settings( )->read( ).
    ms_settings = mo_settings->get_user_settings( ).

    " Startup
    mo_form_data->set(
      iv_key = c_id-show_default_repo
      iv_val = |{ ms_settings-show_default_repo }| ).

    " UI
    mo_form_data->set(
      iv_key = c_id-ui_theme
      iv_val = ms_settings-ui_theme ).
    mo_form_data->set(
      iv_key = c_id-icon_scaling
      iv_val = |{ ms_settings-icon_scaling }| ).
    mo_form_data->set(
      iv_key = c_id-max_lines
      iv_val = |{ ms_settings-max_lines }| ).

    " Interaction
    mo_form_data->set(
      iv_key = c_id-activate_wo_popup
      iv_val = boolc( ms_settings-activate_wo_popup = abap_true ) ) ##TYPE.
    mo_form_data->set(
      iv_key = c_id-adt_jump_enabled
      iv_val = boolc( ms_settings-adt_jump_enabled = abap_true ) ) ##TYPE.
    mo_form_data->set(
      iv_key = c_id-link_hints_enabled
      iv_val = boolc( ms_settings-link_hints_enabled = abap_true ) ) ##TYPE.
    mo_form_data->set(
      iv_key = c_id-link_hint_key
      iv_val = |{ ms_settings-link_hint_key }| ).

    " Resources
    mo_form_data->set(
      iv_key = c_id-parallel_proc_disabled
      iv_val = boolc( ms_settings-parallel_proc_disabled = abap_true ) ) ##TYPE.

    " Set for is_dirty check
    mo_form_util->set_data( mo_form_data ).

  ENDMETHOD.

  METHOD save_settings.

    DATA li_persistence TYPE REF TO zif_abapgit_persist_settings.

    " Startup
    ms_settings-show_default_repo = mo_form_data->get( c_id-show_default_repo ).

    " UI
    ms_settings-ui_theme = mo_form_data->get( c_id-ui_theme ).
    ms_settings-icon_scaling = mo_form_data->get( c_id-icon_scaling ).
    ms_settings-max_lines = mo_form_data->get( c_id-max_lines ).

    " Interaction
    ms_settings-activate_wo_popup = mo_form_data->get( c_id-activate_wo_popup ).
    ms_settings-adt_jump_enabled = mo_form_data->get( c_id-adt_jump_enabled ).
    ms_settings-link_hints_enabled = mo_form_data->get( c_id-link_hints_enabled ).
    ms_settings-link_hint_key = mo_form_data->get( c_id-link_hint_key ).

    " Resources
    ms_settings-parallel_proc_disabled = mo_form_data->get( c_id-parallel_proc_disabled ).

    " Store in DB
    mo_settings->set_user_settings( ms_settings ).

    li_persistence = zcl_abapgit_persist_factory=>get_settings( ).
    li_persistence->modify( mo_settings ).

    COMMIT WORK AND WAIT.

    MESSAGE 'Settings succesfully saved' TYPE 'S'.

    read_settings( ).

  ENDMETHOD.

  METHOD validate_form.

    ro_validation_log = mo_form_util->validate( io_form_data ).

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    mo_form_data = mo_form_util->normalize( ii_event->form_data( ) ).

    CASE ii_event->mv_action.
      WHEN zif_abapgit_definitions=>c_action-go_back.
        rs_handled-state = mo_form_util->exit( mo_form_data ).

      WHEN c_event-save.
        " Validate form entries before saving
        mo_validation_log = validate_form( mo_form_data ).

        IF mo_validation_log->is_empty( ) = abap_true.
          save_settings( ).
        ENDIF.

        rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_renderable~render.

    gui_services( )->register_event_handler( me ).

    IF mo_form_util->is_empty( mo_form_data ) = abap_true.
      read_settings( ).
    ENDIF.

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.
    ri_html->add( '
' ).
    ri_html->add( mo_form->render(
      io_values         = mo_form_data
      io_validation_log = mo_validation_log ) ).
    ri_html->add( '
' ).
  ENDMETHOD.
ENDCLASS.

UI: Add hint for "icon scaling" setting (#5819)


class ZCL_AOT_SERVICE_REST definition
  public
  create public .

public section.

  interfaces ZIF_AOT_SERVICE .
  interfaces ZIF_SWAG_HANDLER .

  methods LIST
    importing
      !IV_PACKAGE type DEVCLASS
    returning
      value(RT_CLASSES) type ZCL_AOT_BACKEND=>TY_CLASSES .
  methods RUN
    importing
      !IV_CLASS type SEOCLSNAME
    returning
      value(RS_RESULT) type ZCL_AOT_BACKEND=>TY_TEST_RESULT .
protected section.

  constants C_BASE type STRING value '/sap/zabapopentest/rest' ##NO_TEXT.
private section.
ENDCLASS.

CLASS ZCL_AOT_SERVICE_REST IMPLEMENTATION.

  METHOD list.

    rt_classes = zcl_aot_backend=>list_classes( to_upper( iv_package ) ).

  ENDMETHOD.

  METHOD run.

    rs_result = zcl_aot_backend=>run_test( iv_class ).

  ENDMETHOD.

  METHOD zif_aot_service~run.

    DATA: lo_swag TYPE REF TO zcl_swag.

    CREATE OBJECT lo_swag
      EXPORTING
        ii_server = ii_server
        iv_base   = c_base
        iv_title  = 'abapOpenTest'.
    lo_swag->register( me ).

    lo_swag->run( ).

  ENDMETHOD.

  METHOD zif_swag_handler~meta.

    FIELD-SYMBOLS: <ls_meta> LIKE LINE OF rt_meta.

    APPEND INITIAL LINE TO rt_meta ASSIGNING <ls_meta>.
    <ls_meta>-summary   = 'List Classes'(001).
    <ls_meta>-url-regex = '/list$'.
    <ls_meta>-method    = zcl_swag=>c_method-get.
    <ls_meta>-handler   = 'LIST'.

    APPEND INITIAL LINE TO rt_meta ASSIGNING <ls_meta>.
    <ls_meta>-summary   = 'Run Test'(002).
    <ls_meta>-url-regex = '/run$'.
    <ls_meta>-method    = zcl_swag=>c_method-post.
    <ls_meta>-handler   = 'RUN'.

  ENDMETHOD.
ENDCLASS.

class ZCL_AOT_SERVICE_REST definition
  public
  create public .

public section.

  interfaces ZIF_AOT_SERVICE .
  interfaces ZIF_SWAG_HANDLER .

  methods LIST
    importing
      !IV_PACKAGE type DEVCLASS
    returning
      value(RT_CLASSES) type ZCL_AOT_BACKEND=>TY_CLASSES .
  methods RUN
    importing
      !IV_CLASS type SEOCLSNAME
    returning
      value(RS_RESULT) type ZCL_AOT_BACKEND=>TY_TEST_RESULT .
protected section.

  constants C_BASE type STRING value '/sap/zabapopentest/rest' ##NO_TEXT.
private section.
ENDCLASS.

CLASS ZCL_AOT_SERVICE_REST IMPLEMENTATION.

  METHOD list.

    rt_classes = zcl_aot_backend=>list_classes( to_upper( iv_package ) ).

  ENDMETHOD.

  METHOD run.

    rs_result = zcl_aot_backend=>run_test( iv_class ).

  ENDMETHOD.

  METHOD zif_aot_service~run.

    DATA: lo_swag TYPE REF TO zcl_swag.

    CREATE OBJECT lo_swag
      EXPORTING
        ii_server = ii_server
        iv_base   = c_base
        iv_title  = 'abapOpenTest'.
    lo_swag->register( me ).

    lo_swag->run( ).

  ENDMETHOD.

  METHOD zif_swag_handler~meta.

    FIELD-SYMBOLS: <ls_meta> LIKE LINE OF rt_meta.

    APPEND INITIAL LINE TO rt_meta ASSIGNING <ls_meta>.
    <ls_meta>-summary   = 'List Classes'(001).
    <ls_meta>-url-regex = '/list$'.
    <ls_meta>-method    = zcl_swag=>c_method-get.
    <ls_meta>-handler   = 'LIST'.
    APPEND 'auto_runner' TO <ls_meta>-tags.

    APPEND INITIAL LINE TO rt_meta ASSIGNING <ls_meta>.
    <ls_meta>-summary   = 'Run Test'(002).
    <ls_meta>-url-regex = '/run$'.
    <ls_meta>-method    = zcl_swag=>c_method-post.
    <ls_meta>-handler   = 'RUN'.
    APPEND 'auto_runner' TO <ls_meta>-tags.

  ENDMETHOD.
ENDCLASS.

add tags

add tags


CLASS zcl_abapgit_repo_content_list DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    METHODS constructor
      IMPORTING io_repo TYPE REF TO zcl_abapgit_repo.

    METHODS list
      IMPORTING iv_path              TYPE string
                iv_by_folders        TYPE abap_bool
                iv_changes_only      TYPE abap_bool
      RETURNING VALUE(rt_repo_items) TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS get_log
      RETURNING VALUE(ri_log) TYPE REF TO zif_abapgit_log.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CONSTANTS: BEGIN OF c_sortkey,
                 default    TYPE i VALUE 9999,
                 parent_dir TYPE i VALUE 0,
                 dir        TYPE i VALUE 1,
                 orphan     TYPE i VALUE 2,
                 changed    TYPE i VALUE 3,
                 inactive   TYPE i VALUE 4,
               END OF c_sortkey.

    DATA: mo_repo TYPE REF TO zcl_abapgit_repo,
          mi_log  TYPE REF TO zif_abapgit_log.

    METHODS build_repo_items_local_only
      RETURNING VALUE(rt_repo_items) TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS build_repo_items_with_remote
      RETURNING VALUE(rt_repo_items) TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS build_folders
      IMPORTING iv_cur_dir    TYPE string
      CHANGING  ct_repo_items TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS filter_changes
      CHANGING ct_repo_items TYPE zif_abapgit_definitions=>ty_repo_item_tt.

    METHODS check_repo_size
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_REPO_CONTENT_LIST IMPLEMENTATION.

  METHOD build_folders.

    DATA: lv_index    TYPE i,
          lt_subitems LIKE ct_repo_items,
          ls_subitem  LIKE LINE OF ct_repo_items,
          ls_folder   LIKE LINE OF ct_repo_items.

    FIELD-SYMBOLS <ls_item> LIKE LINE OF ct_repo_items.

    LOOP AT ct_repo_items ASSIGNING <ls_item>.
      lv_index = sy-tabix.
      CHECK <ls_item>-path <> iv_cur_dir. " files in target dir - just leave them be

      IF zcl_abapgit_path=>is_subdir( iv_path = <ls_item>-path
                                      iv_parent = iv_cur_dir ) = abap_true.
        ls_subitem-changes = <ls_item>-changes.
        ls_subitem-path    = <ls_item>-path.
        ls_subitem-lstate  = <ls_item>-lstate.
        ls_subitem-rstate  = <ls_item>-rstate.
        APPEND ls_subitem TO lt_subitems.
      ENDIF.

      DELETE ct_repo_items INDEX lv_index.
    ENDLOOP.

    SORT lt_subitems BY path ASCENDING.

    LOOP AT lt_subitems ASSIGNING <ls_item>.
      AT NEW path.
        CLEAR ls_folder.
        ls_folder-path    = <ls_item>-path.
        ls_folder-sortkey = c_sortkey-dir. " Directory
        ls_folder-is_dir  = abap_true.
      ENDAT.

      ls_folder-changes = ls_folder-changes + <ls_item>-changes.

      zcl_abapgit_state=>reduce( EXPORTING iv_cur = <ls_item>-lstate
                                 CHANGING cv_prev = ls_folder-lstate ).
      zcl_abapgit_state=>reduce( EXPORTING iv_cur = <ls_item>-rstate
                                 CHANGING cv_prev = ls_folder-rstate ).

      AT END OF path.
        APPEND ls_folder TO ct_repo_items.
      ENDAT.
    ENDLOOP.

  ENDMETHOD.

  METHOD build_repo_items_local_only.

    DATA: lt_tadir TYPE zif_abapgit_definitions=>ty_tadir_tt,
          ls_item  TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_repo_item> LIKE LINE OF rt_repo_items,
                   <ls_tadir>     LIKE LINE OF lt_tadir.

    lt_tadir = zcl_abapgit_factory=>get_tadir( )->read(
      iv_package = mo_repo->get_package( )
      io_dot     = mo_repo->get_dot_abapgit( ) ).

    LOOP AT lt_tadir ASSIGNING <ls_tadir>.
      APPEND INITIAL LINE TO rt_repo_items ASSIGNING <ls_repo_item>.
      <ls_repo_item>-obj_type = <ls_tadir>-object.
      <ls_repo_item>-obj_name = <ls_tadir>-obj_name.
      <ls_repo_item>-path     = <ls_tadir>-path.
      MOVE-CORRESPONDING <ls_repo_item> TO ls_item.
      <ls_repo_item>-inactive = boolc( zcl_abapgit_objects=>is_active( ls_item ) = abap_false ).
      IF <ls_repo_item>-inactive = abap_true.
        <ls_repo_item>-sortkey = c_sortkey-inactive.
      ELSE.
        <ls_repo_item>-sortkey  = c_sortkey-default.      " Default sort key
      ENDIF.

      IF <ls_repo_item>-obj_type IS NOT INITIAL.
        MOVE-CORRESPONDING <ls_repo_item> TO ls_item.
* foo        <ls_repo_item>-changed_by = zcl_abapgit_objects=>changed_by( ls_item ).
        CLEAR ls_item.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

  METHOD build_repo_items_with_remote.

    DATA:
      ls_file   TYPE zif_abapgit_definitions=>ty_repo_file,
      lt_status TYPE zif_abapgit_definitions=>ty_results_tt,
      ls_item   TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_status>    LIKE LINE OF lt_status,
                   <ls_repo_item> LIKE LINE OF rt_repo_items.

    lt_status = mo_repo->status( mi_log ).

    LOOP AT lt_status ASSIGNING <ls_status>.
      AT NEW obj_name. "obj_type + obj_name
        APPEND INITIAL LINE TO rt_repo_items ASSIGNING <ls_repo_item>.
        <ls_repo_item>-obj_type = <ls_status>-obj_type.
        <ls_repo_item>-obj_name = <ls_status>-obj_name.
        <ls_repo_item>-inactive = <ls_status>-inactive.
        <ls_repo_item>-sortkey  = c_sortkey-default. " Default sort key
        <ls_repo_item>-changes  = 0.
        <ls_repo_item>-path     = <ls_status>-path.
      ENDAT.

      IF <ls_status>-filename IS NOT INITIAL.
        ls_file-path       = <ls_status>-path.
        ls_file-filename   = <ls_status>-filename.
        ls_file-is_changed = boolc( <ls_status>-match = abap_false ). " TODO refactor
        ls_file-rstate     = <ls_status>-rstate.
        ls_file-lstate     = <ls_status>-lstate.
        APPEND ls_file TO <ls_repo_item>-files.

        IF <ls_status>-inactive = abap_true
            AND <ls_repo_item>-sortkey > c_sortkey-changed.
          <ls_repo_item>-sortkey = c_sortkey-inactive.
        ENDIF.

        IF ls_file-is_changed = abap_true.
          <ls_repo_item>-sortkey = c_sortkey-changed. " Changed files
          <ls_repo_item>-changes = <ls_repo_item>-changes + 1.

          zcl_abapgit_state=>reduce( EXPORTING iv_cur = ls_file-lstate
                                     CHANGING cv_prev = <ls_repo_item>-lstate ).
          zcl_abapgit_state=>reduce( EXPORTING iv_cur = ls_file-rstate
                                     CHANGING cv_prev = <ls_repo_item>-rstate ).
        ENDIF.
      ENDIF.

      IF <ls_repo_item>-changes > 0 AND <ls_repo_item>-obj_type IS NOT INITIAL.
        MOVE-CORRESPONDING <ls_repo_item> TO ls_item.
* bar        <ls_repo_item>-changed_by = zcl_abapgit_objects=>changed_by( ls_item ).
        CLEAR ls_item.
      ENDIF.

      AT END OF obj_name. "obj_type + obj_name
        IF <ls_repo_item>-obj_type IS INITIAL.
          <ls_repo_item>-sortkey = c_sortkey-orphan. "Virtual objects
        ENDIF.
      ENDAT.
    ENDLOOP.

  ENDMETHOD.

  METHOD check_repo_size.

    CONSTANTS lc_new_repo_size TYPE i VALUE 10.

    DATA lt_remote TYPE zif_abapgit_definitions=>ty_files_tt.

    lt_remote = mo_repo->get_files_remote( ).

    IF lines( lt_remote ) > lc_new_repo_size.
      " Less files means it's a new repo (with just readme and license, for example) which is ok
      READ TABLE lt_remote TRANSPORTING NO FIELDS
        WITH KEY path = zif_abapgit_definitions=>c_root_dir
        filename = zif_abapgit_definitions=>c_dot_abapgit.
      IF sy-subrc <> 0.
        mi_log->add_warning( |Cannot find .abapgit.xml - Is this an abapGit repository?| ).
      ENDIF.
    ENDIF.

  ENDMETHOD.

  METHOD constructor.
    mo_repo = io_repo.
    CREATE OBJECT mi_log TYPE zcl_abapgit_log.
  ENDMETHOD.

  METHOD filter_changes.

    FIELD-SYMBOLS: <ls_item> TYPE zif_abapgit_definitions=>ty_repo_item.

    DELETE ct_repo_items WHERE changes = 0 AND inactive = abap_false.
    LOOP AT ct_repo_items ASSIGNING <ls_item> WHERE inactive = abap_false.
      DELETE <ls_item>-files WHERE is_changed = abap_false.
    ENDLOOP.
  ENDMETHOD.

  METHOD get_log.
    DATA li_repo_log TYPE REF TO zif_abapgit_log.
    DATA lt_repo_msg TYPE zif_abapgit_log=>ty_log_outs.
    DATA lr_repo_msg TYPE REF TO zif_abapgit_log=>ty_log_out.

    ri_log = mi_log.

    "add warning and error messages from repo log
    li_repo_log = mo_repo->get_log( ).
    IF li_repo_log IS BOUND.
      lt_repo_msg = li_repo_log->get_messages( ).
      LOOP AT lt_repo_msg REFERENCE INTO lr_repo_msg WHERE type CA 'EW'.
        CASE lr_repo_msg->type.
          WHEN 'E'.
            ri_log->add_error( lr_repo_msg->text ).
          WHEN 'W'.
            ri_log->add_warning( lr_repo_msg->text ).
          WHEN OTHERS.
            CONTINUE.
        ENDCASE.
      ENDLOOP.
    ENDIF.
  ENDMETHOD.

  METHOD list.

    mi_log->clear( ).

    IF mo_repo->has_remote_source( ) = abap_true.
      rt_repo_items = build_repo_items_with_remote( ).
      check_repo_size( ).
    ELSE.
      rt_repo_items = build_repo_items_local_only( ).
    ENDIF.

    IF iv_by_folders = abap_true.
      build_folders(
        EXPORTING iv_cur_dir    = iv_path
        CHANGING  ct_repo_items = rt_repo_items ).
    ENDIF.

    IF iv_changes_only = abap_true.
      " There are never changes for offline repositories
      filter_changes( CHANGING ct_repo_items = rt_repo_items ).
    ENDIF.

    SORT rt_repo_items BY
      sortkey ASCENDING
      path ASCENDING
      obj_name ASCENDING.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_repo_content_list DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    METHODS constructor
      IMPORTING io_repo TYPE REF TO zcl_abapgit_repo.

    METHODS list
      IMPORTING iv_path              TYPE string
                iv_by_folders        TYPE abap_bool
                iv_changes_only      TYPE abap_bool
      RETURNING VALUE(rt_repo_items) TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS get_log
      RETURNING VALUE(ri_log) TYPE REF TO zif_abapgit_log.
  PROTECTED SECTION.
  PRIVATE SECTION.
    CONSTANTS: BEGIN OF c_sortkey,
                 default    TYPE i VALUE 9999,
                 parent_dir TYPE i VALUE 0,
                 dir        TYPE i VALUE 1,
                 orphan     TYPE i VALUE 2,
                 changed    TYPE i VALUE 3,
                 inactive   TYPE i VALUE 4,
               END OF c_sortkey.

    DATA: mo_repo TYPE REF TO zcl_abapgit_repo,
          mi_log  TYPE REF TO zif_abapgit_log.

    METHODS build_repo_items_local_only
      RETURNING VALUE(rt_repo_items) TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS build_repo_items_with_remote
      RETURNING VALUE(rt_repo_items) TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS build_folders
      IMPORTING iv_cur_dir    TYPE string
      CHANGING  ct_repo_items TYPE zif_abapgit_definitions=>ty_repo_item_tt
      RAISING   zcx_abapgit_exception.

    METHODS filter_changes
      CHANGING ct_repo_items TYPE zif_abapgit_definitions=>ty_repo_item_tt.

    METHODS check_repo_size
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_REPO_CONTENT_LIST IMPLEMENTATION.

  METHOD build_folders.

    DATA: lv_index    TYPE i,
          lt_subitems LIKE ct_repo_items,
          ls_subitem  LIKE LINE OF ct_repo_items,
          ls_folder   LIKE LINE OF ct_repo_items.

    FIELD-SYMBOLS <ls_item> LIKE LINE OF ct_repo_items.

    LOOP AT ct_repo_items ASSIGNING <ls_item>.
      lv_index = sy-tabix.
      CHECK <ls_item>-path <> iv_cur_dir. " files in target dir - just leave them be

      IF zcl_abapgit_path=>is_subdir( iv_path = <ls_item>-path
                                      iv_parent = iv_cur_dir ) = abap_true.
        ls_subitem-changes = <ls_item>-changes.
        ls_subitem-path    = <ls_item>-path.
        ls_subitem-lstate  = <ls_item>-lstate.
        ls_subitem-rstate  = <ls_item>-rstate.
        APPEND ls_subitem TO lt_subitems.
      ENDIF.

      DELETE ct_repo_items INDEX lv_index.
    ENDLOOP.

    SORT lt_subitems BY path ASCENDING.

    LOOP AT lt_subitems ASSIGNING <ls_item>.
      AT NEW path.
        CLEAR ls_folder.
        ls_folder-path    = <ls_item>-path.
        ls_folder-sortkey = c_sortkey-dir. " Directory
        ls_folder-is_dir  = abap_true.
      ENDAT.

      ls_folder-changes = ls_folder-changes + <ls_item>-changes.

      zcl_abapgit_state=>reduce( EXPORTING iv_cur = <ls_item>-lstate
                                 CHANGING cv_prev = ls_folder-lstate ).
      zcl_abapgit_state=>reduce( EXPORTING iv_cur = <ls_item>-rstate
                                 CHANGING cv_prev = ls_folder-rstate ).

      AT END OF path.
        APPEND ls_folder TO ct_repo_items.
      ENDAT.
    ENDLOOP.

  ENDMETHOD.

  METHOD build_repo_items_local_only.

    DATA: lt_tadir TYPE zif_abapgit_definitions=>ty_tadir_tt,
          ls_item  TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_repo_item> LIKE LINE OF rt_repo_items,
                   <ls_tadir>     LIKE LINE OF lt_tadir.

    lt_tadir = zcl_abapgit_factory=>get_tadir( )->read(
      iv_package = mo_repo->get_package( )
      io_dot     = mo_repo->get_dot_abapgit( ) ).

    LOOP AT lt_tadir ASSIGNING <ls_tadir>.
      APPEND INITIAL LINE TO rt_repo_items ASSIGNING <ls_repo_item>.
      <ls_repo_item>-obj_type = <ls_tadir>-object.
      <ls_repo_item>-obj_name = <ls_tadir>-obj_name.
      <ls_repo_item>-path     = <ls_tadir>-path.
      MOVE-CORRESPONDING <ls_repo_item> TO ls_item.
      <ls_repo_item>-inactive = boolc( zcl_abapgit_objects=>is_active( ls_item ) = abap_false ).
      IF <ls_repo_item>-inactive = abap_true.
        <ls_repo_item>-sortkey = c_sortkey-inactive.
      ELSE.
        <ls_repo_item>-sortkey  = c_sortkey-default.      " Default sort key
      ENDIF.

      IF <ls_repo_item>-obj_type IS NOT INITIAL.
        MOVE-CORRESPONDING <ls_repo_item> TO ls_item.
        IF zcl_abapgit_objects=>exists( ls_item ) = abap_true.
          <ls_repo_item>-changed_by = zcl_abapgit_objects=>changed_by( ls_item ).
        ENDIF.
        CLEAR ls_item.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

  METHOD build_repo_items_with_remote.

    DATA:
      ls_file   TYPE zif_abapgit_definitions=>ty_repo_file,
      lt_status TYPE zif_abapgit_definitions=>ty_results_tt,
      ls_item   TYPE zif_abapgit_definitions=>ty_item.

    FIELD-SYMBOLS: <ls_status>    LIKE LINE OF lt_status,
                   <ls_repo_item> LIKE LINE OF rt_repo_items.

    lt_status = mo_repo->status( mi_log ).

    LOOP AT lt_status ASSIGNING <ls_status>.
      AT NEW obj_name. "obj_type + obj_name
        APPEND INITIAL LINE TO rt_repo_items ASSIGNING <ls_repo_item>.
        <ls_repo_item>-obj_type = <ls_status>-obj_type.
        <ls_repo_item>-obj_name = <ls_status>-obj_name.
        <ls_repo_item>-inactive = <ls_status>-inactive.
        <ls_repo_item>-sortkey  = c_sortkey-default. " Default sort key
        <ls_repo_item>-changes  = 0.
        <ls_repo_item>-path     = <ls_status>-path.
      ENDAT.

      IF <ls_status>-filename IS NOT INITIAL.
        ls_file-path       = <ls_status>-path.
        ls_file-filename   = <ls_status>-filename.
        ls_file-is_changed = boolc( <ls_status>-match = abap_false ). " TODO refactor
        ls_file-rstate     = <ls_status>-rstate.
        ls_file-lstate     = <ls_status>-lstate.
        APPEND ls_file TO <ls_repo_item>-files.

        IF <ls_status>-inactive = abap_true
            AND <ls_repo_item>-sortkey > c_sortkey-changed.
          <ls_repo_item>-sortkey = c_sortkey-inactive.
        ENDIF.

        IF ls_file-is_changed = abap_true.
          <ls_repo_item>-sortkey = c_sortkey-changed. " Changed files
          <ls_repo_item>-changes = <ls_repo_item>-changes + 1.

          zcl_abapgit_state=>reduce( EXPORTING iv_cur = ls_file-lstate
                                     CHANGING cv_prev = <ls_repo_item>-lstate ).
          zcl_abapgit_state=>reduce( EXPORTING iv_cur = ls_file-rstate
                                     CHANGING cv_prev = <ls_repo_item>-rstate ).
        ENDIF.
      ENDIF.

      IF <ls_repo_item>-changes > 0 AND <ls_repo_item>-obj_type IS NOT INITIAL.
        MOVE-CORRESPONDING <ls_repo_item> TO ls_item.
        IF zcl_abapgit_objects=>exists( ls_item ) = abap_true.
          <ls_repo_item>-changed_by = zcl_abapgit_objects=>changed_by( ls_item ).
        ENDIF.
        CLEAR ls_item.
      ENDIF.

      AT END OF obj_name. "obj_type + obj_name
        IF <ls_repo_item>-obj_type IS INITIAL.
          <ls_repo_item>-sortkey = c_sortkey-orphan. "Virtual objects
        ENDIF.
      ENDAT.
    ENDLOOP.

  ENDMETHOD.

  METHOD check_repo_size.

    CONSTANTS lc_new_repo_size TYPE i VALUE 10.

    DATA lt_remote TYPE zif_abapgit_definitions=>ty_files_tt.

    lt_remote = mo_repo->get_files_remote( ).

    IF lines( lt_remote ) > lc_new_repo_size.
      " Less files means it's a new repo (with just readme and license, for example) which is ok
      READ TABLE lt_remote TRANSPORTING NO FIELDS
        WITH KEY path = zif_abapgit_definitions=>c_root_dir
        filename = zif_abapgit_definitions=>c_dot_abapgit.
      IF sy-subrc <> 0.
        mi_log->add_warning( |Cannot find .abapgit.xml - Is this an abapGit repository?| ).
      ENDIF.
    ENDIF.

  ENDMETHOD.

  METHOD constructor.
    mo_repo = io_repo.
    CREATE OBJECT mi_log TYPE zcl_abapgit_log.
  ENDMETHOD.

  METHOD filter_changes.

    FIELD-SYMBOLS: <ls_item> TYPE zif_abapgit_definitions=>ty_repo_item.

    DELETE ct_repo_items WHERE changes = 0 AND inactive = abap_false.
    LOOP AT ct_repo_items ASSIGNING <ls_item> WHERE inactive = abap_false.
      DELETE <ls_item>-files WHERE is_changed = abap_false.
    ENDLOOP.
  ENDMETHOD.

  METHOD get_log.
    DATA li_repo_log TYPE REF TO zif_abapgit_log.
    DATA lt_repo_msg TYPE zif_abapgit_log=>ty_log_outs.
    DATA lr_repo_msg TYPE REF TO zif_abapgit_log=>ty_log_out.

    ri_log = mi_log.

    "add warning and error messages from repo log
    li_repo_log = mo_repo->get_log( ).
    IF li_repo_log IS BOUND.
      lt_repo_msg = li_repo_log->get_messages( ).
      LOOP AT lt_repo_msg REFERENCE INTO lr_repo_msg WHERE type CA 'EW'.
        CASE lr_repo_msg->type.
          WHEN 'E'.
            ri_log->add_error( lr_repo_msg->text ).
          WHEN 'W'.
            ri_log->add_warning( lr_repo_msg->text ).
          WHEN OTHERS.
            CONTINUE.
        ENDCASE.
      ENDLOOP.
    ENDIF.
  ENDMETHOD.

  METHOD list.

    mi_log->clear( ).

    IF mo_repo->has_remote_source( ) = abap_true.
      rt_repo_items = build_repo_items_with_remote( ).
      check_repo_size( ).
    ELSE.
      rt_repo_items = build_repo_items_local_only( ).
    ENDIF.

    IF iv_by_folders = abap_true.
      build_folders(
        EXPORTING iv_cur_dir    = iv_path
        CHANGING  ct_repo_items = rt_repo_items ).
    ENDIF.

    IF iv_changes_only = abap_true.
      " There are never changes for offline repositories
      filter_changes( CHANGING ct_repo_items = rt_repo_items ).
    ENDIF.

    SORT rt_repo_items BY
      sortkey ASCENDING
      path ASCENDING
      obj_name ASCENDING.

  ENDMETHOD.
ENDCLASS.

check exists() before changed_by() (#4925)

Co-authored-by: Christian Günter <c51eabdc19271264951aa154d4298536d9372b60@googlemail.com>


CLASS zcl_abapgit_persist_migrate DEFINITION PUBLIC CREATE PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS: run RAISING zcx_abapgit_exception.

  PROTECTED SECTION.
  PRIVATE SECTION.
    TYPES: BEGIN OF ty_setting_to_migrate,
             name  TYPE string,
             value TYPE string,
           END OF ty_setting_to_migrate,
           ty_settings_to_migrate TYPE STANDARD TABLE OF ty_setting_to_migrate
                                        WITH NON-UNIQUE DEFAULT KEY.

    CONSTANTS c_text TYPE string VALUE 'Generated by abapGit' ##NO_TEXT.

    CLASS-METHODS table_create
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS table_exists
      RETURNING
        VALUE(rv_exists) TYPE abap_bool .
    CLASS-METHODS lock_create
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS lock_exists
      RETURNING
        VALUE(rv_exists) TYPE abap_bool .
    CLASS-METHODS migrate_settings
      RAISING
        zcx_abapgit_exception.
    CLASS-METHODS migrate_setting
      IMPORTING
        iv_name                TYPE string
      CHANGING
        ct_settings_to_migrate TYPE ty_settings_to_migrate
        ci_document            TYPE REF TO if_ixml_document.
    CLASS-METHODS distribute_settings_to_users
      IMPORTING
        it_settings_to_migrate TYPE ty_settings_to_migrate
      RAISING
        zcx_abapgit_exception.
    CLASS-METHODS update_global_settings
      IMPORTING
        ii_document TYPE REF TO if_ixml_document
      RAISING
        zcx_abapgit_exception.
    CLASS-METHODS read_global_settings_xml
      RETURNING
        VALUE(rv_global_settings_xml) TYPE string
      RAISING
        zcx_abapgit_not_found.
    CLASS-METHODS get_global_settings_document
      RETURNING
        VALUE(ri_global_settings_dom) TYPE REF TO if_ixml_document
      RAISING
        zcx_abapgit_not_found.

ENDCLASS.

CLASS zcl_abapgit_persist_migrate IMPLEMENTATION.

  METHOD distribute_settings_to_users.

    TYPES: ty_char12 TYPE c LENGTH 12.

    DATA: lt_abapgit_users    TYPE STANDARD TABLE OF ty_char12
                                   WITH NON-UNIQUE DEFAULT KEY,
          ls_user_settings    TYPE zif_abapgit_definitions=>ty_s_user_settings,
          li_user_persistence TYPE REF TO zif_abapgit_persist_user.

    FIELD-SYMBOLS: <lv_user>                      LIKE LINE OF lt_abapgit_users,
                   <ls_setting_to_migrate>        TYPE ty_setting_to_migrate,
                   <lg_user_specific_setting_val> TYPE data.

    " distribute settings to all abapGit users
    SELECT value FROM (zcl_abapgit_persistence_db=>c_tabname)
                 INTO TABLE lt_abapgit_users
                 WHERE type = zcl_abapgit_persistence_db=>c_type_user.

    LOOP AT lt_abapgit_users ASSIGNING <lv_user>.

      li_user_persistence = zcl_abapgit_persistence_user=>get_instance( <lv_user> ).

      ls_user_settings = li_user_persistence->get_settings( ).

      LOOP AT it_settings_to_migrate ASSIGNING <ls_setting_to_migrate>.

        ASSIGN COMPONENT <ls_setting_to_migrate>-name
               OF STRUCTURE ls_user_settings
               TO <lg_user_specific_setting_val>.
        ASSERT sy-subrc = 0.

        <lg_user_specific_setting_val> = <ls_setting_to_migrate>-value.

      ENDLOOP.

      li_user_persistence->set_settings( ls_user_settings ).

    ENDLOOP.

  ENDMETHOD.

  METHOD get_global_settings_document.

    DATA: lv_global_settings_xml TYPE string.

    lv_global_settings_xml = read_global_settings_xml( ).

    ri_global_settings_dom = cl_ixml_80_20=>parse_to_document( stream_string = lv_global_settings_xml ).

  ENDMETHOD.

  METHOD lock_create.

    DATA: lv_obj_name TYPE tadir-obj_name,
          ls_dd25v    TYPE dd25v,
          lt_dd26e    TYPE STANDARD TABLE OF dd26e WITH DEFAULT KEY,
          lt_dd27p    TYPE STANDARD TABLE OF dd27p WITH DEFAULT KEY.

    FIELD-SYMBOLS: <ls_dd26e> LIKE LINE OF lt_dd26e,
                   <ls_dd27p> LIKE LINE OF lt_dd27p.

    ls_dd25v-viewname   = zcl_abapgit_persistence_db=>c_lock.
    ls_dd25v-aggtype    = 'E'.
    ls_dd25v-roottab    = zcl_abapgit_persistence_db=>c_tabname.
    ls_dd25v-ddlanguage = zif_abapgit_definitions=>c_english.
    ls_dd25v-ddtext     = c_text.

    APPEND INITIAL LINE TO lt_dd26e ASSIGNING <ls_dd26e>.
    <ls_dd26e>-viewname   = zcl_abapgit_persistence_db=>c_lock.
    <ls_dd26e>-tabname    = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd26e>-tabpos     = '0001'.
    <ls_dd26e>-fortabname = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd26e>-enqmode    = 'E'.

    APPEND INITIAL LINE TO lt_dd27p ASSIGNING <ls_dd27p>.
    <ls_dd27p>-viewname  = zcl_abapgit_persistence_db=>c_lock.
    <ls_dd27p>-objpos    = '0001'.
    <ls_dd27p>-viewfield = 'TYPE'.
    <ls_dd27p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd27p>-fieldname = 'TYPE'.
    <ls_dd27p>-keyflag   = abap_true.

    APPEND INITIAL LINE TO lt_dd27p ASSIGNING <ls_dd27p>.
    <ls_dd27p>-viewname  = zcl_abapgit_persistence_db=>c_lock.
    <ls_dd27p>-objpos    = '0002'.
    <ls_dd27p>-viewfield = 'VALUE'.
    <ls_dd27p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd27p>-fieldname = 'VALUE'.
    <ls_dd27p>-keyflag   = abap_true.

    CALL FUNCTION 'DDIF_ENQU_PUT'
      EXPORTING
        name              = zcl_abapgit_persistence_db=>c_lock
        dd25v_wa          = ls_dd25v
      TABLES
        dd26e_tab         = lt_dd26e
        dd27p_tab         = lt_dd27p
      EXCEPTIONS
        enqu_not_found    = 1
        name_inconsistent = 2
        enqu_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    lv_obj_name = zcl_abapgit_persistence_db=>c_lock.
    CALL FUNCTION 'TR_TADIR_INTERFACE'
      EXPORTING
        wi_tadir_pgmid    = 'R3TR'
        wi_tadir_object   = 'ENQU'
        wi_tadir_obj_name = lv_obj_name
        wi_set_genflag    = abap_true
        wi_test_modus     = abap_false
        wi_tadir_devclass = '$TMP'
      EXCEPTIONS
        OTHERS            = 1.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    CALL FUNCTION 'DDIF_ENQU_ACTIVATE'
      EXPORTING
        name        = zcl_abapgit_persistence_db=>c_lock
      EXCEPTIONS
        not_found   = 1
        put_failure = 2
        OTHERS      = 3.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'migrate, error from DDIF_ENQU_ACTIVATE' ).
    ENDIF.

  ENDMETHOD.

  METHOD lock_exists.

    DATA: lv_viewname TYPE dd25l-viewname.

    SELECT SINGLE viewname FROM dd25l INTO lv_viewname
      WHERE viewname = zcl_abapgit_persistence_db=>c_lock.
    rv_exists = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD migrate_setting.

    DATA: li_element            TYPE REF TO if_ixml_element,
          ls_setting_to_migrate LIKE LINE OF ct_settings_to_migrate.

    li_element = ci_document->find_from_name( iv_name ).
    IF li_element IS BOUND.

      " The element is present in the global config.
      " Therefore we have to migrate it

      ls_setting_to_migrate-name = iv_name.
      ls_setting_to_migrate-value = li_element->get_value( ).
      INSERT ls_setting_to_migrate INTO TABLE ct_settings_to_migrate.

      li_element->remove_node( ).

    ENDIF.

  ENDMETHOD.

  METHOD migrate_settings.

    DATA: li_global_settings_document TYPE REF TO if_ixml_document,
          lt_settings_to_migrate      TYPE ty_settings_to_migrate,
          lx_error                    TYPE REF TO zcx_abapgit_not_found.

    " migrate global settings to user specific settings

    TRY.
        li_global_settings_document = get_global_settings_document( ).

      CATCH zcx_abapgit_not_found INTO lx_error.
        " No global settings available, nothing todo.
        RETURN.
    ENDTRY.

    migrate_setting(
      EXPORTING
        iv_name                = |MAX_LINES|
      CHANGING
        ct_settings_to_migrate = lt_settings_to_migrate
        ci_document            = li_global_settings_document ).

    migrate_setting(
      EXPORTING
        iv_name                = |ADT_JUMP_ENABLED|
      CHANGING
        ct_settings_to_migrate = lt_settings_to_migrate
        ci_document            = li_global_settings_document ).

    IF lines( lt_settings_to_migrate ) > 0.

      distribute_settings_to_users( lt_settings_to_migrate ).

      update_global_settings( li_global_settings_document ).

    ENDIF.

  ENDMETHOD.

  METHOD read_global_settings_xml.

    rv_global_settings_xml = zcl_abapgit_persistence_db=>get_instance( )->read(
        iv_type  = zcl_abapgit_persistence_db=>c_type_settings
        iv_value = '' ).

  ENDMETHOD.

  METHOD run.

    IF table_exists( ) = abap_false.
      table_create( ).
    ENDIF.

    IF lock_exists( ) = abap_false.
      lock_create( ).
    ENDIF.

    migrate_settings( ).

  ENDMETHOD.

  METHOD table_create.

    DATA: lv_rc       LIKE sy-subrc,
          lv_obj_name TYPE tadir-obj_name,
          ls_dd02v    TYPE dd02v,
          ls_dd09l    TYPE dd09l,
          lt_dd03p    TYPE STANDARD TABLE OF dd03p WITH DEFAULT KEY.

    FIELD-SYMBOLS: <ls_dd03p> LIKE LINE OF lt_dd03p.

    ls_dd02v-tabname    = zcl_abapgit_persistence_db=>c_tabname.
    ls_dd02v-ddlanguage = zif_abapgit_definitions=>c_english.
    ls_dd02v-tabclass   = 'TRANSP'.
    ls_dd02v-ddtext     = c_text.
    ls_dd02v-contflag   = 'L'.
    ls_dd02v-exclass    = '1'.

    ls_dd09l-tabname  = zcl_abapgit_persistence_db=>c_tabname.
    ls_dd09l-as4local = 'A'.
    ls_dd09l-tabkat   = '1'.
    ls_dd09l-tabart   = 'APPL1'.
    ls_dd09l-bufallow = 'N'.

    APPEND INITIAL LINE TO lt_dd03p ASSIGNING <ls_dd03p>.
    <ls_dd03p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd03p>-fieldname = 'TYPE'.
    <ls_dd03p>-position  = '0001'.
    <ls_dd03p>-keyflag   = 'X'.
    <ls_dd03p>-datatype  = 'CHAR'.
    <ls_dd03p>-leng      = '000012'.

    APPEND INITIAL LINE TO lt_dd03p ASSIGNING <ls_dd03p>.
    <ls_dd03p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd03p>-fieldname = 'VALUE'.
    <ls_dd03p>-position  = '0002'.
    <ls_dd03p>-keyflag   = 'X'.
    <ls_dd03p>-datatype  = 'CHAR'.
    <ls_dd03p>-leng      = '000012'.

    APPEND INITIAL LINE TO lt_dd03p ASSIGNING <ls_dd03p>.
    <ls_dd03p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd03p>-fieldname = 'DATA_STR'.
    <ls_dd03p>-position  = '0003'.
    <ls_dd03p>-datatype  = 'STRG'.

    CALL FUNCTION 'DDIF_TABL_PUT'
      EXPORTING
        name              = zcl_abapgit_persistence_db=>c_tabname
        dd02v_wa          = ls_dd02v
        dd09l_wa          = ls_dd09l
      TABLES
        dd03p_tab         = lt_dd03p
      EXCEPTIONS
        tabl_not_found    = 1
        name_inconsistent = 2
        tabl_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    lv_obj_name = zcl_abapgit_persistence_db=>c_tabname.
    CALL FUNCTION 'TR_TADIR_INTERFACE'
      EXPORTING
        wi_tadir_pgmid    = 'R3TR'
        wi_tadir_object   = 'TABL'
        wi_tadir_obj_name = lv_obj_name
        wi_set_genflag    = abap_true
        wi_test_modus     = abap_false
        wi_tadir_devclass = '$TMP'
      EXCEPTIONS
        OTHERS            = 1.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    CALL FUNCTION 'DDIF_TABL_ACTIVATE'
      EXPORTING
        name        = zcl_abapgit_persistence_db=>c_tabname
        auth_chk    = abap_false
      IMPORTING
        rc          = lv_rc
      EXCEPTIONS
        not_found   = 1
        put_failure = 2
        OTHERS      = 3.
    IF sy-subrc <> 0 OR lv_rc <> 0.
      zcx_abapgit_exception=>raise( 'migrate, error from DDIF_TABL_ACTIVATE' ).
    ENDIF.

  ENDMETHOD.

  METHOD table_exists.

    DATA: lv_tabname TYPE dd02l-tabname.

    SELECT SINGLE tabname FROM dd02l INTO lv_tabname
      WHERE tabname = zcl_abapgit_persistence_db=>c_tabname.
    rv_exists = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD update_global_settings.

    DATA: li_ixml          TYPE REF TO if_ixml,
          lv_settings_xml  TYPE string,
          li_ostream       TYPE REF TO if_ixml_ostream,
          li_renderer      TYPE REF TO if_ixml_renderer,
          li_streamfactory TYPE REF TO if_ixml_stream_factory.

    " finally update global settings
    " migrated elements are already removed from document

    li_ixml = cl_ixml=>create( ).
    li_streamfactory = li_ixml->create_stream_factory( ).
    li_ostream = li_streamfactory->create_ostream_cstring( lv_settings_xml ).
    li_renderer = li_ixml->create_renderer( ostream  = li_ostream
                                            document = ii_document ).
    li_renderer->render( ).

    zcl_abapgit_persistence_db=>get_instance( )->update(
      iv_type  = zcl_abapgit_persistence_db=>c_type_settings
      iv_value = ''
      iv_data  = lv_settings_xml ).

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_persist_migrate DEFINITION PUBLIC CREATE PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS: run RAISING zcx_abapgit_exception.

  PROTECTED SECTION.
  PRIVATE SECTION.
    CONSTANTS c_text TYPE string VALUE 'Generated by abapGit' ##NO_TEXT.

    CLASS-METHODS table_create
      RAISING
        zcx_abapgit_exception.
    CLASS-METHODS table_exists
      RETURNING
        VALUE(rv_exists) TYPE abap_bool.
    CLASS-METHODS lock_create
      RAISING
        zcx_abapgit_exception.
    CLASS-METHODS lock_exists
      RETURNING
        VALUE(rv_exists) TYPE abap_bool.

ENDCLASS.

CLASS zcl_abapgit_persist_migrate IMPLEMENTATION.

  METHOD lock_create.

    DATA: lv_obj_name TYPE tadir-obj_name,
          ls_dd25v    TYPE dd25v,
          lt_dd26e    TYPE STANDARD TABLE OF dd26e WITH DEFAULT KEY,
          lt_dd27p    TYPE STANDARD TABLE OF dd27p WITH DEFAULT KEY.

    FIELD-SYMBOLS: <ls_dd26e> LIKE LINE OF lt_dd26e,
                   <ls_dd27p> LIKE LINE OF lt_dd27p.

    ls_dd25v-viewname   = zcl_abapgit_persistence_db=>c_lock.
    ls_dd25v-aggtype    = 'E'.
    ls_dd25v-roottab    = zcl_abapgit_persistence_db=>c_tabname.
    ls_dd25v-ddlanguage = zif_abapgit_definitions=>c_english.
    ls_dd25v-ddtext     = c_text.

    APPEND INITIAL LINE TO lt_dd26e ASSIGNING <ls_dd26e>.
    <ls_dd26e>-viewname   = zcl_abapgit_persistence_db=>c_lock.
    <ls_dd26e>-tabname    = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd26e>-tabpos     = '0001'.
    <ls_dd26e>-fortabname = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd26e>-enqmode    = 'E'.

    APPEND INITIAL LINE TO lt_dd27p ASSIGNING <ls_dd27p>.
    <ls_dd27p>-viewname  = zcl_abapgit_persistence_db=>c_lock.
    <ls_dd27p>-objpos    = '0001'.
    <ls_dd27p>-viewfield = 'TYPE'.
    <ls_dd27p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd27p>-fieldname = 'TYPE'.
    <ls_dd27p>-keyflag   = abap_true.

    APPEND INITIAL LINE TO lt_dd27p ASSIGNING <ls_dd27p>.
    <ls_dd27p>-viewname  = zcl_abapgit_persistence_db=>c_lock.
    <ls_dd27p>-objpos    = '0002'.
    <ls_dd27p>-viewfield = 'VALUE'.
    <ls_dd27p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd27p>-fieldname = 'VALUE'.
    <ls_dd27p>-keyflag   = abap_true.

    CALL FUNCTION 'DDIF_ENQU_PUT'
      EXPORTING
        name              = zcl_abapgit_persistence_db=>c_lock
        dd25v_wa          = ls_dd25v
      TABLES
        dd26e_tab         = lt_dd26e
        dd27p_tab         = lt_dd27p
      EXCEPTIONS
        enqu_not_found    = 1
        name_inconsistent = 2
        enqu_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    lv_obj_name = zcl_abapgit_persistence_db=>c_lock.
    CALL FUNCTION 'TR_TADIR_INTERFACE'
      EXPORTING
        wi_tadir_pgmid    = 'R3TR'
        wi_tadir_object   = 'ENQU'
        wi_tadir_obj_name = lv_obj_name
        wi_set_genflag    = abap_true
        wi_test_modus     = abap_false
        wi_tadir_devclass = '$TMP'
      EXCEPTIONS
        OTHERS            = 1.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    CALL FUNCTION 'DDIF_ENQU_ACTIVATE'
      EXPORTING
        name        = zcl_abapgit_persistence_db=>c_lock
      EXCEPTIONS
        not_found   = 1
        put_failure = 2
        OTHERS      = 3.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'migrate, error from DDIF_ENQU_ACTIVATE' ).
    ENDIF.

  ENDMETHOD.

  METHOD lock_exists.

    DATA: lv_viewname TYPE dd25l-viewname.

    SELECT SINGLE viewname FROM dd25l INTO lv_viewname
      WHERE viewname = zcl_abapgit_persistence_db=>c_lock.
    rv_exists = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD run.

    IF table_exists( ) = abap_false.
      table_create( ).
    ENDIF.

    IF lock_exists( ) = abap_false.
      lock_create( ).
    ENDIF.

  ENDMETHOD.

  METHOD table_create.

    DATA: lv_rc       LIKE sy-subrc,
          lv_obj_name TYPE tadir-obj_name,
          ls_dd02v    TYPE dd02v,
          ls_dd09l    TYPE dd09l,
          lt_dd03p    TYPE STANDARD TABLE OF dd03p WITH DEFAULT KEY.

    FIELD-SYMBOLS: <ls_dd03p> LIKE LINE OF lt_dd03p.

    ls_dd02v-tabname    = zcl_abapgit_persistence_db=>c_tabname.
    ls_dd02v-ddlanguage = zif_abapgit_definitions=>c_english.
    ls_dd02v-tabclass   = 'TRANSP'.
    ls_dd02v-ddtext     = c_text.
    ls_dd02v-contflag   = 'L'.
    ls_dd02v-exclass    = '1'.

    ls_dd09l-tabname  = zcl_abapgit_persistence_db=>c_tabname.
    ls_dd09l-as4local = 'A'.
    ls_dd09l-tabkat   = '1'.
    ls_dd09l-tabart   = 'APPL1'.
    ls_dd09l-bufallow = 'N'.

    APPEND INITIAL LINE TO lt_dd03p ASSIGNING <ls_dd03p>.
    <ls_dd03p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd03p>-fieldname = 'TYPE'.
    <ls_dd03p>-position  = '0001'.
    <ls_dd03p>-keyflag   = 'X'.
    <ls_dd03p>-datatype  = 'CHAR'.
    <ls_dd03p>-leng      = '000012'.

    APPEND INITIAL LINE TO lt_dd03p ASSIGNING <ls_dd03p>.
    <ls_dd03p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd03p>-fieldname = 'VALUE'.
    <ls_dd03p>-position  = '0002'.
    <ls_dd03p>-keyflag   = 'X'.
    <ls_dd03p>-datatype  = 'CHAR'.
    <ls_dd03p>-leng      = '000012'.

    APPEND INITIAL LINE TO lt_dd03p ASSIGNING <ls_dd03p>.
    <ls_dd03p>-tabname   = zcl_abapgit_persistence_db=>c_tabname.
    <ls_dd03p>-fieldname = 'DATA_STR'.
    <ls_dd03p>-position  = '0003'.
    <ls_dd03p>-datatype  = 'STRG'.

    CALL FUNCTION 'DDIF_TABL_PUT'
      EXPORTING
        name              = zcl_abapgit_persistence_db=>c_tabname
        dd02v_wa          = ls_dd02v
        dd09l_wa          = ls_dd09l
      TABLES
        dd03p_tab         = lt_dd03p
      EXCEPTIONS
        tabl_not_found    = 1
        name_inconsistent = 2
        tabl_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    lv_obj_name = zcl_abapgit_persistence_db=>c_tabname.
    CALL FUNCTION 'TR_TADIR_INTERFACE'
      EXPORTING
        wi_tadir_pgmid    = 'R3TR'
        wi_tadir_object   = 'TABL'
        wi_tadir_obj_name = lv_obj_name
        wi_set_genflag    = abap_true
        wi_test_modus     = abap_false
        wi_tadir_devclass = '$TMP'
      EXCEPTIONS
        OTHERS            = 1.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise_t100( ).
    ENDIF.

    CALL FUNCTION 'DDIF_TABL_ACTIVATE'
      EXPORTING
        name        = zcl_abapgit_persistence_db=>c_tabname
        auth_chk    = abap_false
      IMPORTING
        rc          = lv_rc
      EXCEPTIONS
        not_found   = 1
        put_failure = 2
        OTHERS      = 3.
    IF sy-subrc <> 0 OR lv_rc <> 0.
      zcx_abapgit_exception=>raise( 'migrate, error from DDIF_TABL_ACTIVATE' ).
    ENDIF.

  ENDMETHOD.

  METHOD table_exists.

    DATA: lv_tabname TYPE dd02l-tabname.

    SELECT SINGLE tabname FROM dd02l INTO lv_tabname
      WHERE tabname = zcl_abapgit_persistence_db=>c_tabname.
    rv_exists = boolc( sy-subrc = 0 ).

  ENDMETHOD.

ENDCLASS.

Remove user setting migration (#4551)

Remove user setting migration (#4551)


CLASS zcl_ags_service_git DEFINITION
  PUBLIC
  CREATE PUBLIC.

  PUBLIC SECTION.

    INTERFACES zif_ags_service.

    METHODS constructor
      IMPORTING
        !ii_server TYPE REF TO if_http_server.
  PROTECTED SECTION.
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_push,
        old    TYPE zags_sha1,
        new    TYPE zags_sha1,
        name   TYPE zags_branch_name,
        length TYPE i,
      END OF ty_push.

    DATA mi_server TYPE REF TO if_http_server.

    METHODS branch_list
      RAISING
        zcx_ags_error.
    METHODS decode_push
      IMPORTING
        !iv_data       TYPE xstring
      RETURNING
        VALUE(rs_push) TYPE ty_push
      RAISING
        zcx_ags_error.
    METHODS decode_want
      IMPORTING
        !iv_string     TYPE string
      RETURNING
        VALUE(rv_sha1) TYPE zags_sha1.
    METHODS get_null
      RETURNING
        VALUE(rv_char) TYPE char1.
    METHODS pack
      RAISING
        zcx_ags_error.
    METHODS repo_name
      RETURNING
        VALUE(rv_name) TYPE zags_repos-name.
    METHODS unpack
      RAISING
        zcx_ags_error.
    METHODS unpack_ok.
ENDCLASS.

CLASS ZCL_AGS_SERVICE_GIT IMPLEMENTATION.

  METHOD branch_list.

    DEFINE _capability.
      APPEND &1 TO lt_capabilities ##no_text.
    END-OF-DEFINITION.

    DATA: lv_reply        TYPE string,
          lt_reply        TYPE TABLE OF string,
          lv_length       TYPE xstring,
          lv_tmp          TYPE string,
          lt_capabilities TYPE TABLE OF string,
          lv_content      TYPE string,
          lv_utf          TYPE string,
          lv_name         TYPE zags_repos-name,
          lv_head         TYPE zags_sha1,
          lo_repo         TYPE REF TO zcl_ags_repo,
          lt_branches     TYPE zcl_ags_repo=>ty_branches_tt.

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

    _capability 'multi_ack'.
    _capability 'thin-pack'.
    _capability 'side-band'.
    _capability 'side-band-64k'.
    _capability 'ofs-delta'.
    _capability 'shallow'.
    _capability 'no-progress'.
    _capability 'include-tag'.
    _capability 'multi_ack_detailed'.
    _capability 'no-done'.
    _capability 'symref=HEAD:refs/heads/master'.
    _capability 'agent=git/abapGitServer'.

    CONCATENATE LINES OF lt_capabilities INTO lv_reply SEPARATED BY space.

    lv_name = repo_name( ).
    CREATE OBJECT lo_repo
      EXPORTING
        iv_name = lv_name.
    lv_head = lo_repo->get_branch( lo_repo->get_data( )-head )->get_data( )-sha1.

    APPEND |001e# service=git-upload-pack| TO lt_reply ##no_text.

    lv_content = |{ lv_head } HEAD{ get_null( ) }{ lv_reply }|.
    lv_length = lcl_length=>encode( strlen( lv_content ) + 5 ).
    lv_utf = to_lower( zcl_ags_util=>xstring_to_string_utf8( lv_length ) ).

    lv_tmp = '0000' && lv_utf && lv_content.
    APPEND lv_tmp TO lt_reply.

    lt_branches = lo_repo->list_branches( ).
    LOOP AT lt_branches ASSIGNING <lo_branch>.
      lv_content = <lo_branch>->get_data( )-sha1
        && ' refs/heads/'
        && <lo_branch>->get_data( )-name ##no_text.

      lv_length = lcl_length=>encode( strlen( lv_content ) + 5 ).
      lv_utf = to_lower( zcl_ags_util=>xstring_to_string_utf8( lv_length ) ).

      lv_tmp = lv_utf && lv_content.
      APPEND lv_tmp TO lt_reply.
    ENDLOOP.

    APPEND '0000' TO lt_reply.

    CONCATENATE LINES OF lt_reply INTO lv_reply
      SEPARATED BY cl_abap_char_utilities=>newline.

    mi_server->response->set_header_field( name = 'Server'
                                           value = 'abapGitServer' ).
    mi_server->response->set_header_field( name = 'Cache-Control'
                                           value = 'no-cache' ).
    mi_server->response->set_content_type( 'application/x-git-upload-pack-advertisement' ).

* must be sent as raw, using data will change the content-type of the response
    DATA(lv_raw) = zcl_ags_util=>string_to_xstring_utf8( lv_reply ).
    mi_server->response->set_data( lv_raw ).

  ENDMETHOD.

  METHOD constructor.

    mi_server = ii_server.

  ENDMETHOD.

  METHOD decode_push.

    DATA: lv_first TYPE xstring,
          lv_utf TYPE string,
          lv_data TYPE string,
          lt_data TYPE TABLE OF string.

    lv_first = iv_data(4).
    lv_utf = zcl_ags_util=>xstring_to_string_utf8( lv_first ).
    rs_push-length = lcl_length=>decode( lv_utf ).

    lv_first = iv_data(rs_push-length).
    lv_data = zcl_ags_util=>xstring_to_string_utf8( lv_first ).
    lv_data = lv_data+4. " skip length, already decoded

    SPLIT lv_data AT get_null( ) INTO TABLE lt_data.
    ASSERT lines( lt_data ) > 0.

    READ TABLE lt_data INDEX 1 INTO lv_data.

    rs_push-old  = lv_data.
    rs_push-new  = lv_data+41.
    rs_push-name = lv_data+93. " also skip 'refs/heads/'

  ENDMETHOD.

  METHOD decode_want.

* todo, proper decoding
    rv_sha1 = iv_string+9.

  ENDMETHOD.

  METHOD get_null.

    DATA: lv_x(4) TYPE x VALUE '00000000',
          lv_z(2) TYPE c.

    FIELD-SYMBOLS <lv_y> TYPE c.

    ASSIGN lv_x TO <lv_y> CASTING.
    lv_z = <lv_y>.
    rv_char = lv_z(1).

  ENDMETHOD.

  METHOD pack.

    CONSTANTS: lc_band1 TYPE x VALUE '01'.

    DATA: lv_response TYPE xstring,
          lv_branch   TYPE zags_sha1,
          lo_commit   TYPE REF TO zcl_ags_obj_commit,
          lv_encoded  TYPE zags_hex4,
          lv_pack     TYPE xstring,
          lv_length   TYPE i.

    lv_branch = decode_want( mi_server->request->get_cdata( ) ).

    lv_pack = zcl_ags_util=>string_to_xstring_utf8( |NAK\n| ).
    lv_encoded = lcl_length=>encode( xstrlen( lv_pack ) + 4 ).
    CONCATENATE lv_response lv_encoded lv_pack INTO lv_response IN BYTE MODE.

    CREATE OBJECT lo_commit
      EXPORTING
        iv_sha1 = lv_branch.

    lv_pack = zcl_ags_pack=>encode( zcl_ags_pack=>explode( lo_commit ) ).

    WHILE xstrlen( lv_pack ) > 0.
      IF xstrlen( lv_pack ) >= 8196.
        lv_length = 8196.
      ELSE.
        lv_length = xstrlen( lv_pack ).
      ENDIF.

* make sure to include the length encoding itself and band identifier in the length
      lv_encoded = lcl_length=>encode( lv_length + 5 ).

      CONCATENATE lv_response lv_encoded lc_band1 lv_pack(lv_length)
        INTO lv_response IN BYTE MODE.

      lv_pack = lv_pack+lv_length.
    ENDWHILE.

    mi_server->response->set_data( lv_response ).

  ENDMETHOD.

  METHOD repo_name.

    DATA: lv_path TYPE string.

    lv_path = mi_server->request->get_header_field( '~path' ).
    FIND REGEX 'sap/zgit/git/(.*)\.git*'
      IN lv_path
      SUBMATCHES rv_name ##no_text.

  ENDMETHOD.

  METHOD unpack.

    CONSTANTS: lc_utf_0000 TYPE x LENGTH 4 VALUE '30303030'.

    DATA: lv_xstring TYPE xstring,
          lt_objects TYPE zcl_ags_pack=>ty_objects_tt,
          lo_repo    TYPE REF TO zcl_ags_repo,
          lo_branch  TYPE REF TO zcl_ags_branch,
          ls_push    TYPE ty_push.

    ls_push = decode_push( mi_server->request->get_data( ) ).

    lv_xstring = mi_server->request->get_data( ).
    lv_xstring = lv_xstring+ls_push-length.
    ASSERT lv_xstring(4) = lc_utf_0000.
    lv_xstring = lv_xstring+4.

    lt_objects = zcl_ags_pack=>decode( lv_xstring ).

    CREATE OBJECT lo_repo
      EXPORTING
        iv_name = repo_name( ).

    IF ls_push-old CO '0'.
* create branch
      zcl_ags_branch=>create(
        io_repo   = lo_repo
        iv_name   = ls_push-name
        iv_commit = ls_push-new ).
    ELSEIF ls_push-new CO '0'.
* delete branch
* todo
      ASSERT 0 = 1.
    ELSE.
* update branch

      READ TABLE lt_objects WITH KEY sha1 = ls_push-new TRANSPORTING NO FIELDS.
* new commit should exist in objects
      ASSERT sy-subrc = 0.

      lo_branch = lo_repo->get_branch( ls_push-name ).

      ASSERT lo_branch->get_data( )-sha1 = ls_push-old.

      zcl_ags_pack=>save( lt_objects ).

      lo_branch->update_sha1( ls_push-new ).
    ENDIF.

    unpack_ok( ).

  ENDMETHOD.

  METHOD unpack_ok.

* todo, this is all wrong(but will work in most cases):
    mi_server->response->set_cdata( '000eunpack ok#0019ok refs/heads/master#00000000' ).

  ENDMETHOD.

  METHOD zif_ags_service~run.

    DATA: lv_path TYPE string,
          lv_xdata TYPE string.

    lv_path = mi_server->request->get_header_field( '~path_info' ).
    lv_xdata = mi_server->request->get_data( ).

    IF lv_xdata IS INITIAL.
      branch_list( ).
    ELSEIF lv_path CP '*git-upload-pack*'.
      pack( ).
    ELSEIF lv_path CP '*git-receive-pack*'.
      unpack( ).
    ELSE.
      RAISE EXCEPTION TYPE zcx_ags_error
        EXPORTING
          textid = zcx_ags_error=>m008.
    ENDIF.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_ags_service_git DEFINITION
  PUBLIC
  CREATE PUBLIC.

  PUBLIC SECTION.

    INTERFACES zif_ags_service.

    METHODS constructor
      IMPORTING
        !ii_server TYPE REF TO if_http_server.
  PROTECTED SECTION.
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_push,
        old    TYPE zags_sha1,
        new    TYPE zags_sha1,
        name   TYPE zags_branch_name,
        length TYPE i,
      END OF ty_push.

    DATA mi_server TYPE REF TO if_http_server.

    METHODS branch_list
      RAISING
        zcx_ags_error.
    METHODS decode_push
      IMPORTING
        !iv_data       TYPE xstring
      RETURNING
        VALUE(rs_push) TYPE ty_push
      RAISING
        zcx_ags_error.
    METHODS decode_want
      IMPORTING
        !iv_string     TYPE string
      RETURNING
        VALUE(rv_sha1) TYPE zags_sha1.
    METHODS get_null
      RETURNING
        VALUE(rv_char) TYPE char1.
    METHODS pack
      RAISING
        zcx_ags_error.
    METHODS repo_name
      RETURNING
        VALUE(rv_name) TYPE zags_repos-name.
    METHODS unpack
      RAISING
        zcx_ags_error.
    METHODS unpack_ok.
ENDCLASS.

CLASS ZCL_AGS_SERVICE_GIT IMPLEMENTATION.

  METHOD branch_list.

    DEFINE _capability.
      APPEND &1 TO lt_capabilities ##no_text.
    END-OF-DEFINITION.

    DATA: lv_reply        TYPE string,
          lt_reply        TYPE TABLE OF string,
          lv_length       TYPE xstring,
          lv_tmp          TYPE string,
          lt_capabilities TYPE TABLE OF string,
          lv_content      TYPE string,
          lv_utf          TYPE string,
          lv_name         TYPE zags_repos-name,
          lv_head         TYPE zags_sha1,
          lo_repo         TYPE REF TO zcl_ags_repo,
          lt_branches     TYPE zcl_ags_repo=>ty_branches_tt.

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

    _capability 'multi_ack'.
    _capability 'thin-pack'.
    _capability 'side-band'.
    _capability 'side-band-64k'.
    _capability 'ofs-delta'.
    _capability 'shallow'.
    _capability 'no-progress'.
    _capability 'include-tag'.
    _capability 'multi_ack_detailed'.
    _capability 'no-done'.
    _capability 'symref=HEAD:refs/heads/master'.
    _capability 'agent=git/abapGitServer'.

    CONCATENATE LINES OF lt_capabilities INTO lv_reply SEPARATED BY space.

    lv_name = repo_name( ).
    CREATE OBJECT lo_repo
      EXPORTING
        iv_name = lv_name.
    lv_head = lo_repo->get_branch( lo_repo->get_data( )-head )->get_data( )-sha1.

    APPEND |001e# service=git-upload-pack| TO lt_reply ##no_text.

    lv_content = |{ lv_head } HEAD{ get_null( ) }{ lv_reply }|.
    lv_length = lcl_length=>encode( strlen( lv_content ) + 5 ).
    lv_utf = to_lower( zcl_ags_util=>xstring_to_string_utf8( lv_length ) ).

    lv_tmp = '0000' && lv_utf && lv_content.
    APPEND lv_tmp TO lt_reply.

    lt_branches = lo_repo->list_branches( ).
    LOOP AT lt_branches ASSIGNING <lo_branch>.
      lv_content = <lo_branch>->get_data( )-sha1
        && ' refs/heads/'
        && <lo_branch>->get_data( )-name ##no_text.

      lv_length = lcl_length=>encode( strlen( lv_content ) + 5 ).
      lv_utf = to_lower( zcl_ags_util=>xstring_to_string_utf8( lv_length ) ).

      lv_tmp = lv_utf && lv_content.
      APPEND lv_tmp TO lt_reply.
    ENDLOOP.

    APPEND '0000' TO lt_reply.

    CONCATENATE LINES OF lt_reply INTO lv_reply
      SEPARATED BY cl_abap_char_utilities=>newline.

    mi_server->response->set_header_field( name = 'Server'
                                           value = 'abapGitServer' ).
    mi_server->response->set_header_field( name = 'Cache-Control'
                                           value = 'no-cache' ).
    mi_server->response->set_content_type( 'application/x-git-upload-pack-advertisement' ).

* must be sent as raw, using data will change the content-type of the response
    DATA(lv_raw) = zcl_ags_util=>string_to_xstring_utf8( lv_reply ).
    mi_server->response->set_data( lv_raw ).

  ENDMETHOD.

  METHOD constructor.

    mi_server = ii_server.

  ENDMETHOD.

  METHOD decode_push.

    DATA: lv_first TYPE xstring,
          lv_utf TYPE string,
          lv_data TYPE string,
          lt_data TYPE TABLE OF string.

    lv_first = iv_data(4).
    lv_utf = zcl_ags_util=>xstring_to_string_utf8( lv_first ).
    rs_push-length = lcl_length=>decode( lv_utf ).

    lv_first = iv_data(rs_push-length).
    lv_data = zcl_ags_util=>xstring_to_string_utf8( lv_first ).
    lv_data = lv_data+4. " skip length, already decoded

    SPLIT lv_data AT get_null( ) INTO TABLE lt_data.
    ASSERT lines( lt_data ) > 0.

    READ TABLE lt_data INDEX 1 INTO lv_data.

    rs_push-old  = lv_data.
    rs_push-new  = lv_data+41.
    rs_push-name = lv_data+93. " also skip 'refs/heads/'

  ENDMETHOD.

  METHOD decode_want.

* todo, proper decoding
    rv_sha1 = iv_string+9.

  ENDMETHOD.

  METHOD get_null.

    DATA: lv_x(4) TYPE x VALUE '00000000',
          lv_z(2) TYPE c.

    FIELD-SYMBOLS <lv_y> TYPE c.

    ASSIGN lv_x TO <lv_y> CASTING.
    lv_z = <lv_y>.
    rv_char = lv_z(1).

  ENDMETHOD.

  METHOD pack.

    CONSTANTS: lc_band1 TYPE x VALUE '01'.

    DATA: lv_response TYPE xstring,
          lv_branch   TYPE zags_sha1,
          lo_commit   TYPE REF TO zcl_ags_obj_commit,
          lv_encoded  TYPE zags_hex4,
          lv_pack     TYPE xstring,
          lv_length   TYPE i.

    lv_branch = decode_want( mi_server->request->get_cdata( ) ).

    lv_pack = zcl_ags_util=>string_to_xstring_utf8( |NAK\n| ).
    lv_encoded = lcl_length=>encode( xstrlen( lv_pack ) + 4 ).
    CONCATENATE lv_response lv_encoded lv_pack INTO lv_response IN BYTE MODE.

    CREATE OBJECT lo_commit
      EXPORTING
        iv_sha1 = lv_branch.

    lv_pack = zcl_ags_pack=>encode( zcl_ags_pack=>explode( lo_commit ) ).

    WHILE xstrlen( lv_pack ) > 0.
      IF xstrlen( lv_pack ) >= 8196.
        lv_length = 8196.
      ELSE.
        lv_length = xstrlen( lv_pack ).
      ENDIF.

* make sure to include the length encoding itself and band identifier in the length
      lv_encoded = lcl_length=>encode( lv_length + 5 ).

      CONCATENATE lv_response lv_encoded lc_band1 lv_pack(lv_length)
        INTO lv_response IN BYTE MODE.

      lv_pack = lv_pack+lv_length.
    ENDWHILE.

    lv_pack = zcl_ags_util=>string_to_xstring_utf8( '0000' ).
    CONCATENATE lv_response lv_pack INTO lv_response IN BYTE MODE.

    mi_server->response->set_data( lv_response ).

  ENDMETHOD.

  METHOD repo_name.

    DATA: lv_path TYPE string.

    lv_path = mi_server->request->get_header_field( '~path' ).
    FIND REGEX 'sap/zgit/git/(.*)\.git*'
      IN lv_path
      SUBMATCHES rv_name ##no_text.

  ENDMETHOD.

  METHOD unpack.

    CONSTANTS: lc_utf_0000 TYPE x LENGTH 4 VALUE '30303030'.

    DATA: lv_xstring TYPE xstring,
          lt_objects TYPE zcl_ags_pack=>ty_objects_tt,
          lo_repo    TYPE REF TO zcl_ags_repo,
          lo_branch  TYPE REF TO zcl_ags_branch,
          ls_push    TYPE ty_push.

    ls_push = decode_push( mi_server->request->get_data( ) ).

    lv_xstring = mi_server->request->get_data( ).
    lv_xstring = lv_xstring+ls_push-length.
    ASSERT lv_xstring(4) = lc_utf_0000.
    lv_xstring = lv_xstring+4.

    lt_objects = zcl_ags_pack=>decode( lv_xstring ).

    CREATE OBJECT lo_repo
      EXPORTING
        iv_name = repo_name( ).

    IF ls_push-old CO '0'.
* create branch
      zcl_ags_branch=>create(
        io_repo   = lo_repo
        iv_name   = ls_push-name
        iv_commit = ls_push-new ).
    ELSEIF ls_push-new CO '0'.
* delete branch
* todo
      ASSERT 0 = 1.
    ELSE.
* update branch

      READ TABLE lt_objects WITH KEY sha1 = ls_push-new TRANSPORTING NO FIELDS.
* new commit should exist in objects
      ASSERT sy-subrc = 0.

      lo_branch = lo_repo->get_branch( ls_push-name ).

      ASSERT lo_branch->get_data( )-sha1 = ls_push-old.

      zcl_ags_pack=>save( lt_objects ).

      lo_branch->update_sha1( ls_push-new ).
    ENDIF.

    unpack_ok( ).

  ENDMETHOD.

  METHOD unpack_ok.

* todo, this is all wrong(but will work in most cases):
    mi_server->response->set_cdata( '000eunpack ok#0019ok refs/heads/master#00000000' ).

  ENDMETHOD.

  METHOD zif_ags_service~run.

    DATA: lv_path TYPE string,
          lv_xdata TYPE string.

    lv_path = mi_server->request->get_header_field( '~path_info' ).
    lv_xdata = mi_server->request->get_data( ).

    IF lv_xdata IS INITIAL.
      branch_list( ).
    ELSEIF lv_path CP '*git-upload-pack*'.
      pack( ).
    ELSEIF lv_path CP '*git-receive-pack*'.
      unpack( ).
    ELSE.
      RAISE EXCEPTION TYPE zcx_ags_error
        EXPORTING
          textid = zcx_ags_error=>m008.
    ENDIF.

  ENDMETHOD.
ENDCLASS.

fix error in demultiplexer

fix error in demultiplexer