?? RIGHT := 110 ??
?? NEWTITLE := 'INSTALL_SOFTWARE Utility: RAP$PERFORM_INSTALLATION_STEPS Interface.' ??
MODULE ram$perform_installation_steps;

{ PURPOSE:
{   This module contains the interface and procedures that perform
{   the installation steps.
{
{ DESIGN:
{   The compiled module resides in RAF$LIBRARY.
{
{ NOTES:
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc clc$standard_file_names
*copyc rac$inss_processor_version
*copyc rac$summary_file_level
*copyc rac$summary_file_name
*copyc rae$install_software_cc
*copyc rat$installation_control_record
*copyc rat$processing_summary_types
?? POP ??
*copyc amp$flush
*copyc amp$get_segment_pointer
*copyc clp$get_system_file_id
*copyc clp$put_job_command_response
*copyc clp$trimmed_string_size
*copyc fsp$close_file
*copyc fsp$open_file
*copyc mmp$create_scratch_segment
*copyc mmp$delete_scratch_segment
*copyc osp$append_status_file
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$set_status_abnormal
*copyc rap$activate_products
*copyc rap$convert_job_record_to_strs
*copyc rap$correct_products
*copyc rap$delete_previous_cycles
*copyc rap$execute_installer_procs
*copyc rap$load_products
*copyc rap$reconcile_cycle_conflicts
*copyc rap$stage_products
*copyc rap$update_directory
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] rap$perform_installation_steps', EJECT ??

{ PURPOSE:
{   This interface performs the installation steps as required by the
{   installation control record.
{
{ DESIGN:
{   This interface contains the calls to the installation steps.  Before
{   the steps are performed, the processing summary file is opened and the
{   job status record for this job is located.  A pointer to the job status
{   record is set in the installation control record.  Each step will
{   record processing status into this record.
{
{   The job status record only shows the status at the instant the status
{   record is read.  The processing summary file (and the job status
{   records) are to be read by the DISPLAY_PROCESSING_SUMMARY command for a
{   state of the processing report.
{
{ NOTES:
{   The status variable on each of the processing step interfaces does not
{   return success or failure of the step.  It is used to indicate failure
{   outside of normal processing.  Success or failure of each step shows up
{   in the job logs.
{
{   A scratch segment is setup to provide any subsequently called interface
{   or procedure a place to do scratch work without having to create their
{   own segments.
{

  PROCEDURE [XDCL] rap$perform_installation_steps
    (VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR status: ost$status);


    VAR
      called_from_package_software: boolean,
      file_opened: boolean,
      ignore_status: ost$status,
      local_status: ost$status,
      subproducts_failed_processing: boolean,
      scratch_segment_pointer: amt$segment_pointer,
      summary_file_fid: amt$file_identifier;


?? NEWTITLE := 'abort_handler', EJECT ??

{ PURPOSE:
{   This procedure cleans up when an abort situation occurs within the
{   block structure.
{
{ DESIGN:
{   The function of this condition handler is to close the scratch segment
{   and the processing summary file when an abort condition arises.
{
{ NOTES:
{

    PROCEDURE abort_handler
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        ignore_status: ost$status;


      IF scratch_segment_pointer.sequence_pointer <> NIL THEN
        mmp$delete_scratch_segment (scratch_segment_pointer, ignore_status);
        scratch_segment_pointer.sequence_pointer := NIL;
      IFEND;

      fsp$close_file (summary_file_fid, ignore_status);

    PROCEND abort_handler;

?? OLDTITLE, EJECT ??


    status.normal := TRUE;
    subproducts_failed_processing := FALSE;
    called_from_package_software := FALSE;
    scratch_segment_pointer.kind := amc$sequence_pointer;
    scratch_segment_pointer.sequence_pointer := NIL;
    file_opened := FALSE;

    osp$establish_block_exit_hndlr (^abort_handler);

  /main/
    BEGIN

      mmp$create_scratch_segment (amc$sequence_pointer, mmc$as_random, scratch_segment_pointer, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;
      installation_control_record.scratch_seq_p := scratch_segment_pointer.sequence_pointer;

      open_processing_summary_file (installation_control_record, summary_file_fid, file_opened, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      display_installing_message (installation_control_record.job_status_record_p^, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$reconcile_cycle_conflicts (installation_control_record, subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$load_products (called_from_package_software, installation_control_record,
            subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$correct_products (installation_control_record, subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$stage_products (installation_control_record, subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$activate_products (installation_control_record, subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$execute_installer_procs (installation_control_record, subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$update_directory (installation_control_record, subproducts_failed_processing, status);
      IF NOT status.normal THEN
        EXIT /main/;
      IFEND;

      rap$delete_previous_cycles (installation_control_record, subproducts_failed_processing, status);

    END /main/;

    IF status.normal AND subproducts_failed_processing THEN
      osp$set_status_abnormal ('RA', rae$subproducts_failed_install, '', status);
    IFEND;

    IF file_opened THEN
      fsp$close_file (summary_file_fid, local_status);
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    IF scratch_segment_pointer.sequence_pointer <> NIL THEN
      mmp$delete_scratch_segment (scratch_segment_pointer, local_status);
      scratch_segment_pointer.sequence_pointer := NIL;
      IF status.normal AND (NOT local_status.normal) THEN
        status := local_status;
      IFEND;
    IFEND;

    osp$disestablish_cond_handler;

  PROCEND rap$perform_installation_steps;

?? OLDTITLE ??
?? NEWTITLE := 'display_installing_message', EJECT ??

{ PURPOSE:
{   This procedure displays the start of installing message to $RESPONSE.
{
{ DESIGN:
{   The installing message is formatted as follows:
{
{     Installing <a> subproducts (<b> steps).
{
{   where:
{     <a> is the initial subproduct count.
{     <b> is the number of steps.
{
{   As an example the following status line could be created:
{
{    "Installing 10 subproducts (7 steps)"
{
{   The information to be displayed comes from the job status record.
{   The record is first converted to string values for displaying.
{
{ NOTES:
{   The $RESPONSE output buffer must be flushed to get the line to display
{   immediately.
{

  PROCEDURE display_installing_message
    (    job_status_record: rat$job_status_record;
     VAR status: ost$status);


    VAR
      length: integer,
      line: string (osc$max_string_size),
      job_status_strs: rat$job_status_record_strs,
      response_fid: amt$file_identifier;


    status.normal := TRUE;

    rap$convert_job_record_to_strs (job_status_record, job_status_strs, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    STRINGREP (line, length, '0Installing ', job_status_strs.initial_subproduct_count.
          value (1, job_status_strs.initial_subproduct_count.size), ' subproducts (',
          job_status_strs.number_of_steps.value (1, job_status_strs.number_of_steps.size), ' steps).');

    clp$put_job_command_response (line (1, length), status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clp$get_system_file_id (clc$job_command_response, response_fid, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    amp$flush (response_fid, osc$nowait, status);

  PROCEND display_installing_message;

?? OLDTITLE ??
?? NEWTITLE := 'open_processing_summary_file', EJECT ??

{ PURPOSE:
{   This procedure opens the processing summary file for the current
{   installation event.
{
{ DESIGN:
{   The processing summary file is opened as a read modify segment access
{   file and the file is validated as being the processing summary file.
{   The job status record for this job is located and a pointer is set in
{   the installation control record.
{
{   When the job status record pointer (from the installation control
{   record) is not nil, the record is already established and the processing
{   summary file is not opened.
{
{   The file must be closed by the calling procedure.
{
{ NOTES:
{

  PROCEDURE open_processing_summary_file
    (VAR installation_control_record {input, output} : rat$installation_control_record;
     VAR summary_file_fid: amt$file_identifier;
     VAR file_opened: boolean;
     VAR status: ost$status);


    VAR
      attachment_options: array [1 .. 3] of fst$attachment_option,
      found: boolean,
      installation_identifier_catalog: rat$path,
      job_status_record_p: ^rat$job_status_record,
      segment_pointer: amt$segment_pointer,
      sequence_descriptor_p: ^rat$sequence_descriptor,
      summary_file: rat$path,
      summary_file_header_p: ^rat$processing_summary_header,
      summary_file_seq_p: ^rat$processing_summary_sequence;


    status.normal := TRUE;

    IF installation_control_record.job_status_record_p <> NIL THEN
      RETURN;
    IFEND;

    attachment_options [1].selector := fsc$access_and_share_modes;
    attachment_options [1].access_modes.selector := fsc$specific_access_modes;
    attachment_options [1].access_modes.value := $fst$file_access_options [fsc$read, fsc$modify];
    attachment_options [1].share_modes.selector := fsc$specific_share_modes;
    attachment_options [1].share_modes.value := $fst$file_access_options [fsc$read, fsc$modify];
    attachment_options [2].selector := fsc$create_file;
    attachment_options [2].create_file := FALSE;
    attachment_options [3].selector := fsc$wait_for_attachment;
    attachment_options [3].wait_for_attachment.wait := osc$wait;
    attachment_options [3].wait_for_attachment.wait_time := fsc$longest_wait_time;

{ Assemble the path to the processing summary file using the installation logs path,
{ the installation identifier and the processing summary file name.

    STRINGREP (installation_identifier_catalog.path, installation_identifier_catalog.size,
          installation_control_record.processing_header_p^.installation_defaults.installation_logs.
          path (1, installation_control_record.processing_header_p^.installation_defaults.installation_logs.
          size), '.', installation_control_record.processing_header_p^.
          installation_identifier (1, clp$trimmed_string_size
          (installation_control_record.processing_header_p^.installation_identifier)));

    STRINGREP (summary_file.path, summary_file.size, installation_identifier_catalog.
          path (1, installation_identifier_catalog.size), '.', rac$summary_file_name);

    file_opened := TRUE;
    fsp$open_file (summary_file.path (1, summary_file.size), amc$segment, ^attachment_options, NIL, NIL, NIL,
          NIL, summary_file_fid, status);
    IF NOT status.normal THEN
      file_opened := FALSE;
      RETURN;
    IFEND;

    amp$get_segment_pointer (summary_file_fid, amc$sequence_pointer, segment_pointer, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    summary_file_seq_p := segment_pointer.sequence_pointer;

    RESET summary_file_seq_p;
    NEXT sequence_descriptor_p IN summary_file_seq_p;
    IF sequence_descriptor_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$unexpected_eof_summary_file, rac$summary_file_name, status);
      osp$append_status_file (osc$status_parameter_delimiter, installation_identifier_catalog.
            path (1, installation_identifier_catalog.size), status);
      RETURN;
    IFEND;

    NEXT summary_file_header_p IN summary_file_seq_p;
    IF summary_file_header_p = NIL THEN
      osp$set_status_abnormal ('RA', rae$unexpected_eof_summary_file, rac$summary_file_name, status);
      osp$append_status_file (osc$status_parameter_delimiter, installation_identifier_catalog.
            path (1, installation_identifier_catalog.size), status);
      RETURN;
    IFEND;

    found := FALSE;

    WHILE NOT found DO
      NEXT job_status_record_p IN summary_file_seq_p;
      IF job_status_record_p = NIL THEN
        osp$set_status_abnormal ('RA', rae$unexpected_eof_summary_file, rac$summary_file_name, status);
        osp$append_status_file (osc$status_parameter_delimiter, installation_identifier_catalog.
              path (1, installation_identifier_catalog.size), status);
        RETURN;
      IFEND;

      IF job_status_record_p^.job_identifier = installation_control_record.job_identifier THEN
        installation_control_record.job_status_record_p := job_status_record_p;
        found := TRUE;
      IFEND;
    WHILEND;

  PROCEND open_processing_summary_file;
MODEND ram$perform_installation_steps;
