*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_TRANSPORT
*&---------------------------------------------------------------------*
CLASS lcl_transport DEFINITION FINAL.

  PUBLIC SECTION.
    CLASS-METHODS:
      zip RAISING lcx_exception,
      to_tadir IMPORTING it_transport_headers TYPE trwbo_request_headers
               RETURNING VALUE(rt_tadir)      TYPE scts_tadir
               RAISING   lcx_exception.

  PRIVATE SECTION.
    CLASS-METHODS:
      read_requests
        IMPORTING it_trkorr          TYPE trwbo_request_headers
        RETURNING VALUE(rt_requests) TYPE trwbo_requests
        RAISING   lcx_exception,
      find_top_package
        IMPORTING it_tadir          TYPE scts_tadir
        RETURNING VALUE(rv_package) TYPE devclass,
      resolve
        IMPORTING it_requests     TYPE trwbo_requests
        RETURNING VALUE(rt_tadir) TYPE scts_tadir
        RAISING   lcx_exception.

ENDCLASS.

CLASS lcl_transport IMPLEMENTATION.

  METHOD zip.
    DATA: lt_requests TYPE trwbo_requests,
          lt_tadir    TYPE scts_tadir,
          lv_package  TYPE devclass,
          ls_data     TYPE lcl_persistence_repo=>ty_repo,
          lo_repo     TYPE REF TO lcl_repo_offline,
          lt_trkorr   TYPE trwbo_request_headers.

    lt_trkorr = lcl_popups=>popup_to_select_transports( ).
    IF lines( lt_trkorr ) = 0.
      RETURN.
    ENDIF.

    lt_requests = read_requests( lt_trkorr ).
    lt_tadir = resolve( lt_requests ).
    IF lines( lt_tadir ) = 0.
      lcx_exception=>raise( 'empty transport' ).
    ENDIF.

    lv_package = find_top_package( lt_tadir ).
    IF lv_package IS INITIAL.
      lcx_exception=>raise( 'error finding super package' ).
    ENDIF.

    ls_data-key         = 'TZIP'.
    ls_data-package     = lv_package.
    ls_data-dot_abapgit = lcl_dot_abapgit=>build_default( )->get_data( ).

    CREATE OBJECT lo_repo
      EXPORTING
        is_data = ls_data.

    lcl_zip=>export( io_repo   = lo_repo
                     it_filter = lt_tadir ).
  ENDMETHOD.

  METHOD to_tadir.
    DATA: lt_requests TYPE trwbo_requests.

    IF lines( it_transport_headers ) = 0.
      RETURN.
    ENDIF.

    lt_requests = read_requests( it_transport_headers ).
    rt_tadir = resolve( lt_requests ).
  ENDMETHOD.

  METHOD find_top_package.
* assumption: all objects in transport share a common super package

    DATA: lt_obj   TYPE lif_sap_package=>ty_devclass_tt,
          lt_super TYPE lif_sap_package=>ty_devclass_tt,
          lv_super LIKE LINE OF lt_super,
          lv_index TYPE i.

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

    READ TABLE it_tadir INDEX 1 ASSIGNING <ls_tadir>.
    ASSERT sy-subrc = 0.
    lt_super = lcl_sap_package=>get( <ls_tadir>-devclass )->list_superpackages( ).

    LOOP AT it_tadir ASSIGNING <ls_tadir>.
      lt_obj = lcl_sap_package=>get( <ls_tadir>-devclass )->list_superpackages( ).

* filter out possibilities from lt_super
      LOOP AT lt_super INTO lv_super.
        lv_index = sy-tabix.
        READ TABLE lt_obj FROM lv_super TRANSPORTING NO FIELDS.
        IF sy-subrc <> 0.
          DELETE lt_super INDEX lv_index.
        ENDIF.
      ENDLOOP.
    ENDLOOP.

    SORT lt_super.
    READ TABLE lt_super INDEX 1 INTO rv_package.
  ENDMETHOD.

  METHOD read_requests.
    DATA lt_requests LIKE rt_requests.
    FIELD-SYMBOLS <fs_trkorr> LIKE LINE OF it_trkorr.

    LOOP AT it_trkorr ASSIGNING <fs_trkorr>.
      CALL FUNCTION 'TR_READ_REQUEST_WITH_TASKS'
        EXPORTING
          iv_trkorr     = <fs_trkorr>-trkorr
        IMPORTING
          et_requests   = lt_requests
        EXCEPTIONS
          invalid_input = 1
          OTHERS        = 2.
      IF sy-subrc <> 0.
        lcx_exception=>raise( 'error from TR_READ_REQUEST_WITH_TASKS' ).
      ENDIF.

      APPEND LINES OF lt_requests TO rt_requests.
    ENDLOOP.
  ENDMETHOD.

  METHOD resolve.
    DATA: lv_object     TYPE tadir-object,
          lv_obj_name   TYPE tadir-obj_name,
          lv_trobj_name TYPE trobj_name,
          ls_tadir      TYPE tadir.

    FIELD-SYMBOLS: <ls_request> LIKE LINE OF it_requests,
                   <ls_object>  LIKE LINE OF <ls_request>-objects.

    LOOP AT it_requests ASSIGNING <ls_request>.
      LOOP AT <ls_request>-objects ASSIGNING <ls_object>.
        IF <ls_object>-pgmid = 'LIMU'.
          CALL FUNCTION 'GET_R3TR_OBJECT_FROM_LIMU_OBJ'
            EXPORTING
              p_limu_objtype = <ls_object>-object
              p_limu_objname = <ls_object>-obj_name
            IMPORTING
              p_r3tr_objtype = lv_object
              p_r3tr_objname = lv_trobj_name
            EXCEPTIONS
              no_mapping     = 1
              OTHERS         = 2.
          IF sy-subrc <> 0.
            lcx_exception=>raise( 'error from GET_R3TR_OBJECT_FROM_LIMU_OBJ' ).
          ENDIF.
          lv_obj_name = lv_trobj_name.
        ELSE.
          lv_object   = <ls_object>-object.
          lv_obj_name = <ls_object>-obj_name.
        ENDIF.

        ls_tadir = lcl_tadir=>read_single(
          iv_object   = lv_object
          iv_obj_name = lv_obj_name ).

        APPEND ls_tadir TO rt_tadir.
      ENDLOOP.
    ENDLOOP.

    SORT rt_tadir BY object ASCENDING obj_name ASCENDING.
    DELETE ADJACENT DUPLICATES FROM rt_tadir COMPARING object obj_name.
    DELETE rt_tadir WHERE table_line IS INITIAL.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_transport_objects DEFINITION.
  "Under test at ltcl_transport_objects
  PUBLIC SECTION.
    METHODS constructor
      IMPORTING
        it_transport_objects TYPE scts_tadir.
    METHODS to_stage
      IMPORTING
        io_stage           TYPE REF TO lcl_stage
        is_stage_objects   TYPE ty_stage_files
        it_object_statuses TYPE ty_results_tt
      RAISING
        lcx_exception.
  PRIVATE SECTION.
    DATA mt_transport_objects TYPE scts_tadir.
ENDCLASS.

CLASS lcl_transport_objects IMPLEMENTATION.
  METHOD constructor.
    mt_transport_objects = it_transport_objects.
  ENDMETHOD.

  METHOD to_stage.
    DATA: ls_transport_object TYPE tadir,
          ls_local_file       TYPE ty_file_item,
          ls_object_status    TYPE ty_result.

    LOOP AT mt_transport_objects INTO ls_transport_object.
      LOOP AT it_object_statuses INTO ls_object_status
        WHERE obj_name = ls_transport_object-obj_name
          AND obj_type = ls_transport_object-object.

        CASE ls_object_status-lstate.
          WHEN gc_state-added OR gc_state-modified.
            IF ls_transport_object-delflag = abap_true.
              lcx_exception=>raise( |Object { ls_transport_object-obj_name
              } should be added/modified, but has deletion flag in transport| ).
            ENDIF.

            READ TABLE is_stage_objects-local
                  INTO ls_local_file
              WITH KEY item-obj_name = ls_transport_object-obj_name
                       item-obj_type = ls_transport_object-object
                       file-filename = ls_object_status-filename.
            IF sy-subrc <> 0.
              lcx_exception=>raise( |Object { ls_transport_object-obj_name
              } not found in the local repository files| ).
            ENDIF.

            io_stage->add(
              iv_path     = ls_local_file-file-path
              iv_filename = ls_local_file-file-filename
              iv_data     = ls_local_file-file-data ).
          WHEN gc_state-deleted.
            IF ls_transport_object-delflag = abap_false.
              lcx_exception=>raise( |Object { ls_transport_object-obj_name
              } should be removed, but has NO deletion flag in transport| ).
            ENDIF.
            io_stage->rm(
              iv_path     = ls_object_status-path
              iv_filename = ls_object_status-filename ).
          WHEN OTHERS.
            ASSERT 0 = 1. "Unexpected state
        ENDCASE.
      ENDLOOP.
      IF sy-subrc <> 0.
        lcx_exception=>raise( |Object { ls_transport_object-obj_name
        } not found in the local repository files| ).
      ENDIF.
    ENDLOOP.
  ENDMETHOD.

ENDCLASS.

CLASS lcl_transport_to_branch DEFINITION.
  PUBLIC SECTION.
    METHODS:
      create
        IMPORTING io_repository          TYPE REF TO lcl_repo_online
                  is_transport_to_branch TYPE ty_transport_to_branch
                  it_transport_objects   TYPE scts_tadir
        RAISING   lcx_exception.
  PRIVATE SECTION.

    METHODS create_new_branch
      IMPORTING
        io_repository  TYPE REF TO lcl_repo_online
        iv_branch_name TYPE string
      RAISING
        lcx_exception.
    METHODS generate_commit_message
      IMPORTING
        is_transport_to_branch TYPE ty_transport_to_branch
      RETURNING
        VALUE(rs_comment)      TYPE ty_comment.
    METHODS stage_transport_objects
      IMPORTING
        it_transport_objects TYPE scts_tadir
        io_stage             TYPE REF TO lcl_stage
        is_stage_objects     TYPE ty_stage_files
        it_object_statuses   TYPE ty_results_tt
      RAISING
        lcx_exception.
ENDCLASS.

CLASS lcl_transport_to_branch IMPLEMENTATION.

  METHOD create.
    DATA:
      lv_branch_name      TYPE string,
      ls_comment          TYPE ty_comment,
      lo_stage            TYPE REF TO lcl_stage,
      ls_stage_objects    TYPE ty_stage_files,
      lt_object_statuses  TYPE ty_results_tt.

    lv_branch_name = lcl_git_branch_list=>complete_heads_branch_name(
        lcl_git_branch_list=>normalize_branch_name( is_transport_to_branch-branch_name ) ).

    create_new_branch(
      io_repository  = io_repository
      iv_branch_name = lv_branch_name ).

    CREATE OBJECT lo_stage
      EXPORTING
        iv_branch_name = lv_branch_name
        iv_branch_sha1 = io_repository->get_sha1_remote( ).

    ls_stage_objects = lcl_stage_logic=>get( io_repository ).

    lt_object_statuses = io_repository->status( ).

    stage_transport_objects(
       it_transport_objects = it_transport_objects
       io_stage             = lo_stage
       is_stage_objects     = ls_stage_objects
       it_object_statuses   = lt_object_statuses ).

    ls_comment = generate_commit_message( is_transport_to_branch ).

    io_repository->push( is_comment = ls_comment
                         io_stage   = lo_stage ).
  ENDMETHOD.

  METHOD create_new_branch.
    ASSERT iv_branch_name CP 'refs/heads/+*'.
    TRY.
        lcl_git_porcelain=>create_branch(
          io_repo = io_repository
          iv_name = iv_branch_name
          iv_from = io_repository->get_sha1_local( ) ).

        io_repository->set_branch_name( iv_branch_name ).
      CATCH lcx_exception.
        lcx_exception=>raise( 'Error when creating new branch').
    ENDTRY.
  ENDMETHOD.

  METHOD generate_commit_message.
    rs_comment-committer-name  = sy-uname.
    rs_comment-committer-email = |{ rs_comment-committer-name }@localhost|.
    rs_comment-comment         = is_transport_to_branch-commit_text.
  ENDMETHOD.

  METHOD stage_transport_objects.
    DATA lo_transport_objects TYPE REF TO lcl_transport_objects.
    CREATE OBJECT lo_transport_objects
      EXPORTING
        it_transport_objects = it_transport_objects.

    lo_transport_objects->to_stage(
      io_stage           = io_stage
      is_stage_objects   = is_stage_objects
      it_object_statuses = it_object_statuses ).
  ENDMETHOD.
ENDCLASS.

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_TRANSPORT
*&---------------------------------------------------------------------*
CLASS lcl_transport DEFINITION FINAL.

  PUBLIC SECTION.
    CLASS-METHODS:
      zip RAISING lcx_exception,
      to_tadir IMPORTING it_transport_headers TYPE trwbo_request_headers
               RETURNING VALUE(rt_tadir)      TYPE scts_tadir
               RAISING   lcx_exception.

  PRIVATE SECTION.
    CLASS-METHODS:
      read_requests
        IMPORTING it_trkorr          TYPE trwbo_request_headers
        RETURNING VALUE(rt_requests) TYPE trwbo_requests
        RAISING   lcx_exception,
      find_top_package
        IMPORTING it_tadir          TYPE scts_tadir
        RETURNING VALUE(rv_package) TYPE devclass,
      resolve
        IMPORTING it_requests     TYPE trwbo_requests
        RETURNING VALUE(rt_tadir) TYPE scts_tadir
        RAISING   lcx_exception.

ENDCLASS.

CLASS lcl_transport IMPLEMENTATION.

  METHOD zip.
    DATA: lt_requests TYPE trwbo_requests,
          lt_tadir    TYPE scts_tadir,
          lv_package  TYPE devclass,
          ls_data     TYPE lcl_persistence_repo=>ty_repo,
          lo_repo     TYPE REF TO lcl_repo_offline,
          lt_trkorr   TYPE trwbo_request_headers.

    lt_trkorr = lcl_popups=>popup_to_select_transports( ).
    IF lines( lt_trkorr ) = 0.
      RETURN.
    ENDIF.

    lt_requests = read_requests( lt_trkorr ).
    lt_tadir = resolve( lt_requests ).
    IF lines( lt_tadir ) = 0.
      lcx_exception=>raise( 'empty transport' ).
    ENDIF.

    lv_package = find_top_package( lt_tadir ).
    IF lv_package IS INITIAL.
      lcx_exception=>raise( 'error finding super package' ).
    ENDIF.

    ls_data-key         = 'TZIP'.
    ls_data-package     = lv_package.
    ls_data-dot_abapgit = lcl_dot_abapgit=>build_default( )->get_data( ).

    CREATE OBJECT lo_repo
      EXPORTING
        is_data = ls_data.

    lcl_zip=>export( io_repo   = lo_repo
                     it_filter = lt_tadir ).
  ENDMETHOD.

  METHOD to_tadir.
    DATA: lt_requests TYPE trwbo_requests.

    IF lines( it_transport_headers ) = 0.
      RETURN.
    ENDIF.

    lt_requests = read_requests( it_transport_headers ).
    rt_tadir = resolve( lt_requests ).
  ENDMETHOD.

  METHOD find_top_package.
* assumption: all objects in transport share a common super package

    DATA: lt_obj   TYPE lif_sap_package=>ty_devclass_tt,
          lt_super TYPE lif_sap_package=>ty_devclass_tt,
          lv_super LIKE LINE OF lt_super,
          lv_index TYPE i.

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

    READ TABLE it_tadir INDEX 1 ASSIGNING <ls_tadir>.
    ASSERT sy-subrc = 0.
    lt_super = lcl_sap_package=>get( <ls_tadir>-devclass )->list_superpackages( ).

    LOOP AT it_tadir ASSIGNING <ls_tadir>.
      lt_obj = lcl_sap_package=>get( <ls_tadir>-devclass )->list_superpackages( ).

* filter out possibilities from lt_super
      LOOP AT lt_super INTO lv_super.
        lv_index = sy-tabix.
        READ TABLE lt_obj FROM lv_super TRANSPORTING NO FIELDS.
        IF sy-subrc <> 0.
          DELETE lt_super INDEX lv_index.
        ENDIF.
      ENDLOOP.
    ENDLOOP.

    SORT lt_super.
    READ TABLE lt_super INDEX 1 INTO rv_package.
  ENDMETHOD.

  METHOD read_requests.
    DATA lt_requests LIKE rt_requests.
    FIELD-SYMBOLS <fs_trkorr> LIKE LINE OF it_trkorr.

    LOOP AT it_trkorr ASSIGNING <fs_trkorr>.
      CALL FUNCTION 'TR_READ_REQUEST_WITH_TASKS'
        EXPORTING
          iv_trkorr     = <fs_trkorr>-trkorr
        IMPORTING
          et_requests   = lt_requests
        EXCEPTIONS
          invalid_input = 1
          OTHERS        = 2.
      IF sy-subrc <> 0.
        lcx_exception=>raise( 'error from TR_READ_REQUEST_WITH_TASKS' ).
      ENDIF.

      APPEND LINES OF lt_requests TO rt_requests.
    ENDLOOP.
  ENDMETHOD.

  METHOD resolve.
    DATA: lv_object     TYPE tadir-object,
          lv_obj_name   TYPE tadir-obj_name,
          lv_trobj_name TYPE trobj_name,
          ls_tadir      TYPE tadir.

    FIELD-SYMBOLS: <ls_request> LIKE LINE OF it_requests,
                   <ls_object>  LIKE LINE OF <ls_request>-objects.

    LOOP AT it_requests ASSIGNING <ls_request>.
      LOOP AT <ls_request>-objects ASSIGNING <ls_object>.
        IF <ls_object>-pgmid = 'LIMU'.
          CALL FUNCTION 'GET_R3TR_OBJECT_FROM_LIMU_OBJ'
            EXPORTING
              p_limu_objtype = <ls_object>-object
              p_limu_objname = <ls_object>-obj_name
            IMPORTING
              p_r3tr_objtype = lv_object
              p_r3tr_objname = lv_trobj_name
            EXCEPTIONS
              no_mapping     = 1
              OTHERS         = 2.
          IF sy-subrc <> 0.
            lcx_exception=>raise( 'error from GET_R3TR_OBJECT_FROM_LIMU_OBJ' ).
          ENDIF.
          lv_obj_name = lv_trobj_name.
        ELSE.
          lv_object   = <ls_object>-object.
          lv_obj_name = <ls_object>-obj_name.
        ENDIF.

        ls_tadir = lcl_tadir=>read_single(
          iv_object   = lv_object
          iv_obj_name = lv_obj_name ).

        APPEND ls_tadir TO rt_tadir.
      ENDLOOP.
    ENDLOOP.

    SORT rt_tadir BY object ASCENDING obj_name ASCENDING.
    DELETE ADJACENT DUPLICATES FROM rt_tadir COMPARING object obj_name.
    DELETE rt_tadir WHERE table_line IS INITIAL.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_transport_objects DEFINITION.
  "Under test at ltcl_transport_objects
  PUBLIC SECTION.
    METHODS constructor
      IMPORTING
        it_transport_objects TYPE scts_tadir.
    METHODS to_stage
      IMPORTING
        io_stage           TYPE REF TO lcl_stage
        is_stage_objects   TYPE ty_stage_files
        it_object_statuses TYPE ty_results_tt
      RAISING
        lcx_exception.
  PRIVATE SECTION.
    DATA mt_transport_objects TYPE scts_tadir.
ENDCLASS.

CLASS lcl_transport_objects IMPLEMENTATION.
  METHOD constructor.
    mt_transport_objects = it_transport_objects.
  ENDMETHOD.

  METHOD to_stage.
    DATA: ls_transport_object TYPE tadir,
          ls_local_file       TYPE ty_file_item,
          ls_object_status    TYPE ty_result.

    LOOP AT mt_transport_objects INTO ls_transport_object.
      LOOP AT it_object_statuses INTO ls_object_status
          WHERE obj_name = ls_transport_object-obj_name
          AND obj_type = ls_transport_object-object
          AND NOT lstate IS INITIAL.

        CASE ls_object_status-lstate.
          WHEN gc_state-added OR gc_state-modified.
            IF ls_transport_object-delflag = abap_true.
              lcx_exception=>raise( |Object { ls_transport_object-obj_name
              } should be added/modified, but has deletion flag in transport| ).
            ENDIF.

            READ TABLE is_stage_objects-local
                  INTO ls_local_file
              WITH KEY item-obj_name = ls_transport_object-obj_name
                       item-obj_type = ls_transport_object-object
                       file-filename = ls_object_status-filename.
            IF sy-subrc <> 0.
              lcx_exception=>raise( |Object { ls_transport_object-obj_name
              } not found in the local repository files| ).
            ENDIF.

            io_stage->add(
              iv_path     = ls_local_file-file-path
              iv_filename = ls_local_file-file-filename
              iv_data     = ls_local_file-file-data ).
          WHEN gc_state-deleted.
            IF ls_transport_object-delflag = abap_false.
              lcx_exception=>raise( |Object { ls_transport_object-obj_name
              } should be removed, but has NO deletion flag in transport| ).
            ENDIF.
            io_stage->rm(
              iv_path     = ls_object_status-path
              iv_filename = ls_object_status-filename ).
          WHEN OTHERS.
            ASSERT 0 = 1. "Unexpected state
        ENDCASE.
      ENDLOOP.
      IF sy-subrc <> 0.
        lcx_exception=>raise( |Object { ls_transport_object-obj_name
        } not found in the local repository files| ).
      ENDIF.
    ENDLOOP.
  ENDMETHOD.

ENDCLASS.

CLASS lcl_transport_to_branch DEFINITION.
  PUBLIC SECTION.
    METHODS:
      create
        IMPORTING io_repository          TYPE REF TO lcl_repo_online
                  is_transport_to_branch TYPE ty_transport_to_branch
                  it_transport_objects   TYPE scts_tadir
        RAISING   lcx_exception.
  PRIVATE SECTION.

    METHODS create_new_branch
      IMPORTING
        io_repository  TYPE REF TO lcl_repo_online
        iv_branch_name TYPE string
      RAISING
        lcx_exception.
    METHODS generate_commit_message
      IMPORTING
        is_transport_to_branch TYPE ty_transport_to_branch
      RETURNING
        VALUE(rs_comment)      TYPE ty_comment.
    METHODS stage_transport_objects
      IMPORTING
        it_transport_objects TYPE scts_tadir
        io_stage             TYPE REF TO lcl_stage
        is_stage_objects     TYPE ty_stage_files
        it_object_statuses   TYPE ty_results_tt
      RAISING
        lcx_exception.
ENDCLASS.

CLASS lcl_transport_to_branch IMPLEMENTATION.

  METHOD create.
    DATA:
      lv_branch_name     TYPE string,
      ls_comment         TYPE ty_comment,
      lo_stage           TYPE REF TO lcl_stage,
      ls_stage_objects   TYPE ty_stage_files,
      lt_object_statuses TYPE ty_results_tt.

    lv_branch_name = lcl_git_branch_list=>complete_heads_branch_name(
        lcl_git_branch_list=>normalize_branch_name( is_transport_to_branch-branch_name ) ).

    create_new_branch(
      io_repository  = io_repository
      iv_branch_name = lv_branch_name ).

    CREATE OBJECT lo_stage
      EXPORTING
        iv_branch_name = lv_branch_name
        iv_branch_sha1 = io_repository->get_sha1_remote( ).

    ls_stage_objects = lcl_stage_logic=>get( io_repository ).

    lt_object_statuses = io_repository->status( ).

    stage_transport_objects(
       it_transport_objects = it_transport_objects
       io_stage             = lo_stage
       is_stage_objects     = ls_stage_objects
       it_object_statuses   = lt_object_statuses ).

    ls_comment = generate_commit_message( is_transport_to_branch ).

    io_repository->push( is_comment = ls_comment
                         io_stage   = lo_stage ).
  ENDMETHOD.

  METHOD create_new_branch.
    ASSERT iv_branch_name CP 'refs/heads/+*'.
    TRY.
        lcl_git_porcelain=>create_branch(
          io_repo = io_repository
          iv_name = iv_branch_name
          iv_from = io_repository->get_sha1_local( ) ).

        io_repository->set_branch_name( iv_branch_name ).
      CATCH lcx_exception.
        lcx_exception=>raise( 'Error when creating new branch').
    ENDTRY.
  ENDMETHOD.

  METHOD generate_commit_message.
    rs_comment-committer-name  = sy-uname.
    rs_comment-committer-email = |{ rs_comment-committer-name }@localhost|.
    rs_comment-comment         = is_transport_to_branch-commit_text.
  ENDMETHOD.

  METHOD stage_transport_objects.
    DATA lo_transport_objects TYPE REF TO lcl_transport_objects.
    CREATE OBJECT lo_transport_objects
      EXPORTING
        it_transport_objects = it_transport_objects.

    lo_transport_objects->to_stage(
      io_stage           = io_stage
      is_stage_objects   = is_stage_objects
      it_object_statuses = it_object_statuses ).
  ENDMETHOD.
ENDCLASS.

fix transport to branch

fix transport to branch


CLASS zcl_abapgit_url DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS:
      host
        IMPORTING
          !iv_repo       TYPE string
        RETURNING
          VALUE(rv_host) TYPE string
        RAISING
          zcx_abapgit_exception,

      name
        IMPORTING
          !iv_repo       TYPE string
        RETURNING
          VALUE(rv_name) TYPE string
        RAISING
          zcx_abapgit_exception,

      path_name
        IMPORTING
          !iv_repo            TYPE string
        RETURNING
          VALUE(rv_path_name) TYPE string
        RAISING
          zcx_abapgit_exception .

  PRIVATE SECTION.
    CLASS-METHODS:
      regex
        IMPORTING
          !iv_repo TYPE string
        EXPORTING
          !ev_host TYPE string
          !ev_path TYPE string
          !ev_name TYPE string
        RAISING
          zcx_abapgit_exception .

ENDCLASS.

CLASS zcl_abapgit_url IMPLEMENTATION.

  METHOD host.

    regex( EXPORTING iv_repo = iv_repo
           IMPORTING ev_host = rv_host ).

  ENDMETHOD.

  METHOD name.

    regex( EXPORTING iv_repo = iv_repo
           IMPORTING ev_name = rv_name ).

  ENDMETHOD.

  METHOD path_name.

    DATA: lv_host TYPE string ##NEEDED.

    FIND REGEX '(.*://[^/]*)(.*)' IN iv_repo
      SUBMATCHES lv_host rv_path_name.

  ENDMETHOD.

  METHOD regex.

    FIND REGEX '(.*://[^/]*)(.*/)([^\.]*)[\.git]?' IN iv_repo
      SUBMATCHES ev_host ev_path ev_name.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'Malformed URL' ).
    ENDIF.

  ENDMETHOD.
ENDCLASS.

Fix lint errors

Fix lint errors


CLASS zcl_abapgit_gui_page_addofflin 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
        " TODO importing prefilled form data
      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,
        url              TYPE string VALUE 'url',
        package          TYPE string VALUE 'package',
        folder_logic     TYPE string VALUE 'folder_logic',
        master_lang_only TYPE string VALUE 'master_lang_only',
      END OF c_id .
    CONSTANTS:
      BEGIN OF c_event,
        go_back          TYPE string VALUE 'go-back',
        choose_package   TYPE string VALUE 'choose-package',
        create_package   TYPE string VALUE 'create-package',
        add_offline_repo TYPE string VALUE 'add-repo-offline',
      END OF c_event .
    DATA mo_validation_log TYPE REF TO zcl_abapgit_string_map .
    DATA mo_form_data TYPE REF TO zcl_abapgit_string_map .
    DATA mo_form TYPE REF TO zcl_abapgit_html_form .

    METHODS parse_form
      IMPORTING
        !it_form_fields     TYPE tihttpnvp
      RETURNING
        VALUE(ro_form_data) TYPE REF TO zcl_abapgit_string_map
      RAISING
        zcx_abapgit_exception .
    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 .
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE_ADDOFFLIN IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    CREATE OBJECT mo_validation_log.
    CREATE OBJECT mo_form_data.
    mo_form = get_form_schema( ).
  ENDMETHOD.

  METHOD create.

    DATA lo_component TYPE REF TO zcl_abapgit_gui_page_addofflin.

    CREATE OBJECT lo_component.

    ri_page = zcl_abapgit_gui_page_hoc=>create(
      iv_page_title = 'Create offline repository'
      ii_child_component = lo_component ).

  ENDMETHOD.

  METHOD get_form_schema.

    ro_form = zcl_abapgit_html_form=>create( iv_form_id = 'add-repo-offline-form' ).

    ro_form->text(
      iv_name        = c_id-url
      iv_required    = abap_true
      iv_label       = 'Repository name'
      iv_hint        = 'Unique name for repository'
    )->text(
      iv_name        = c_id-package
      iv_side_action = c_event-choose_package
      iv_required    = abap_true
      iv_label       = 'Package'
      iv_hint        = 'SAP package for the code (should be a dedicated one)'
      iv_placeholder = 'Z... / $...'
    )->radio(
      iv_name        = c_id-folder_logic
      iv_default_value = zif_abapgit_dot_abapgit=>c_folder_logic-prefix
      iv_label       = 'Folder logic'
      iv_hint        = 'Define how package folders are named in the repo (see https://docs.abapgit.org)'
    )->option(
      iv_label       = 'Prefix'
      iv_value       = zif_abapgit_dot_abapgit=>c_folder_logic-prefix
    )->option(
      iv_label       = 'Full'
      iv_value       = zif_abapgit_dot_abapgit=>c_folder_logic-full
    )->checkbox(
      iv_name        = c_id-master_lang_only
      iv_label       = 'Serialize master language only'
      iv_hint        = 'Ignore translations, serialize just master language'
    )->command(
      iv_label       = 'Create offline repo'
      iv_is_main     = abap_true
      iv_action      = c_event-add_offline_repo
    )->command(
      iv_label       = 'Create package'
      iv_action      = c_event-create_package
    )->command(
      iv_label       = 'Back'
      iv_action      = c_event-go_back ).

  ENDMETHOD.

  METHOD parse_form.

    DATA ls_field LIKE LINE OF it_form_fields.

    CREATE OBJECT ro_form_data.

    " temporary, TODO refactor later, after gui_event class is ready, move to on_event
    LOOP AT it_form_fields INTO ls_field.
      ro_form_data->set(
        iv_key = ls_field-name
        iv_val = ls_field-value ).
    ENDLOOP.

    ro_form_data = mo_form->validate_normalize_form_data( ro_form_data ).

  ENDMETHOD.

  METHOD validate_form.

    DATA lx_err TYPE REF TO zcx_abapgit_exception.

    ro_validation_log = mo_form->validate_required_fields( io_form_data ).

    IF io_form_data->get( c_id-package ) IS NOT INITIAL.
      TRY.
          zcl_abapgit_repo_srv=>get_instance( )->validate_package(
            iv_package    = |{ io_form_data->get( c_id-package ) }| ).
        CATCH zcx_abapgit_exception INTO lx_err.
          ro_validation_log->set(
            iv_key = c_id-package
            iv_val = lx_err->get_text( ) ).
      ENDTRY.
    ENDIF.

    IF io_form_data->get( c_id-folder_logic ) <> zif_abapgit_dot_abapgit=>c_folder_logic-prefix
        AND io_form_data->get( c_id-folder_logic ) <> zif_abapgit_dot_abapgit=>c_folder_logic-full.
      ro_validation_log->set(
        iv_key = c_id-folder_logic
        iv_val = |Invalid folder logic { io_form_data->get( c_id-folder_logic )
        }. Must be { zif_abapgit_dot_abapgit=>c_folder_logic-prefix
        } or { zif_abapgit_dot_abapgit=>c_folder_logic-full } | ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    DATA: ls_repo_params      TYPE zif_abapgit_services_repo=>ty_repo_params,
          lo_new_offline_repo TYPE REF TO zcl_abapgit_repo_offline.

    " import data from html before re-render
    mo_form_data = parse_form( zcl_abapgit_html_action_utils=>parse_post_form_data( ii_event->mt_postdata ) ).

    CASE ii_event->mv_action.
      WHEN c_event-go_back.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-go_back.

      WHEN c_event-create_package.

        mo_form_data->set(
          iv_key = c_id-package
          iv_val = zcl_abapgit_services_basis=>create_package(
            iv_prefill_package = |{ mo_form_data->get( 'package' ) }| ) ).
        IF mo_form_data->get( c_id-package ) IS NOT INITIAL.
          mo_validation_log = validate_form( mo_form_data ).
          rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
        ELSE.
          rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.
        ENDIF.

      WHEN c_event-choose_package.

        mo_form_data->set(
          iv_key = c_id-package
          iv_val = zcl_abapgit_ui_factory=>get_popups( )->popup_search_help( 'TDEVC-DEVCLASS' ) ).
        IF mo_form_data->get( c_id-package ) IS NOT INITIAL.
          mo_validation_log = validate_form( mo_form_data ).
          rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
        ELSE.
          rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.
        ENDIF.

      WHEN c_event-add_offline_repo.

        mo_validation_log = validate_form( mo_form_data ).

        IF mo_validation_log->is_empty( ) = abap_true.
          mo_form_data->to_abap( CHANGING cs_container = ls_repo_params ).
          lo_new_offline_repo = zcl_abapgit_services_repo=>new_offline( ls_repo_params ).
          CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_view
            EXPORTING
              iv_key = lo_new_offline_repo->get_key( ).
          rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page_replacing.
        ELSE.
          rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render. " Display errors
        ENDIF.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_renderable~render.

    gui_services( )->register_event_handler( me ).

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( mo_form->render(
      iv_form_class     = 'dialog w600px m-em5-sides margin-v1' " to center add wmax600px and auto-center instead
      io_values         = mo_form_data
      io_validation_log = mo_validation_log ) ).

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_gui_page_addofflin 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
        " TODO importing prefilled form data
      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,
        url              TYPE string VALUE 'url',
        package          TYPE string VALUE 'package',
        folder_logic     TYPE string VALUE 'folder_logic',
        master_lang_only TYPE string VALUE 'master_lang_only',
      END OF c_id .
    CONSTANTS:
      BEGIN OF c_event,
        go_back          TYPE string VALUE 'go-back',
        choose_package   TYPE string VALUE 'choose-package',
        create_package   TYPE string VALUE 'create-package',
        add_offline_repo TYPE string VALUE 'add-repo-offline',
      END OF c_event .
    DATA mo_validation_log TYPE REF TO zcl_abapgit_string_map .
    DATA mo_form_data TYPE REF TO zcl_abapgit_string_map .
    DATA mo_form TYPE REF TO zcl_abapgit_html_form .

    METHODS parse_form
      IMPORTING
        !it_form_fields     TYPE tihttpnvp
      RETURNING
        VALUE(ro_form_data) TYPE REF TO zcl_abapgit_string_map
      RAISING
        zcx_abapgit_exception .
    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 .
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_PAGE_ADDOFFLIN IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    CREATE OBJECT mo_validation_log.
    CREATE OBJECT mo_form_data.
    mo_form = get_form_schema( ).
  ENDMETHOD.

  METHOD create.

    DATA lo_component TYPE REF TO zcl_abapgit_gui_page_addofflin.

    CREATE OBJECT lo_component.

    ri_page = zcl_abapgit_gui_page_hoc=>create(
      iv_page_title = 'Create offline repository'
      ii_child_component = lo_component ).

  ENDMETHOD.

  METHOD get_form_schema.

    ro_form = zcl_abapgit_html_form=>create( iv_form_id = 'add-repo-offline-form' ).

    ro_form->text(
      iv_name        = c_id-url
      iv_required    = abap_true
      iv_label       = 'Repository name'
      iv_hint        = 'Unique name for repository'
    )->text(
      iv_name        = c_id-package
      iv_side_action = c_event-choose_package
      iv_required    = abap_true
      iv_upper_case  = abap_true
      iv_label       = 'Package'
      iv_hint        = 'SAP package for the code (should be a dedicated one)'
      iv_placeholder = 'Z... / $...'
    )->radio(
      iv_name        = c_id-folder_logic
      iv_default_value = zif_abapgit_dot_abapgit=>c_folder_logic-prefix
      iv_label       = 'Folder logic'
      iv_hint        = 'Define how package folders are named in the repo (see https://docs.abapgit.org)'
    )->option(
      iv_label       = 'Prefix'
      iv_value       = zif_abapgit_dot_abapgit=>c_folder_logic-prefix
    )->option(
      iv_label       = 'Full'
      iv_value       = zif_abapgit_dot_abapgit=>c_folder_logic-full
    )->checkbox(
      iv_name        = c_id-master_lang_only
      iv_label       = 'Serialize master language only'
      iv_hint        = 'Ignore translations, serialize just master language'
    )->command(
      iv_label       = 'Create offline repo'
      iv_is_main     = abap_true
      iv_action      = c_event-add_offline_repo
    )->command(
      iv_label       = 'Create package'
      iv_action      = c_event-create_package
    )->command(
      iv_label       = 'Back'
      iv_action      = c_event-go_back ).

  ENDMETHOD.

  METHOD parse_form.

    DATA ls_field LIKE LINE OF it_form_fields.

    CREATE OBJECT ro_form_data.

    " temporary, TODO refactor later, after gui_event class is ready, move to on_event
    LOOP AT it_form_fields INTO ls_field.
      ro_form_data->set(
        iv_key = ls_field-name
        iv_val = ls_field-value ).
    ENDLOOP.

    ro_form_data = mo_form->validate_normalize_form_data( ro_form_data ).

  ENDMETHOD.

  METHOD validate_form.

    DATA lx_err TYPE REF TO zcx_abapgit_exception.

    ro_validation_log = mo_form->validate_required_fields( io_form_data ).

    IF io_form_data->get( c_id-package ) IS NOT INITIAL.
      TRY.
          zcl_abapgit_repo_srv=>get_instance( )->validate_package(
            iv_package    = |{ io_form_data->get( c_id-package ) }| ).
        CATCH zcx_abapgit_exception INTO lx_err.
          ro_validation_log->set(
            iv_key = c_id-package
            iv_val = lx_err->get_text( ) ).
      ENDTRY.
    ENDIF.

    IF io_form_data->get( c_id-folder_logic ) <> zif_abapgit_dot_abapgit=>c_folder_logic-prefix
        AND io_form_data->get( c_id-folder_logic ) <> zif_abapgit_dot_abapgit=>c_folder_logic-full.
      ro_validation_log->set(
        iv_key = c_id-folder_logic
        iv_val = |Invalid folder logic { io_form_data->get( c_id-folder_logic )
        }. Must be { zif_abapgit_dot_abapgit=>c_folder_logic-prefix
        } or { zif_abapgit_dot_abapgit=>c_folder_logic-full } | ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_gui_event_handler~on_event.

    DATA: ls_repo_params      TYPE zif_abapgit_services_repo=>ty_repo_params,
          lo_new_offline_repo TYPE REF TO zcl_abapgit_repo_offline.

    " import data from html before re-render
    mo_form_data = parse_form( zcl_abapgit_html_action_utils=>parse_post_form_data( ii_event->mt_postdata ) ).

    CASE ii_event->mv_action.
      WHEN c_event-go_back.
        rs_handled-state = zcl_abapgit_gui=>c_event_state-go_back.

      WHEN c_event-create_package.

        mo_form_data->set(
          iv_key = c_id-package
          iv_val = zcl_abapgit_services_basis=>create_package(
            iv_prefill_package = |{ mo_form_data->get( 'package' ) }| ) ).
        IF mo_form_data->get( c_id-package ) IS NOT INITIAL.
          mo_validation_log = validate_form( mo_form_data ).
          rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
        ELSE.
          rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.
        ENDIF.

      WHEN c_event-choose_package.

        mo_form_data->set(
          iv_key = c_id-package
          iv_val = zcl_abapgit_ui_factory=>get_popups( )->popup_search_help( 'TDEVC-DEVCLASS' ) ).
        IF mo_form_data->get( c_id-package ) IS NOT INITIAL.
          mo_validation_log = validate_form( mo_form_data ).
          rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render.
        ELSE.
          rs_handled-state = zcl_abapgit_gui=>c_event_state-no_more_act.
        ENDIF.

      WHEN c_event-add_offline_repo.

        mo_validation_log = validate_form( mo_form_data ).

        IF mo_validation_log->is_empty( ) = abap_true.
          mo_form_data->to_abap( CHANGING cs_container = ls_repo_params ).
          lo_new_offline_repo = zcl_abapgit_services_repo=>new_offline( ls_repo_params ).
          CREATE OBJECT rs_handled-page TYPE zcl_abapgit_gui_page_repo_view
            EXPORTING
              iv_key = lo_new_offline_repo->get_key( ).
          rs_handled-state = zcl_abapgit_gui=>c_event_state-new_page_replacing.
        ELSE.
          rs_handled-state = zcl_abapgit_gui=>c_event_state-re_render. " Display errors
        ENDIF.

    ENDCASE.

  ENDMETHOD.

  METHOD zif_abapgit_gui_renderable~render.

    gui_services( )->register_event_handler( me ).

    CREATE OBJECT ri_html TYPE zcl_abapgit_html.

    ri_html->add( mo_form->render(
      iv_form_class     = 'dialog w600px m-em5-sides margin-v1' " to center add wmax600px and auto-center instead
      io_values         = mo_form_data
      io_validation_log = mo_validation_log ) ).

  ENDMETHOD.
ENDCLASS.

Add Offline: Uppercase package name (#4002)


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.

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.

    FIELD-SYMBOLS: <ls_value>  LIKE LINE OF ls_char-cls_attr_value,
                   <ls_valuet> LIKE LINE OF ls_char-cls_attr_value.

    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 ).

    LOOP AT ls_char-cls_attr_value ASSIGNING <ls_value>.
      <ls_value>-activation_state = 'I'.
    ENDLOOP.
    LOOP AT ls_char-cls_attr_value ASSIGNING <ls_valuet>.
      <ls_value>-activation_state = 'I'.
    ENDLOOP.

    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.

fix dump during pull #1660

CHAR: fix dump during pull #1660

Set the activation state to inactive for the values


CLASS zcl_ags_obj_commit DEFINITION
  PUBLIC
  CREATE PRIVATE .

  PUBLIC SECTION.

    INTERFACES zif_ags_object .

    ALIASES deserialize
      FOR zif_ags_object~deserialize .
    ALIASES get_adler32
      FOR zif_ags_object~get_adler32 .
    ALIASES get_sha1
      FOR zif_ags_object~get_sha1 .
    ALIASES get_type
      FOR zif_ags_object~get_type .
    ALIASES save
      FOR zif_ags_object~save .
    ALIASES serialize
      FOR zif_ags_object~serialize .

    TYPES:
      BEGIN OF ty_userfield,
        name  TYPE string,
        email TYPE string,
        time  TYPE zags_unix_time,
      END OF ty_userfield .
    TYPES:
      BEGIN OF ty_pretty,
        sha1      TYPE zags_sha1,
        tree      TYPE zags_sha1,
        parent    TYPE zags_sha1,
        parent2   TYPE zags_sha1,
        author    TYPE ty_userfield,
        committer TYPE ty_userfield,
        text      TYPE string,
        body      TYPE string,
      END OF ty_pretty .
    TYPES:
      ty_pretty_tt TYPE STANDARD TABLE OF ty_pretty WITH DEFAULT KEY .
    TYPES:
      ty_commit TYPE zcl_abapgit_git_pack=>ty_commit.

    CLASS-METHODS load
      IMPORTING
        !iv_repo         TYPE zags_objects-repo
        !iv_sha1         TYPE zags_objects-sha1
      RETURNING
        VALUE(ro_commit) TYPE REF TO zcl_ags_obj_commit
      RAISING
        zcx_ags_error .
    CLASS-METHODS new
      IMPORTING
        !iv_repo         TYPE zags_objects-repo
      RETURNING
        VALUE(ro_commit) TYPE REF TO zcl_ags_obj_commit
      RAISING
        zcx_ags_error .
    METHODS get
      RETURNING
        VALUE(rs_data) TYPE ty_commit .
    METHODS get_pretty
      RETURNING
        VALUE(rs_data) TYPE ty_pretty
      RAISING
        zcx_ags_error .
    METHODS set_author
      IMPORTING
        !iv_author TYPE ty_commit-author
      RAISING
        zcx_ags_error .
    METHODS set_body
      IMPORTING
        !iv_body TYPE ty_commit-body .
    METHODS set_committer
      IMPORTING
        !iv_committer TYPE ty_commit-committer
      RAISING
        zcx_ags_error .
    METHODS set_parent
      IMPORTING
        !iv_parent TYPE ty_commit-parent .
    METHODS set_parent2
      IMPORTING
        !iv_parent TYPE ty_commit-parent .
    METHODS set_tree
      IMPORTING
        !iv_tree TYPE zags_sha1 .
  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA ms_data TYPE ty_commit .
    DATA mv_new TYPE abap_bool .
    DATA mv_sha1 TYPE zags_sha1 .
    DATA mv_repo TYPE zags_objects-repo .
    DATA mv_adler32 TYPE zags_adler32 .

    METHODS parse_userfield
      IMPORTING
        !iv_field           TYPE string
      RETURNING
        VALUE(rs_userfield) TYPE ty_userfield
      RAISING
        zcx_ags_error .
ENDCLASS.

CLASS ZCL_AGS_OBJ_COMMIT IMPLEMENTATION.

  METHOD get.

    rs_data = ms_data.

  ENDMETHOD.

  METHOD get_pretty.

    DATA: ls_data TYPE ty_commit,
          lt_body TYPE TABLE OF string,
          lv_body LIKE LINE OF lt_body.

    ls_data = get( ).

    rs_data-sha1      = get_sha1( ).
    rs_data-tree      = ls_data-tree.
    rs_data-parent    = ls_data-parent.
    rs_data-parent2   = ls_data-parent2.
    rs_data-author    = parse_userfield( ls_data-author ).
    rs_data-committer = parse_userfield( ls_data-committer ).

    SPLIT ls_data-body AT cl_abap_char_utilities=>newline INTO TABLE lt_body.

    READ TABLE lt_body INDEX 1 INTO lv_body.              "#EC CI_SUBRC
    rs_data-text = lv_body.

    DELETE lt_body INDEX 1.
    CONCATENATE LINES OF lt_body
      INTO rs_data-body
      SEPARATED BY cl_abap_char_utilities=>newline.

  ENDMETHOD.

  METHOD load.

    DATA: ls_data TYPE zags_objects.

    CREATE OBJECT ro_commit.
    ro_commit->mv_new = abap_false.
    ro_commit->mv_sha1 = iv_sha1.

    ls_data = zcl_ags_db=>get_objects( )->single(
      iv_repo = iv_repo
      iv_sha1 = iv_sha1 ).

    ro_commit->deserialize(
      iv_data    = ls_data-data_raw
      iv_adler32 = ls_data-adler32 ).

  ENDMETHOD.

  METHOD new.

    ASSERT NOT iv_repo IS INITIAL.

    CREATE OBJECT ro_commit.
    ro_commit->mv_new = abap_true.
    ro_commit->mv_repo = iv_repo.

  ENDMETHOD.

  METHOD parse_userfield.

    DATA: lv_time TYPE string.

    FIND REGEX '^([\w\*\.\,\(\)\- ]+) <(.*)> (\d{10}) .\d{4}$' IN iv_field
      SUBMATCHES
      rs_userfield-name
      rs_userfield-email
      lv_time ##NO_TEXT.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_ags_error
        EXPORTING
          textid = zcx_ags_error=>m012.
    ENDIF.

    rs_userfield-time = lv_time.

  ENDMETHOD.

  METHOD set_author.

    ASSERT mv_new = abap_true.

    parse_userfield( iv_author ).

    ms_data-author = iv_author.

  ENDMETHOD.

  METHOD set_body.

    ASSERT mv_new = abap_true.

    ms_data-body = iv_body.

  ENDMETHOD.

  METHOD set_committer.

    ASSERT mv_new = abap_true.

    parse_userfield( iv_committer ).

    ms_data-committer = iv_committer.

  ENDMETHOD.

  METHOD set_parent.

    ASSERT mv_new = abap_true.

    ms_data-parent = iv_parent.

  ENDMETHOD.

  METHOD set_parent2.

    ASSERT mv_new = abap_true.

    ms_data-parent2 = iv_parent.

  ENDMETHOD.

  METHOD set_tree.

    ASSERT mv_new = abap_true.

    ms_data-tree = iv_tree.

  ENDMETHOD.

  METHOD zif_ags_object~deserialize.

    TRY.
        ms_data = zcl_abapgit_git_pack=>decode_commit( iv_data ).
      CATCH zcx_abapgit_exception.
        ASSERT 0 = 1.
    ENDTRY.

    mv_adler32 = iv_adler32.

  ENDMETHOD.

  METHOD zif_ags_object~get_adler32.

    IF mv_adler32 IS INITIAL.
      rv_adler32 = zcl_abapgit_hash=>adler32( serialize( ) ).
    ELSE.
      ASSERT NOT mv_adler32 IS INITIAL.
      rv_adler32 = mv_adler32.
    ENDIF.

  ENDMETHOD.

  METHOD zif_ags_object~get_sha1.

    IF mv_new = abap_true.
      rv_sha1 = zcl_ags_util=>sha1(
        iv_type = zif_ags_constants=>c_type-commit
        iv_data = serialize( ) ).
    ELSE.
      ASSERT NOT mv_sha1 IS INITIAL.
      rv_sha1 = mv_sha1.
    ENDIF.

  ENDMETHOD.

  METHOD zif_ags_object~get_type.
    rv_type = zif_ags_constants=>c_type-commit.
  ENDMETHOD.

  METHOD zif_ags_object~save.

    DATA: ls_object TYPE zags_objects.

    ASSERT mv_new = abap_true.

    ls_object-repo = mv_repo.
    ls_object-sha1 = get_sha1( ).
    ls_object-type = get_type( ).
    ls_object-data_raw = serialize( ).
    ls_object-adler32 = get_adler32( ).

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

  ENDMETHOD.

  METHOD zif_ags_object~serialize.

    ASSERT NOT ms_data-tree IS INITIAL.
    ASSERT NOT ms_data-author IS INITIAL.
    ASSERT NOT ms_data-committer IS INITIAL.

    rv_data = zcl_abapgit_git_pack=>encode_commit( ms_data ).

  ENDMETHOD.
ENDCLASS.

CLASS zcl_ags_obj_commit DEFINITION
  PUBLIC
  CREATE PRIVATE .

  PUBLIC SECTION.

    INTERFACES zif_ags_object .

    ALIASES deserialize
      FOR zif_ags_object~deserialize .
    ALIASES get_adler32
      FOR zif_ags_object~get_adler32 .
    ALIASES get_sha1
      FOR zif_ags_object~get_sha1 .
    ALIASES get_type
      FOR zif_ags_object~get_type .
    ALIASES save
      FOR zif_ags_object~save .
    ALIASES serialize
      FOR zif_ags_object~serialize .

    TYPES:
      BEGIN OF ty_userfield,
        name  TYPE string,
        email TYPE string,
        time  TYPE zags_unix_time,
      END OF ty_userfield .
    TYPES:
      BEGIN OF ty_pretty,
        sha1      TYPE zags_sha1,
        tree      TYPE zags_sha1,
        parent    TYPE zags_sha1,
        parent2   TYPE zags_sha1,
        author    TYPE ty_userfield,
        committer TYPE ty_userfield,
        text      TYPE string,
        body      TYPE string,
      END OF ty_pretty .
    TYPES:
      ty_pretty_tt TYPE STANDARD TABLE OF ty_pretty WITH DEFAULT KEY .
    TYPES:
      ty_commit TYPE zcl_abapgit_git_pack=>ty_commit.

    CLASS-METHODS load
      IMPORTING
        !iv_repo         TYPE zags_objects-repo
        !iv_sha1         TYPE zags_objects-sha1
      RETURNING
        VALUE(ro_commit) TYPE REF TO zcl_ags_obj_commit
      RAISING
        zcx_ags_error .
    CLASS-METHODS new
      IMPORTING
        !iv_repo         TYPE zags_objects-repo
      RETURNING
        VALUE(ro_commit) TYPE REF TO zcl_ags_obj_commit
      RAISING
        zcx_ags_error .
    METHODS get
      RETURNING
        VALUE(rs_data) TYPE ty_commit .
    METHODS get_pretty
      RETURNING
        VALUE(rs_data) TYPE ty_pretty
      RAISING
        zcx_ags_error .
    METHODS set_author
      IMPORTING
        !iv_author TYPE ty_commit-author
      RAISING
        zcx_ags_error .
    METHODS set_body
      IMPORTING
        !iv_body TYPE ty_commit-body .
    METHODS set_committer
      IMPORTING
        !iv_committer TYPE ty_commit-committer
      RAISING
        zcx_ags_error .
    METHODS set_parent
      IMPORTING
        !iv_parent TYPE ty_commit-parent .
    METHODS set_parent2
      IMPORTING
        !iv_parent TYPE ty_commit-parent .
    METHODS set_tree
      IMPORTING
        !iv_tree TYPE zags_sha1 .
  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA ms_data TYPE ty_commit .
    DATA mv_new TYPE abap_bool .
    DATA mv_sha1 TYPE zags_sha1 .
    DATA mv_repo TYPE zags_objects-repo .
    DATA mv_adler32 TYPE zags_adler32 .

    METHODS parse_userfield
      IMPORTING
        !iv_field           TYPE string
      RETURNING
        VALUE(rs_userfield) TYPE ty_userfield
      RAISING
        zcx_ags_error .
ENDCLASS.

CLASS ZCL_AGS_OBJ_COMMIT IMPLEMENTATION.

  METHOD get.

    rs_data = ms_data.

  ENDMETHOD.

  METHOD get_pretty.

    DATA: ls_data TYPE ty_commit,
          lt_body TYPE TABLE OF string,
          lv_body LIKE LINE OF lt_body.

    ls_data = get( ).

    rs_data-sha1      = get_sha1( ).
    rs_data-tree      = ls_data-tree.
    rs_data-parent    = ls_data-parent.
    rs_data-parent2   = ls_data-parent2.
    rs_data-author    = parse_userfield( ls_data-author ).
    rs_data-committer = parse_userfield( ls_data-committer ).

    SPLIT ls_data-body AT cl_abap_char_utilities=>newline INTO TABLE lt_body.

    READ TABLE lt_body INDEX 1 INTO lv_body.              "#EC CI_SUBRC
    rs_data-text = lv_body.

    DELETE lt_body INDEX 1.
    CONCATENATE LINES OF lt_body
      INTO rs_data-body
      SEPARATED BY cl_abap_char_utilities=>newline.

  ENDMETHOD.

  METHOD load.

    DATA: ls_data TYPE zags_objects.

    CREATE OBJECT ro_commit.
    ro_commit->mv_new = abap_false.
    ro_commit->mv_sha1 = iv_sha1.

    ls_data = zcl_ags_db=>get_objects( )->single(
      iv_repo = iv_repo
      iv_sha1 = iv_sha1 ).

    ro_commit->deserialize(
      iv_data    = ls_data-data_raw
      iv_adler32 = ls_data-adler32 ).

  ENDMETHOD.

  METHOD new.

    ASSERT NOT iv_repo IS INITIAL.

    CREATE OBJECT ro_commit.
    ro_commit->mv_new = abap_true.
    ro_commit->mv_repo = iv_repo.

  ENDMETHOD.

  METHOD parse_userfield.

    DATA: lv_time TYPE string.

    FIND REGEX '^([\w\*\.\,\(\)\-\[\] ]+) <(.*)> (\d{10}) .\d{4}$' IN iv_field
      SUBMATCHES
      rs_userfield-name
      rs_userfield-email
      lv_time ##NO_TEXT.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_ags_error
        EXPORTING
          textid = zcx_ags_error=>m012.
    ENDIF.

    rs_userfield-time = lv_time.

  ENDMETHOD.

  METHOD set_author.

    ASSERT mv_new = abap_true.

    parse_userfield( iv_author ).

    ms_data-author = iv_author.

  ENDMETHOD.

  METHOD set_body.

    ASSERT mv_new = abap_true.

    ms_data-body = iv_body.

  ENDMETHOD.

  METHOD set_committer.

    ASSERT mv_new = abap_true.

    parse_userfield( iv_committer ).

    ms_data-committer = iv_committer.

  ENDMETHOD.

  METHOD set_parent.

    ASSERT mv_new = abap_true.

    ms_data-parent = iv_parent.

  ENDMETHOD.

  METHOD set_parent2.

    ASSERT mv_new = abap_true.

    ms_data-parent2 = iv_parent.

  ENDMETHOD.

  METHOD set_tree.

    ASSERT mv_new = abap_true.

    ms_data-tree = iv_tree.

  ENDMETHOD.

  METHOD zif_ags_object~deserialize.

    TRY.
        ms_data = zcl_abapgit_git_pack=>decode_commit( iv_data ).
      CATCH zcx_abapgit_exception.
        ASSERT 0 = 1.
    ENDTRY.

    mv_adler32 = iv_adler32.

  ENDMETHOD.

  METHOD zif_ags_object~get_adler32.

    IF mv_adler32 IS INITIAL.
      rv_adler32 = zcl_abapgit_hash=>adler32( serialize( ) ).
    ELSE.
      ASSERT NOT mv_adler32 IS INITIAL.
      rv_adler32 = mv_adler32.
    ENDIF.

  ENDMETHOD.

  METHOD zif_ags_object~get_sha1.

    IF mv_new = abap_true.
      rv_sha1 = zcl_ags_util=>sha1(
        iv_type = zif_ags_constants=>c_type-commit
        iv_data = serialize( ) ).
    ELSE.
      ASSERT NOT mv_sha1 IS INITIAL.
      rv_sha1 = mv_sha1.
    ENDIF.

  ENDMETHOD.

  METHOD zif_ags_object~get_type.
    rv_type = zif_ags_constants=>c_type-commit.
  ENDMETHOD.

  METHOD zif_ags_object~save.

    DATA: ls_object TYPE zags_objects.

    ASSERT mv_new = abap_true.

    ls_object-repo = mv_repo.
    ls_object-sha1 = get_sha1( ).
    ls_object-type = get_type( ).
    ls_object-data_raw = serialize( ).
    ls_object-adler32 = get_adler32( ).

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

  ENDMETHOD.

  METHOD zif_ags_object~serialize.

    ASSERT NOT ms_data-tree IS INITIAL.
    ASSERT NOT ms_data-author IS INITIAL.
    ASSERT NOT ms_data-committer IS INITIAL.

    rv_data = zcl_abapgit_git_pack=>encode_commit( ms_data ).

  ENDMETHOD.
ENDCLASS.

Support special characters in committer name


CLASS zcl_abapgit_object_doma DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

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

  PROTECTED SECTION.
  PRIVATE SECTION.

    TYPES: BEGIN OF ty_dd01_texts,
             ddlanguage TYPE dd01v-ddlanguage,
             ddtext     TYPE dd01v-ddtext,
           END OF ty_dd01_texts,
           BEGIN OF ty_dd07_texts,
             valpos     TYPE dd07v-valpos,
             ddlanguage TYPE dd07v-ddlanguage,
             domvalue_l TYPE dd07v-domvalue_l,
             domvalue_h TYPE dd07v-domvalue_h,
             ddtext     TYPE dd07v-ddtext,
             domval_ld  TYPE dd07v-domval_ld,
             domval_hd  TYPE dd07v-domval_hd,
           END OF ty_dd07_texts,
           tt_dd01_texts TYPE STANDARD TABLE OF ty_dd01_texts,
           tt_dd07_texts TYPE STANDARD TABLE OF ty_dd07_texts.
    CONSTANTS: c_longtext_id_doma TYPE dokil-id VALUE 'DO'.

    METHODS:
      serialize_texts
        IMPORTING io_xml TYPE REF TO zcl_abapgit_xml_output
        RAISING   zcx_abapgit_exception,
      deserialize_texts
        IMPORTING io_xml   TYPE REF TO zcl_abapgit_xml_input
                  is_dd01v TYPE dd01v
                  it_dd07v TYPE dd07v_tab
        RAISING   zcx_abapgit_exception.

ENDCLASS.

CLASS ZCL_ABAPGIT_OBJECT_DOMA IMPLEMENTATION.

  METHOD deserialize_texts.

    DATA: lv_name       TYPE ddobjname,
          lv_valpos     TYPE valpos,
          ls_dd01v_tmp  TYPE dd01v,
          lt_dd07v_tmp  TYPE TABLE OF dd07v,
          lt_i18n_langs TYPE TABLE OF langu,
          lt_dd01_texts TYPE tt_dd01_texts,
          lt_dd07_texts TYPE tt_dd07_texts.

    FIELD-SYMBOLS: <lv_lang>      LIKE LINE OF lt_i18n_langs,
                   <ls_dd07v>     LIKE LINE OF it_dd07v,
                   <ls_dd01_text> LIKE LINE OF lt_dd01_texts,
                   <ls_dd07_text> LIKE LINE OF lt_dd07_texts.

    lv_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'I18N_LANGS'
                  CHANGING  cg_data = lt_i18n_langs ).

    io_xml->read( EXPORTING iv_name = 'DD01_TEXTS'
                  CHANGING  cg_data = lt_dd01_texts ).

    io_xml->read( EXPORTING iv_name = 'DD07_TEXTS'
                  CHANGING  cg_data = lt_dd07_texts ).

    SORT lt_i18n_langs.
    SORT lt_dd07_texts BY ddlanguage. " Optimization

    LOOP AT lt_i18n_langs ASSIGNING <lv_lang>.

      " Domain description
      ls_dd01v_tmp = is_dd01v.
      READ TABLE lt_dd01_texts ASSIGNING <ls_dd01_text> WITH KEY ddlanguage = <lv_lang>.
      IF sy-subrc > 0.
        zcx_abapgit_exception=>raise( |DD01_TEXTS cannot find lang { <lv_lang> } in XML| ).
      ENDIF.
      MOVE-CORRESPONDING <ls_dd01_text> TO ls_dd01v_tmp.

      " Domain values
      lt_dd07v_tmp = it_dd07v.
      LOOP AT lt_dd07v_tmp ASSIGNING <ls_dd07v>.
        lv_valpos = <ls_dd07v>-valpos.
        READ TABLE lt_dd07_texts ASSIGNING <ls_dd07_text>
          WITH KEY ddlanguage = <lv_lang> valpos = <ls_dd07v>-valpos.
        CHECK sy-subrc = 0. " ! no translation -> master translation remain (maybe not OK)
        MOVE-CORRESPONDING <ls_dd07_text> TO <ls_dd07v>.
        <ls_dd07v>-valpos = lv_valpos.
        DELETE lt_dd07_texts INDEX sy-tabix. " Optimization
      ENDLOOP.

      CALL FUNCTION 'DDIF_DOMA_PUT'
        EXPORTING
          name              = lv_name
          dd01v_wa          = ls_dd01v_tmp
        TABLES
          dd07v_tab         = lt_dd07v_tmp
        EXCEPTIONS
          doma_not_found    = 1
          name_inconsistent = 2
          doma_inconsistent = 3
          put_failure       = 4
          put_refused       = 5
          OTHERS            = 6.
      IF sy-subrc <> 0.
        zcx_abapgit_exception=>raise( 'error from DDIF_DOMA_PUT @TEXTS' ).
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

  METHOD serialize_texts.

    DATA: lv_name       TYPE ddobjname,
          lv_index      TYPE i,
          ls_dd01v      TYPE dd01v,
          lt_dd07v      TYPE TABLE OF dd07v,
          lt_i18n_langs TYPE TABLE OF langu,
          lt_dd01_texts TYPE tt_dd01_texts,
          lt_dd07_texts TYPE tt_dd07_texts.

    FIELD-SYMBOLS: <lv_lang>      LIKE LINE OF lt_i18n_langs,
                   <ls_dd07v>     LIKE LINE OF lt_dd07v,
                   <ls_dd01_text> LIKE LINE OF lt_dd01_texts,
                   <ls_dd07_text> LIKE LINE OF lt_dd07_texts.

    IF io_xml->i18n_params( )-serialize_master_lang_only = abap_true.
      RETURN.
    ENDIF.

    lv_name = ms_item-obj_name.

    " Collect additional languages, skip master lang - it was serialized already
    SELECT DISTINCT ddlanguage AS langu INTO TABLE lt_i18n_langs
      FROM dd01v
      WHERE domname = lv_name
      AND ddlanguage <> mv_language.                      "#EC CI_SUBRC

    LOOP AT lt_i18n_langs ASSIGNING <lv_lang>.
      lv_index = sy-tabix.

      CALL FUNCTION 'DDIF_DOMA_GET'
        EXPORTING
          name          = lv_name
          langu         = <lv_lang>
        IMPORTING
          dd01v_wa      = ls_dd01v
        TABLES
          dd07v_tab     = lt_dd07v
        EXCEPTIONS
          illegal_input = 1
          OTHERS        = 2.
      IF sy-subrc <> 0 OR ls_dd01v-ddlanguage IS INITIAL.
        DELETE lt_i18n_langs INDEX lv_index. " Don't save this lang
        CONTINUE.
      ENDIF.

      APPEND INITIAL LINE TO lt_dd01_texts ASSIGNING <ls_dd01_text>.
      MOVE-CORRESPONDING ls_dd01v TO <ls_dd01_text>.

      LOOP AT lt_dd07v ASSIGNING <ls_dd07v> WHERE NOT ddlanguage IS INITIAL.
        APPEND INITIAL LINE TO lt_dd07_texts ASSIGNING <ls_dd07_text>.
        MOVE-CORRESPONDING <ls_dd07v> TO <ls_dd07_text>.
      ENDLOOP.

    ENDLOOP.

    SORT lt_i18n_langs ASCENDING.
    SORT lt_dd01_texts BY ddlanguage ASCENDING.
    SORT lt_dd07_texts BY valpos ASCENDING ddlanguage ASCENDING.

    IF lines( lt_i18n_langs ) > 0.
      io_xml->add( iv_name = 'I18N_LANGS'
                   ig_data = lt_i18n_langs ).

      io_xml->add( iv_name = 'DD01_TEXTS'
                   ig_data = lt_dd01_texts ).

      io_xml->add( iv_name = 'DD07_TEXTS'
                   ig_data = lt_dd07_texts ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE as4user FROM dd01l INTO rv_user
      WHERE domname = ms_item-obj_name
      AND as4local = 'A'
      AND as4vers = '0000'.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    IF zif_abapgit_object~exists( ) = abap_false.
      RETURN.
    ENDIF.

    delete_ddic( iv_objtype              = 'D'
                 iv_no_ask_delete_append = abap_true ).

    delete_longtexts( c_longtext_id_doma ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

* package SEDD
* package SDIC

* fm TR_TADIR_INTERFACE
* fm RS_CORR_INSERT ?

    DATA: lv_name  TYPE ddobjname,
          ls_dd01v TYPE dd01v,
          lt_dd07v TYPE TABLE OF dd07v.

    FIELD-SYMBOLS <ls_dd07v> TYPE dd07v.

    io_xml->read( EXPORTING iv_name = 'DD01V'
                  CHANGING cg_data = ls_dd01v ).
    io_xml->read( EXPORTING iv_name = 'DD07V_TAB'
                  CHANGING cg_data = lt_dd07v ).

    corr_insert( iv_package = iv_package
                 ig_object_class = 'DICT' ).

    lv_name = ms_item-obj_name. " type conversion

    LOOP AT lt_dd07v ASSIGNING <ls_dd07v>.
      <ls_dd07v>-domname = lv_name.
      <ls_dd07v>-valpos = sy-tabix.
    ENDLOOP.

    CALL FUNCTION 'DDIF_DOMA_PUT'
      EXPORTING
        name              = lv_name
        dd01v_wa          = ls_dd01v
      TABLES
        dd07v_tab         = lt_dd07v
      EXCEPTIONS
        doma_not_found    = 1
        name_inconsistent = 2
        doma_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from DDIF_DOMA_PUT' ).
    ENDIF.

    deserialize_texts( io_xml   = io_xml
                       is_dd01v = ls_dd01v
                       it_dd07v = lt_dd07v ).

    deserialize_longtexts( io_xml ).

    zcl_abapgit_objects_activation=>add_item( ms_item ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA: lv_domname TYPE dd01l-domname.

    SELECT SINGLE domname FROM dd01l INTO lv_domname
      WHERE domname = ms_item-obj_name
      AND as4local = 'A'
      AND as4vers = '0000'.
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_comparator.
    RETURN.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_deserialize_steps.
    APPEND zif_abapgit_object=>gc_step_id-ddic TO rt_steps.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
    rs_metadata-ddic = abap_true.
  ENDMETHOD.

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

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = exists_a_lock_entry_for( iv_lock_object = 'ESDICT'
                                            iv_argument    = |{ ms_item-obj_type }{ ms_item-obj_name }| ).
  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    jump_se11( iv_radio = 'RSRD1-DOMA'
               iv_field = 'RSRD1-DOMA_VAL' ).

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: lv_name    TYPE ddobjname,
          ls_dd01v   TYPE dd01v,
          lv_masklen TYPE c LENGTH 4,
          lt_dd07v   TYPE TABLE OF dd07v.

    lv_name = ms_item-obj_name.

    CALL FUNCTION 'DDIF_DOMA_GET'
      EXPORTING
        name          = lv_name
        langu         = mv_language
      IMPORTING
        dd01v_wa      = ls_dd01v
      TABLES
        dd07v_tab     = lt_dd07v
      EXCEPTIONS
        illegal_input = 1
        OTHERS        = 2.
    IF sy-subrc <> 0 OR ls_dd01v IS INITIAL.
      zcx_abapgit_exception=>raise( 'error from DDIF_DOMA_GET' ).
    ENDIF.

    CLEAR: ls_dd01v-as4user,
           ls_dd01v-as4date,
           ls_dd01v-as4time,
           ls_dd01v-appexist.

* make sure XML serialization does not dump if the field contains invalid data
* note that this is a N field, so '' is not valid
    IF ls_dd01v-authclass = ''.
      CLEAR ls_dd01v-authclass.
    ENDIF.
    lv_masklen = ls_dd01v-masklen.
    IF lv_masklen = '' OR NOT lv_masklen CO '0123456789'.
      CLEAR ls_dd01v-masklen.
    ENDIF.

    DELETE lt_dd07v WHERE appval = abap_true.

    SORT lt_dd07v BY
      valpos ASCENDING
      ddlanguage ASCENDING.

    io_xml->add( iv_name = 'DD01V'
                 ig_data = ls_dd01v ).
    io_xml->add( iv_name = 'DD07V_TAB'
                 ig_data = lt_dd07v ).

    serialize_texts( io_xml ).

    serialize_longtexts( io_xml         = io_xml
                         iv_longtext_id = c_longtext_id_doma ).

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_object_doma DEFINITION PUBLIC INHERITING FROM zcl_abapgit_objects_super FINAL.

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

  PROTECTED SECTION.
  PRIVATE SECTION.

    TYPES:
      BEGIN OF ty_dd01_texts,
        ddlanguage TYPE dd01v-ddlanguage,
        ddtext     TYPE dd01v-ddtext,
      END OF ty_dd01_texts .
    TYPES:
      BEGIN OF ty_dd07_texts,
        valpos     TYPE dd07v-valpos,
        ddlanguage TYPE dd07v-ddlanguage,
        domvalue_l TYPE dd07v-domvalue_l,
        domvalue_h TYPE dd07v-domvalue_h,
        ddtext     TYPE dd07v-ddtext,
        domval_ld  TYPE dd07v-domval_ld,
        domval_hd  TYPE dd07v-domval_hd,
      END OF ty_dd07_texts .
    TYPES:
      tt_dd01_texts TYPE STANDARD TABLE OF ty_dd01_texts .
    TYPES:
      tt_dd07_texts TYPE STANDARD TABLE OF ty_dd07_texts .

    CONSTANTS c_longtext_id_doma TYPE dokil-id VALUE 'DO' ##NO_TEXT.

    METHODS serialize_texts
      IMPORTING
        !io_xml   TYPE REF TO zcl_abapgit_xml_output
        !it_dd07v TYPE dd07v_tab
      RAISING
        zcx_abapgit_exception .
    METHODS deserialize_texts
      IMPORTING
        !io_xml   TYPE REF TO zcl_abapgit_xml_input
        !is_dd01v TYPE dd01v
        !it_dd07v TYPE dd07v_tab
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_OBJECT_DOMA IMPLEMENTATION.

  METHOD deserialize_texts.

    DATA: lv_name       TYPE ddobjname,
          lv_valpos     TYPE valpos,
          ls_dd01v_tmp  TYPE dd01v,
          lt_dd07v_tmp  TYPE TABLE OF dd07v,
          lt_i18n_langs TYPE TABLE OF langu,
          lt_dd01_texts TYPE tt_dd01_texts,
          lt_dd07_texts TYPE tt_dd07_texts.

    FIELD-SYMBOLS: <lv_lang>      LIKE LINE OF lt_i18n_langs,
                   <ls_dd07v>     LIKE LINE OF it_dd07v,
                   <ls_dd01_text> LIKE LINE OF lt_dd01_texts,
                   <ls_dd07_text> LIKE LINE OF lt_dd07_texts.

    lv_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'I18N_LANGS'
                  CHANGING  cg_data = lt_i18n_langs ).

    io_xml->read( EXPORTING iv_name = 'DD01_TEXTS'
                  CHANGING  cg_data = lt_dd01_texts ).

    io_xml->read( EXPORTING iv_name = 'DD07_TEXTS'
                  CHANGING  cg_data = lt_dd07_texts ).

    SORT lt_i18n_langs.
    SORT lt_dd07_texts BY ddlanguage. " Optimization

    LOOP AT lt_i18n_langs ASSIGNING <lv_lang>.

      " Domain description
      ls_dd01v_tmp = is_dd01v.
      READ TABLE lt_dd01_texts ASSIGNING <ls_dd01_text> WITH KEY ddlanguage = <lv_lang>.
      IF sy-subrc > 0.
        zcx_abapgit_exception=>raise( |DD01_TEXTS cannot find lang { <lv_lang> } in XML| ).
      ENDIF.
      MOVE-CORRESPONDING <ls_dd01_text> TO ls_dd01v_tmp.

      " Domain values
      lt_dd07v_tmp = it_dd07v.
      LOOP AT lt_dd07v_tmp ASSIGNING <ls_dd07v>.
        lv_valpos = <ls_dd07v>-valpos.
        " it_dd07v was potentially renumbered so lookup by value
        READ TABLE lt_dd07_texts ASSIGNING <ls_dd07_text>
          WITH KEY ddlanguage = <lv_lang> domvalue_l = <ls_dd07v>-domvalue_l domvalue_h = <ls_dd07v>-domvalue_h.
        IF sy-subrc = 0.
          MOVE-CORRESPONDING <ls_dd07_text> TO <ls_dd07v>.
          <ls_dd07v>-valpos = lv_valpos.
          DELETE lt_dd07_texts INDEX sy-tabix. " Optimization
        ELSE.
          " no translation -> keep entry but clear texts
          <ls_dd07v>-ddlanguage = <lv_lang>.
          CLEAR: <ls_dd07v>-ddtext, <ls_dd07v>-domval_ld, <ls_dd07v>-domval_hd.
        ENDIF.
      ENDLOOP.

      CALL FUNCTION 'DDIF_DOMA_PUT'
        EXPORTING
          name              = lv_name
          dd01v_wa          = ls_dd01v_tmp
        TABLES
          dd07v_tab         = lt_dd07v_tmp
        EXCEPTIONS
          doma_not_found    = 1
          name_inconsistent = 2
          doma_inconsistent = 3
          put_failure       = 4
          put_refused       = 5
          OTHERS            = 6.
      IF sy-subrc <> 0.
        zcx_abapgit_exception=>raise( 'error from DDIF_DOMA_PUT @TEXTS' ).
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

  METHOD serialize_texts.

    DATA: lv_name       TYPE ddobjname,
          lv_index      TYPE i,
          ls_dd01v      TYPE dd01v,
          lt_dd07v      TYPE TABLE OF dd07v,
          lt_i18n_langs TYPE TABLE OF langu,
          lt_dd01_texts TYPE tt_dd01_texts,
          lt_dd07_texts TYPE tt_dd07_texts.

    FIELD-SYMBOLS: <lv_lang>      LIKE LINE OF lt_i18n_langs,
                   <ls_dd07v>     LIKE LINE OF lt_dd07v,
                   <ls_dd07v_tmp> LIKE LINE OF lt_dd07v,
                   <ls_dd01_text> LIKE LINE OF lt_dd01_texts,
                   <ls_dd07_text> LIKE LINE OF lt_dd07_texts.

    IF io_xml->i18n_params( )-serialize_master_lang_only = abap_true.
      RETURN.
    ENDIF.

    lv_name = ms_item-obj_name.

    " Collect additional languages, skip master lang - it was serialized already
    SELECT DISTINCT ddlanguage AS langu INTO TABLE lt_i18n_langs
      FROM dd01v
      WHERE domname = lv_name
      AND ddlanguage <> mv_language.                      "#EC CI_SUBRC

    LOOP AT lt_i18n_langs ASSIGNING <lv_lang>.
      lv_index = sy-tabix.

      CALL FUNCTION 'DDIF_DOMA_GET'
        EXPORTING
          name          = lv_name
          langu         = <lv_lang>
        IMPORTING
          dd01v_wa      = ls_dd01v
        TABLES
          dd07v_tab     = lt_dd07v
        EXCEPTIONS
          illegal_input = 1
          OTHERS        = 2.
      IF sy-subrc <> 0 OR ls_dd01v-ddlanguage IS INITIAL.
        DELETE lt_i18n_langs INDEX lv_index. " Don't save this lang
        CONTINUE.
      ENDIF.

      APPEND INITIAL LINE TO lt_dd01_texts ASSIGNING <ls_dd01_text>.
      MOVE-CORRESPONDING ls_dd01v TO <ls_dd01_text>.

      " Process master language entries and find corresponding translation
      LOOP AT it_dd07v ASSIGNING <ls_dd07v> WHERE NOT ddlanguage IS INITIAL.
        APPEND INITIAL LINE TO lt_dd07_texts ASSIGNING <ls_dd07_text>.
        READ TABLE lt_dd07v ASSIGNING <ls_dd07v_tmp>
          WITH KEY ddlanguage = <lv_lang> domvalue_l = <ls_dd07v>-domvalue_l domvalue_h = <ls_dd07v>-domvalue_h.
        IF sy-subrc = 0.
          MOVE-CORRESPONDING <ls_dd07v_tmp> TO <ls_dd07_text>.
        ELSE.
          " no translation -> keep entry but clear texts
          <ls_dd07_text>-ddlanguage = <lv_lang>.
          CLEAR: <ls_dd07_text>-ddtext, <ls_dd07_text>-domval_ld, <ls_dd07_text>-domval_hd.
        ENDIF.
      ENDLOOP.

    ENDLOOP.

    SORT lt_i18n_langs ASCENDING.
    SORT lt_dd01_texts BY ddlanguage ASCENDING.
    SORT lt_dd07_texts BY valpos ASCENDING ddlanguage ASCENDING.

    IF lines( lt_i18n_langs ) > 0.
      io_xml->add( iv_name = 'I18N_LANGS'
                   ig_data = lt_i18n_langs ).

      io_xml->add( iv_name = 'DD01_TEXTS'
                   ig_data = lt_dd01_texts ).

      io_xml->add( iv_name = 'DD07_TEXTS'
                   ig_data = lt_dd07_texts ).
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~changed_by.

    SELECT SINGLE as4user FROM dd01l INTO rv_user
      WHERE domname = ms_item-obj_name
      AND as4local = 'A'
      AND as4vers = '0000'.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

  METHOD zif_abapgit_object~delete.

    IF zif_abapgit_object~exists( ) = abap_false.
      RETURN.
    ENDIF.

    delete_ddic( iv_objtype              = 'D'
                 iv_no_ask_delete_append = abap_true ).

    delete_longtexts( c_longtext_id_doma ).

  ENDMETHOD.

  METHOD zif_abapgit_object~deserialize.

* package SEDD
* package SDIC

* fm TR_TADIR_INTERFACE
* fm RS_CORR_INSERT ?

    DATA: lv_name  TYPE ddobjname,
          ls_dd01v TYPE dd01v,
          lt_dd07v TYPE TABLE OF dd07v.

    FIELD-SYMBOLS <ls_dd07v> TYPE dd07v.

    io_xml->read( EXPORTING iv_name = 'DD01V'
                  CHANGING cg_data = ls_dd01v ).
    io_xml->read( EXPORTING iv_name = 'DD07V_TAB'
                  CHANGING cg_data = lt_dd07v ).

    corr_insert( iv_package = iv_package
                 ig_object_class = 'DICT' ).

    lv_name = ms_item-obj_name. " type conversion

    LOOP AT lt_dd07v ASSIGNING <ls_dd07v>.
      <ls_dd07v>-domname = lv_name.
      <ls_dd07v>-valpos = sy-tabix.
    ENDLOOP.

    CALL FUNCTION 'DDIF_DOMA_PUT'
      EXPORTING
        name              = lv_name
        dd01v_wa          = ls_dd01v
      TABLES
        dd07v_tab         = lt_dd07v
      EXCEPTIONS
        doma_not_found    = 1
        name_inconsistent = 2
        doma_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      zcx_abapgit_exception=>raise( 'error from DDIF_DOMA_PUT' ).
    ENDIF.

    deserialize_texts( io_xml   = io_xml
                       is_dd01v = ls_dd01v
                       it_dd07v = lt_dd07v ).

    deserialize_longtexts( io_xml ).

    zcl_abapgit_objects_activation=>add_item( ms_item ).

  ENDMETHOD.

  METHOD zif_abapgit_object~exists.

    DATA: lv_domname TYPE dd01l-domname.

    SELECT SINGLE domname FROM dd01l INTO lv_domname
      WHERE domname = ms_item-obj_name
      AND as4local = 'A'
      AND as4vers = '0000'.
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.

  METHOD zif_abapgit_object~get_comparator.
    RETURN.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_deserialize_steps.
    APPEND zif_abapgit_object=>gc_step_id-ddic TO rt_steps.
  ENDMETHOD.

  METHOD zif_abapgit_object~get_metadata.
    rs_metadata = get_metadata( ).
    rs_metadata-ddic = abap_true.
  ENDMETHOD.

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

  METHOD zif_abapgit_object~is_locked.
    rv_is_locked = exists_a_lock_entry_for( iv_lock_object = 'ESDICT'
                                            iv_argument    = |{ ms_item-obj_type }{ ms_item-obj_name }| ).
  ENDMETHOD.

  METHOD zif_abapgit_object~jump.

    jump_se11( iv_radio = 'RSRD1-DOMA'
               iv_field = 'RSRD1-DOMA_VAL' ).

  ENDMETHOD.

  METHOD zif_abapgit_object~serialize.

    DATA: lv_name    TYPE ddobjname,
          ls_dd01v   TYPE dd01v,
          lv_masklen TYPE c LENGTH 4,
          lt_dd07v   TYPE TABLE OF dd07v.

    lv_name = ms_item-obj_name.

    CALL FUNCTION 'DDIF_DOMA_GET'
      EXPORTING
        name          = lv_name
        langu         = mv_language
      IMPORTING
        dd01v_wa      = ls_dd01v
      TABLES
        dd07v_tab     = lt_dd07v
      EXCEPTIONS
        illegal_input = 1
        OTHERS        = 2.
    IF sy-subrc <> 0 OR ls_dd01v IS INITIAL.
      zcx_abapgit_exception=>raise( 'error from DDIF_DOMA_GET' ).
    ENDIF.

    CLEAR: ls_dd01v-as4user,
           ls_dd01v-as4date,
           ls_dd01v-as4time,
           ls_dd01v-appexist.

* make sure XML serialization does not dump if the field contains invalid data
* note that this is a N field, so '' is not valid
    IF ls_dd01v-authclass = ''.
      CLEAR ls_dd01v-authclass.
    ENDIF.
    lv_masklen = ls_dd01v-masklen.
    IF lv_masklen = '' OR NOT lv_masklen CO '0123456789'.
      CLEAR ls_dd01v-masklen.
    ENDIF.

    DELETE lt_dd07v WHERE appval = abap_true.

    SORT lt_dd07v BY
      valpos ASCENDING
      ddlanguage ASCENDING.

    io_xml->add( iv_name = 'DD01V'
                 ig_data = ls_dd01v ).
    io_xml->add( iv_name = 'DD07V_TAB'
                 ig_data = lt_dd07v ).

    serialize_texts( io_xml   = io_xml
                     it_dd07v = lt_dd07v ).

    serialize_longtexts( io_xml         = io_xml
                         iv_longtext_id = c_longtext_id_doma ).

  ENDMETHOD.
ENDCLASS.

DOMA: Fix translation of domain values (#3692)

* DOMA: Fix translations

* DOMA: Fix translations

* Lint

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