# Copyright 2023 Google LLC. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Code strings for kfp scripts."""

# pylint: disable=anomalous-backslash-in-string
# pylint: disable=line-too-long

import re

from AutoMLOps.utils.utils import (
    execute_process,
    get_components_list,
    read_file,
    read_yaml_file
)
from AutoMLOps.utils.constants import (
    GENERATED_LICENSE,
    NEWLINE,
    LEFT_BRACKET,
    RIGHT_BRACKET,
    GENERATED_COMPONENT_BASE,
    GENERATED_PARAMETER_VALUES_PATH,
    GENERATED_PIPELINE_JOB_SPEC_PATH
)

class KfpScripts():
    """Generates files related to running kubeflow pipelines."""
    def __init__(self,
                 af_registry_location: str,
                 af_registry_name: str,
                 cb_trigger_location: str,
                 cb_trigger_name: str,
                 cloud_run_location: str,
                 cloud_run_name: str,
                 cloud_tasks_queue_location: str,
                 cloud_tasks_queue_name: str,
                 csr_branch_name: str,
                 csr_name: str,
                 default_image: str,
                 gs_bucket_location: str,
                 gs_bucket_name: str,
                 pipeline_runner_sa: str,
                 project_id: str,
                 run_local: str,
                 schedule_location: str,
                 schedule_name: str,
                 schedule_pattern: str,
                 base_dir: str,
                 vpc_connector: str):
        """Constructs scripts for resource deployment and running Kubeflow pipelines.

        Args:
            af_registry_location: Region of the Artifact Registry.
            af_registry_name: Artifact Registry name where components are stored.
            cb_trigger_location: The location of the cloudbuild trigger.
            cb_trigger_name: The name of the cloudbuild trigger.
            cloud_run_location: The location of the cloud runner service.
            cloud_run_name: The name of the cloud runner service.
            cloud_tasks_queue_location: The location of the cloud tasks queue.
            cloud_tasks_queue_name: The name of the cloud tasks queue.
            csr_branch_name: The name of the csr branch to push to to trigger cb job.
            csr_name: The name of the cloud source repo to use.
            default_image: The image to use in the dockerfile.
            gs_bucket_location: Region of the GS bucket.
            gs_bucket_name: GS bucket name where pipeline run metadata is stored.
            pipeline_runner_sa: Service Account to runner PipelineJobs.
            project_id: The project ID.
            run_local: Flag that determines whether to use Cloud Run CI/CD.
            schedule_location: The location of the scheduler resource.
            schedule_name: The name of the scheduler resource.
            schedule_pattern: Cron formatted value used to create a Scheduled retrain job.
            base_dir: Top directory name.
            vpc_connector: The name of the vpc connector to use.
        """
        # Set passed variables as hidden attributes
        self.__base_dir = base_dir
        self.__run_local = run_local

        # Parse defaults file for hidden class attributes
        self.__af_registry_name = af_registry_name
        self.__af_registry_location = af_registry_location
        self.__project_id = project_id
        self.__gs_bucket_name = gs_bucket_name
        self.__gs_bucket_location = gs_bucket_location
        self.__pipeline_region = gs_bucket_location
        self.__pipeline_runner_service_account = pipeline_runner_sa
        self.__cloud_source_repository = csr_name
        self.__cloud_source_repository_branch = csr_branch_name
        self.__cb_trigger_location = cb_trigger_location
        self.__cb_trigger_name = cb_trigger_name
        self.__cloud_tasks_queue_location = cloud_tasks_queue_location
        self.__cloud_tasks_queue_name = cloud_tasks_queue_name
        self.__vpc_connector = vpc_connector
        self.__cloud_run_name = cloud_run_name
        self.__cloud_run_location = cloud_run_location
        self.__cloud_schedule_location = schedule_location
        self.__cloud_schedule_name = schedule_name
        self.__cloud_schedule_pattern = schedule_pattern
        self.__default_image = default_image

        # Set generated scripts as public attributes
        self.build_pipeline_spec = self._build_pipeline_spec()
        self.build_components = self._build_components()
        self.run_pipeline = self._run_pipeline()
        self.run_all = self._run_all()
        self.create_resources_script = self._create_resources_script()
        self.create_cloudbuild_config = self._create_cloudbuild_config()
        self.dockerfile = self._create_dockerfile()
        self.defaults = self._create_default_config()
        self.requirements = self._create_requirements()

    def _build_pipeline_spec(self):
        """Builds content of a shell script to build the pipeline specs.

        Returns:
            str: Text of script to build pipeline specs.
        """
        return (
            '#!/bin/bash\n' + GENERATED_LICENSE +
            '# Builds the pipeline specs\n'
            f'# This script should run from the {self.__base_dir} directory\n'
            '# Change directory in case this is not the script root.\n'
            '\n'
            'CONFIG_FILE=configs/defaults.yaml\n'
            '\n'
            'python3 -m pipelines.pipeline --config $CONFIG_FILE\n')

    def _build_components(self):
        """Builds content of a shell script to build components.

        Returns:
            str: Text of script to build components.
        """
        return (
            '#!/bin/bash\n' + GENERATED_LICENSE +
            '# Submits a Cloud Build job that builds and deploys the components\n'
            f'# This script should run from the {self.__base_dir} directory\n'
            '# Change directory in case this is not the script root.\n'
            '\n'
            'gcloud builds submit .. --config cloudbuild.yaml --timeout=3600\n')

    def _run_pipeline(self):
        """Builds content of a shell script to run the pipeline.

        Returns:
            str: Text of script to run pipeline.
        """
        return (
            '#!/bin/bash\n' + GENERATED_LICENSE +
            '# Submits the PipelineJob to Vertex AI\n'
            f'# This script should run from the {self.__base_dir} directory\n'
            '# Change directory in case this is not the script root.\n'
            '\n'
            'CONFIG_FILE=configs/defaults.yaml\n'
            '\n'
            'python3 -m pipelines.pipeline_runner --config $CONFIG_FILE\n')

    def _run_all(self):
        """Builds content of a shell script to run all other shell scripts.

        Returns:
            str: Text of script to run all other scripts.
        """
        return (
            '#!/bin/bash\n' + GENERATED_LICENSE +
            '# Builds components, pipeline specs, and submits the PipelineJob.\n'
            f'# This script should run from the {self.__base_dir} directory\n'
            '# Change directory in case this is not the script root.\n'
            '\n'
            '''GREEN='\033[0;32m'\n'''
            '''NC='\033[0m'\n'''
            '\n'
            'echo -e "${GREEN} BUILDING COMPONENTS ${NC}"\n'
            'gcloud builds submit .. --config cloudbuild.yaml --timeout=3600\n'
            '\n'
            'echo -e "${GREEN} BUILDING PIPELINE SPEC ${NC}"\n'
            './scripts/build_pipeline_spec.sh\n'
            '\n'
            'echo -e "${GREEN} RUNNING PIPELINE JOB ${NC}"\n'
            './scripts/run_pipeline.sh\n')

    def _create_resources_script(self):
        """Builds content of create_resources.sh, which creates a specified
        artifact registry and gs bucket if they do not already exist. Also creates
        a service account to run Vertex AI Pipelines.

        Returns:
            str: Text to be written to create_resources.sh
        """
        create_resources_script = (
            '#!/bin/bash\n' + GENERATED_LICENSE +
            f'# This script will create an artifact registry and gs bucket if they do not already exist.\n'
            f'\n'
            f'''GREEN='\033[0;32m'\n'''
            f'''NC='\033[0m'\n'''
            f'''AF_REGISTRY_NAME={self.__af_registry_name}\n'''
            f'''AF_REGISTRY_LOCATION={self.__af_registry_location}\n'''
            f'''PROJECT_ID={self.__project_id}\n'''
            f'''PROJECT_NUMBER=`gcloud projects describe {self.__project_id} --format 'value(projectNumber)'`\n'''
            f'''BUCKET_NAME={self.__gs_bucket_name}\n'''
            f'''BUCKET_LOCATION={self.__pipeline_region}\n'''
            f'''SERVICE_ACCOUNT_NAME={self.__pipeline_runner_service_account.split('@')[0]}\n'''
            f'''SERVICE_ACCOUNT_FULL={self.__pipeline_runner_service_account}\n'''
            f'''CLOUD_SOURCE_REPO={self.__cloud_source_repository}\n'''
            f'''CLOUD_SOURCE_REPO_BRANCH={self.__cloud_source_repository_branch}\n'''
            f'''CB_TRIGGER_LOCATION={self.__cb_trigger_location}\n'''
            f'''CB_TRIGGER_NAME={self.__cb_trigger_name}\n'''
            f'''CLOUD_TASKS_QUEUE_LOCATION={self.__cloud_tasks_queue_location}\n'''
            f'''CLOUD_TASKS_QUEUE_NAME={self.__cloud_tasks_queue_name}\n'''
            f'\n'
            f'echo -e "$GREEN Updating required API services in project $PROJECT_ID $NC"\n'
            f'gcloud services enable cloudresourcemanager.googleapis.com \{NEWLINE}'
            f'  aiplatform.googleapis.com \{NEWLINE}'
            f'  artifactregistry.googleapis.com \{NEWLINE}'
            f'  cloudbuild.googleapis.com \{NEWLINE}'
            f'  cloudscheduler.googleapis.com \{NEWLINE}'
            f'  cloudtasks.googleapis.com \{NEWLINE}'
            f'  compute.googleapis.com \{NEWLINE}'
            f'  iam.googleapis.com \{NEWLINE}'
            f'  iamcredentials.googleapis.com \{NEWLINE}'
            f'  ml.googleapis.com \{NEWLINE}'
            f'  run.googleapis.com \{NEWLINE}'
            f'  storage.googleapis.com \{NEWLINE}'
            f'  sourcerepo.googleapis.com\n'
            f'\n'
            f'echo -e "$GREEN Checking for Artifact Registry: $AF_REGISTRY_NAME in project $PROJECT_ID $NC"\n'
            f'if ! (gcloud artifacts repositories list --project="$PROJECT_ID" --location=$AF_REGISTRY_LOCATION | grep -E "(^|[[:blank:]])$AF_REGISTRY_NAME($|[[:blank:]])"); then\n'
            f'\n'
            f'  echo "Creating Artifact Registry: ${LEFT_BRACKET}AF_REGISTRY_NAME{RIGHT_BRACKET} in project $PROJECT_ID"\n'
            f'  gcloud artifacts repositories create "$AF_REGISTRY_NAME" \{NEWLINE}'
            f'    --repository-format=docker \{NEWLINE}'
            f'    --location=$AF_REGISTRY_LOCATION \{NEWLINE}'
            f'    --project="$PROJECT_ID" \{NEWLINE}'
            f'    --description="Artifact Registry ${LEFT_BRACKET}AF_REGISTRY_NAME{RIGHT_BRACKET} in ${LEFT_BRACKET}AF_REGISTRY_LOCATION{RIGHT_BRACKET}." \n'
            f'\n'
            f'else\n'
            f'\n'
            f'  echo "Artifact Registry: ${LEFT_BRACKET}AF_REGISTRY_NAME{RIGHT_BRACKET} already exists in project $PROJECT_ID"\n'
            f'\n'
            f'fi\n'
            f'\n'
            f'\n'
            f'echo -e "$GREEN Checking for GS Bucket: $BUCKET_NAME in project $PROJECT_ID $NC"\n'
            f'if !(gsutil ls -b gs://$BUCKET_NAME | grep --fixed-strings "$BUCKET_NAME"); then\n'
            f'\n'
            f'  echo "Creating GS Bucket: ${LEFT_BRACKET}BUCKET_NAME{RIGHT_BRACKET} in project $PROJECT_ID"\n'
            f'  gsutil mb -l ${LEFT_BRACKET}BUCKET_LOCATION{RIGHT_BRACKET} gs://$BUCKET_NAME\n'
            f'\n'
            f'else\n'
            f'\n'
            f'  echo "GS Bucket: ${LEFT_BRACKET}BUCKET_NAME{RIGHT_BRACKET} already exists in project $PROJECT_ID"\n'
            f'\n'
            f'fi\n'
            f'\n'
            f'echo -e "$GREEN Checking for Service Account: $SERVICE_ACCOUNT_NAME in project $PROJECT_ID $NC"\n'
            f'if ! (gcloud iam service-accounts list --project="$PROJECT_ID" | grep -E "(^|[[:blank:]])$SERVICE_ACCOUNT_FULL($|[[:blank:]])"); then\n'
            f'\n'
            f'  echo "Creating Service Account: ${LEFT_BRACKET}SERVICE_ACCOUNT_NAME{RIGHT_BRACKET} in project $PROJECT_ID"\n'
            f'  gcloud iam service-accounts create $SERVICE_ACCOUNT_NAME \{NEWLINE}'
            f'      --description="For submitting PipelineJobs" \{NEWLINE}'
            f'      --display-name="Pipeline Runner Service Account"\n'
            f'else\n'
            f'\n'
            f'  echo "Service Account: ${LEFT_BRACKET}SERVICE_ACCOUNT_NAME{RIGHT_BRACKET} already exists in project $PROJECT_ID"\n'
            f'\n'
            f'fi\n'
            f'\n'
            f'echo -e "$GREEN Updating required IAM roles in project $PROJECT_ID $NC"\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'    --role="roles/aiplatform.user" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'    --role="roles/artifactregistry.reader" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'    --role="roles/bigquery.user" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'   --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'   --role="roles/bigquery.dataEditor" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'    --role="roles/iam.serviceAccountUser" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'    --role="roles/storage.admin" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$SERVICE_ACCOUNT_FULL" \{NEWLINE}'
            f'    --role="roles/run.admin" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \{NEWLINE}'
            f'    --role="roles/run.admin" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \{NEWLINE}'
            f'    --role="roles/iam.serviceAccountUser" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \{NEWLINE}'
            f'    --role="roles/cloudtasks.enqueuer" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'gcloud projects add-iam-policy-binding $PROJECT_ID \{NEWLINE}'
            f'    --member="serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com" \{NEWLINE}'
            f'    --role="roles/cloudscheduler.admin" \{NEWLINE}'
            f'    --no-user-output-enabled\n'
            f'\n'
            f'echo -e "$GREEN Checking for Cloud Source Repository: $CLOUD_SOURCE_REPO in project $PROJECT_ID $NC"\n'
            f'if ! (gcloud source repos list --project="$PROJECT_ID" | grep -E "(^|[[:blank:]])$CLOUD_SOURCE_REPO($|[[:blank:]])"); then\n'
            f'\n'
            f'  echo "Creating Cloud Source Repository: ${LEFT_BRACKET}CLOUD_SOURCE_REPO{RIGHT_BRACKET} in project $PROJECT_ID"\n'
            f'  gcloud source repos create $CLOUD_SOURCE_REPO\n'
            f'\n'
            f'else\n'
            f'\n'
            f'  echo "Cloud Source Repository: ${LEFT_BRACKET}CLOUD_SOURCE_REPO{RIGHT_BRACKET} already exists in project $PROJECT_ID"\n'
            f'\n'
            f'fi\n')

        if not self.__run_local:
            create_resources_script += (
                f'\n'
                f'# Create cloud tasks queue\n'
                f'echo -e "$GREEN Checking for Cloud Tasks Queue: $CLOUD_TASKS_QUEUE_NAME in project $PROJECT_ID $NC"\n'
                f'if ! (gcloud tasks queues list --location $CLOUD_TASKS_QUEUE_LOCATION | grep -E "(^|[[:blank:]])$CLOUD_TASKS_QUEUE_NAME($|[[:blank:]])"); then\n'
                f'\n'
                f'  echo "Creating Cloud Tasks Queue: ${LEFT_BRACKET}CLOUD_TASKS_QUEUE_NAME{RIGHT_BRACKET} in project $PROJECT_ID"\n'
                f'  gcloud tasks queues create $CLOUD_TASKS_QUEUE_NAME \{NEWLINE}'
                f'  --location=$CLOUD_TASKS_QUEUE_LOCATION\n'
                f'\n'
                f'else\n'
                f'\n'
                f'  echo "Cloud Tasks Queue: ${LEFT_BRACKET}CLOUD_TASKS_QUEUE_NAME{RIGHT_BRACKET} already exists in project $PROJECT_ID"\n'
                f'\n'
                f'fi\n'
                f'\n'
                f'# Create cloud build trigger\n'
                f'echo -e "$GREEN Checking for Cloudbuild Trigger: $CB_TRIGGER_NAME in project $PROJECT_ID $NC"\n'
                f'if ! (gcloud beta builds triggers list --project="$PROJECT_ID" --region="$CB_TRIGGER_LOCATION" | grep -E "(^|[[:blank:]])name: $CB_TRIGGER_NAME($|[[:blank:]])"); then\n'
                f'\n'
                f'  echo "Creating Cloudbuild Trigger on branch $CLOUD_SOURCE_REPO_BRANCH in project $PROJECT_ID for repo ${LEFT_BRACKET}CLOUD_SOURCE_REPO{RIGHT_BRACKET}"\n'
                f'  gcloud beta builds triggers create cloud-source-repositories \{NEWLINE}'
                f'  --region=$CB_TRIGGER_LOCATION \{NEWLINE}'
                f'  --name=$CB_TRIGGER_NAME \{NEWLINE}'
                f'  --repo=$CLOUD_SOURCE_REPO \{NEWLINE}'
                f'  --branch-pattern="$CLOUD_SOURCE_REPO_BRANCH" \{NEWLINE}'
                f'  --build-config={self.__base_dir}cloudbuild.yaml\n'
                f'\n'
                f'else\n'
                f'\n'
                f'  echo "Cloudbuild Trigger already exists in project $PROJECT_ID for repo ${LEFT_BRACKET}CLOUD_SOURCE_REPO{RIGHT_BRACKET}"\n'
                f'\n'
                f'fi\n')

        return create_resources_script

    def _create_cloudbuild_config(self):
        """Builds the content of cloudbuild.yaml.

        Args:
            str: Text content of cloudbuild.yaml.
        """
        vpc_connector_tail = ''
        if self.__vpc_connector != 'No VPC Specified':
            vpc_connector_tail = (
                f'\n'
                f'           "--ingress", "internal",\n'
                f'           "--vpc-connector", "{self.__vpc_connector}",\n'
                f'           "--vpc-egress", "all-traffic"')
        vpc_connector_tail += ']\n'

        cloudbuild_comp_config = (
            GENERATED_LICENSE +
            f'steps:\n'
            f'# ==============================================================================\n'
            f'# BUILD CUSTOM IMAGES\n'
            f'# ==============================================================================\n'
            f'\n'
            f'''  # build the component_base image\n'''
            f'''  - name: "gcr.io/cloud-builders/docker"\n'''
            f'''    args: [ "build", "-t", "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/components/component_base:latest", "." ]\n'''
            f'''    dir: "{self.__base_dir}components/component_base"\n'''
            f'''    id: "build_component_base"\n'''
            f'''    waitFor: ["-"]\n'''
            f'\n'
            f'''  # build the run_pipeline image\n'''
            f'''  - name: 'gcr.io/cloud-builders/docker'\n'''
            f'''    args: [ "build", "-t", "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/run_pipeline:latest", "-f", "cloud_run/run_pipeline/Dockerfile", "." ]\n'''
            f'''    dir: "{self.__base_dir}"\n'''
            f'''    id: "build_pipeline_runner_svc"\n'''
            f'''    waitFor: ['build_component_base']\n''')

        cloudbuild_cloudrun_config = (
            f'\n'
            f'# ==============================================================================\n'
            f'# PUSH & DEPLOY CUSTOM IMAGES\n'
            f'# ==============================================================================\n'
            f'\n'
            f'''  # push the component_base image\n'''
            f'''  - name: "gcr.io/cloud-builders/docker"\n'''
            f'''    args: ["push", "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/components/component_base:latest"]\n'''
            f'''    dir: "{self.__base_dir}components/component_base"\n'''
            f'''    id: "push_component_base"\n'''
            f'''    waitFor: ["build_pipeline_runner_svc"]\n'''
            f'\n'
            f'''  # push the run_pipeline image\n'''
            f'''  - name: "gcr.io/cloud-builders/docker"\n'''
            f'''    args: ["push", "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/run_pipeline:latest"]\n'''
            f'''    dir: "{self.__base_dir}"\n'''
            f'''    id: "push_pipeline_runner_svc"\n'''
            f'''    waitFor: ["push_component_base"]\n'''
            f'\n'
            f'''  # deploy the cloud run service\n'''
            f'''  - name: "gcr.io/google.com/cloudsdktool/cloud-sdk"\n'''
            f'''    entrypoint: gcloud\n'''
            f'''    args: ["run",\n'''
            f'''           "deploy",\n'''
            f'''           "{self.__cloud_run_name}",\n'''
            f'''           "--image",\n'''
            f'''           "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/run_pipeline:latest",\n'''
            f'''           "--region",\n'''
            f'''           "{self.__cloud_run_location}",\n'''
            f'''           "--service-account",\n'''
            f'''           "{self.__pipeline_runner_service_account}",{vpc_connector_tail}'''
            f'''    id: "deploy_pipeline_runner_svc"\n'''
            f'''    waitFor: ["push_pipeline_runner_svc"]\n'''
            f'\n'
            f'''  # Copy runtime parameters\n'''
            f'''  - name: 'gcr.io/cloud-builders/gcloud'\n'''
            f'''    entrypoint: bash\n'''
            f'''    args:\n'''
            f'''      - '-e'\n'''
            f'''      - '-c'\n'''
            f'''      - |\n'''
            f'''        cp -r {self.__base_dir}cloud_run/queueing_svc .\n'''
            f'''    id: "setup_queueing_svc"\n'''
            f'''    waitFor: ["deploy_pipeline_runner_svc"]\n'''
            f'\n'
            f'''  # Install dependencies\n'''
            f'''  - name: python\n'''
            f'''    entrypoint: pip\n'''
            f'''    args: ["install", "-r", "queueing_svc/requirements.txt", "--user"]\n'''
            f'''    id: "install_queueing_svc_deps"\n'''
            f'''    waitFor: ["setup_queueing_svc"]\n'''
            f'\n'
            f'''  # Submit to queue\n'''
            f'''  - name: python\n'''
            f'''    entrypoint: python\n'''
            f'''    args: ["queueing_svc/main.py", "--setting", "queue_job"]\n'''
            f'''    id: "submit_job_to_queue"\n'''
            f'''    waitFor: ["install_queueing_svc_deps"]\n''')

        cloudbuild_scheduler_config = (
            '\n'
            '''  # Create Scheduler Job\n'''
            '''  - name: python\n'''
            '''    entrypoint: python\n'''
            '''    args: ["queueing_svc/main.py", "--setting", "schedule_job"]\n'''
            '''    id: "schedule_job"\n'''
            '''    waitFor: ["submit_job_to_queue"]\n''')

        custom_comp_image = (
            f'\n'
            f'images:\n'
            f'''  # custom component images\n'''
            f'''  - "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/components/component_base:latest"\n''')

        cloudrun_image = (
            f'''  # Cloud Run image\n'''
            f'''  - "{self.__af_registry_location}-docker.pkg.dev/{self.__project_id}/{self.__af_registry_name}/run_pipeline:latest"\n''')

        if self.__run_local:
            cb_file_contents = cloudbuild_comp_config + custom_comp_image
        else:
            if self.__cloud_schedule_pattern == 'No Schedule Specified':
                cb_file_contents = cloudbuild_comp_config + cloudbuild_cloudrun_config + custom_comp_image + cloudrun_image
            else:
                cb_file_contents = cloudbuild_comp_config + cloudbuild_cloudrun_config + cloudbuild_scheduler_config + custom_comp_image + cloudrun_image

        return cb_file_contents

    def _create_dockerfile(self):
        """Creates the content of a Dockerfile to be written to the component_base directory.

        Args:
            default_image: Default image used for this process.

        Returns:
            str: Text content of dockerfile.
        """
        return (
            GENERATED_LICENSE +
            f'FROM {self.__default_image}\n'
            f'RUN python -m pip install --upgrade pip\n'
            f'COPY requirements.txt .\n'
            f'RUN python -m pip install -r \ \n'
            f'    requirements.txt --quiet --no-cache-dir \ \n'
            f'    && rm -f requirements.txt\n'
            f'COPY ./src /pipelines/component/src\n'
            f'ENTRYPOINT ["/bin/bash"]\n')

    def _create_default_config(self):
        """Creates default defaults.yaml file contents. This defaults
        file is used by subsequent functions and by the pipeline
        files themselves.

        Returns:
            str: Defaults yaml file content
        """
        return (
            GENERATED_LICENSE +
            f'# These values are descriptive only - do not change.\n'
            f'# Rerun AutoMLOps.generate() to change these values.\n'
            f'gcp:\n'
            f'  af_registry_location: {self.__af_registry_location}\n'
            f'  af_registry_name: {self.__af_registry_name}\n'
            f'  cb_trigger_location: {self.__cb_trigger_location}\n'
            f'  cb_trigger_name: {self.__cb_trigger_name}\n'
            f'  cloud_run_location: {self.__cloud_run_location}\n'
            f'  cloud_run_name: {self.__cloud_run_name}\n'
            f'  cloud_tasks_queue_location: {self.__cloud_tasks_queue_location}\n'
            f'  cloud_tasks_queue_name: {self.__cloud_tasks_queue_name}\n'
            f'  cloud_schedule_location: {self.__cloud_schedule_location}\n'
            f'  cloud_schedule_name: {self.__cloud_schedule_name}\n'
            f'  cloud_schedule_pattern: {self.__cloud_schedule_pattern}\n'
            f'  cloud_source_repository: {self.__cloud_source_repository}\n'
            f'  cloud_source_repository_branch: {self.__cloud_source_repository_branch}\n'
            f'  gs_bucket_name: {self.__gs_bucket_name}\n'
            f'  pipeline_runner_service_account: {self.__pipeline_runner_service_account}\n'
            f'  project_id: {self.__project_id}\n'
            f'  vpc_connector: {self.__vpc_connector}\n'
            f'\n'
            f'pipelines:\n'
            f'  parameter_values_path: {GENERATED_PARAMETER_VALUES_PATH}\n'
            f'  pipeline_component_directory: components\n'
            f'  pipeline_job_spec_path: {GENERATED_PIPELINE_JOB_SPEC_PATH}\n'
            f'  pipeline_region: {self.__gs_bucket_location}\n'
            f'  pipeline_storage_path: gs://{self.__gs_bucket_name}/pipeline_root\n')

    def _create_requirements(self):
        """Writes a requirements.txt to the component_base directory.
        Infers pip requirements from the python srcfiles using 
        pipreqs. Takes user-inputted requirements, and addes some 
        default gcp packages as well as packages that are often missing
        in setup.py files (e.g db_types, pyarrow, gcsfs, fsspec).
        """
        reqs_filename = f'{GENERATED_COMPONENT_BASE}/requirements.txt'
        default_gcp_reqs = [
            'google-cloud-aiplatform',
            'google-cloud-appengine-logging',
            'google-cloud-audit-log',
            'google-cloud-bigquery',
            'google-cloud-bigquery-storage',
            'google-cloud-bigtable',
            'google-cloud-core',
            'google-cloud-dataproc',
            'google-cloud-datastore',
            'google-cloud-dlp',
            'google-cloud-firestore',
            'google-cloud-kms',
            'google-cloud-language',
            'google-cloud-logging',
            'google-cloud-monitoring',
            'google-cloud-notebooks',
            'google-cloud-pipeline-components',
            'google-cloud-pubsub',
            'google-cloud-pubsublite',
            'google-cloud-recommendations-ai',
            'google-cloud-resource-manager',
            'google-cloud-scheduler',
            'google-cloud-spanner',
            'google-cloud-speech',
            'google-cloud-storage',
            'google-cloud-tasks',
            'google-cloud-translate',
            'google-cloud-videointelligence',
            'google-cloud-vision',
            'db_dtypes',
            'pyarrow',
            'gcsfs',
            'fsspec']
        # Infer reqs using pipreqs
        execute_process(f'python3 -m pipreqs.pipreqs {GENERATED_COMPONENT_BASE} --mode no-pin --force', to_null=False)
        pipreqs = read_file(reqs_filename).splitlines()
        # Get user-inputted requirements from .tmpfiles dir
        user_inp_reqs = []
        components_path_list = get_components_list()
        for component_path in components_path_list:
            component_spec = read_yaml_file(component_path)
            reqs = component_spec['implementation']['container']['command'][2]
            formatted_reqs = re.findall('\'([^\']*)\'', reqs)
            user_inp_reqs.extend(formatted_reqs)
        # Remove duplicates
        set_of_requirements = set(user_inp_reqs) if user_inp_reqs else set(pipreqs + default_gcp_reqs)
        reqs_str = ''.join(r+'\n' for r in sorted(set_of_requirements))
        return reqs_str
