
    C0                        d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlZddlZddl	Z	ddl
mZ ddlmZ ddlmZ dd	lmZ dd
lmZ dZdZdZdZdZdZd Zd ZddZ	 	 	 	 	 	 ddZddZd Z	 	 	 	 	 ddZ 	 	 	 	 	 	 ddZ!y)z;Functions required to interact with Docker to build images.    )absolute_import)division)unicode_literalsN)errors)
local_util)utils)log)shlex_quotez/homez/usr/app
./setup.py./requirements.txtzcloudai-autogenerated   c                 6    d}t        j                  ||       duS )z<Checks whether the image is pre-built by Vertex AI training.zY^(us|europe|asia)-docker.pkg.dev/vertex-ai/training/(tf|scikit-learn|pytorch|xgboost)-.+$N)re	fullmatch)
image_nameprebuilt_image_name_regexs     1lib/googlecloudsdk/command_lib/ai/docker/build.py_IsVertexTrainingPrebuiltImager   )   s$     H 
/	<D	HH    c                     | rdS dS )znReturns a Dockerfile entry that removes `sitecustomize` if it's Vertex AI Training pre-built container images.zRUN rm -rf /var/sitecustomize  )is_prebuilt_images    r   _SitecustomizeRemovalEntryr   1   s    ,=	(E2Er   c                     dj                  t        j                  | |g            }|2dj                  |j	                  d            }dj                  ||      S |S )zReturns a Dockerfile entry that copies a file from host to container.

  Args:
    from_path: (str) Path of the source in host.
    to_path: (str) Path to the destination in the container.
    comment: (str) A comment explaining the copy operation.
  zCOPY {}
z
# 
z# {}
{})formatjsondumpsjoinsplit)	from_pathto_pathcommentcmdformatted_comments        r   _GenerateCopyCommandr'   6   sY     	4::y'&:;<#GMM$$78.44	*r   c                 x   d}| rdnd}|4|t        j                  dj                  t        |dd      |            z  }|4|t        j                  dj                  t        |d	d
      |            z  }|b|D ]]  }t        j
                  j                  |      }	|t        j                  dj                  t        ||	      |t        |	                  z  }_ |8|D ]3  }
|t        j                  dj                  |t        |
                  z  }5 |%|D ]   }|dj                  t        ||            z  }" |S )a2  Returns the Dockerfile entries required to install dependencies.

  Args:
    is_prebuilt_image: (bool) Whether the base image is pre-built and provided
      by Vertex AI.
    requirements_path: (str) Path that points to a requirements.txt file
    setup_path: (str) Path that points to a setup.py
    extra_requirements: (List[str]) Required dependencies to be installed from
      remote resource archives.
    extra_packages: (List[str]) User custom dependency packages to install.
    extra_dirs: (List[str]) Directories other than the work_dir required.
  r   pip3pipz<
        {}
        RUN {} install --no-cache-dir .
        r   z:Found setup.py file, thus copy it to the docker container.r$   zP
        {}
        RUN {} install --no-cache-dir -r ./requirements.txt
        r   z:Found requirements.txt file, thus to the docker container.z=
        {}
        RUN {} install --no-cache-dir {}
        z<
        RUN {} install --no-cache-dir --upgrade {}
        
{}
)textwrapdedentr   r'   ospathbasenamer
   )r   requirements_path
setup_pathextra_requirementsextra_packages
extra_dirsretpip_versionextrapackage_namerequirement	directorys               r   _DependencyEntriesr=   G   si   $ 	#++8??  F T  C "8??  F !$T  C WW%%e,l	X__  F 5{%'( (c   #)	X__ F;K 89; ;c *
 		X__1)YGHHc   
*r   c                 B   |rdnd}| j                   #t        j                  |d| j                   g      }nZt        j                  j                  | j                        \  }}|dk(  r|gndg}t        j                  || j                  gz         }dj                  |      S )a@  Generates dockerfile entry to set the container entrypoint.

  Args:
    package: (Package) Represents the main application copied to the container.
    is_prebuilt_image: (bool) Whether the base image is pre-built and provided
      by Vertex AI.

  Returns:
    A string with Dockerfile directives to set ENTRYPOINT
  python3pythonz-mz.pyz	/bin/bashz
ENTRYPOINT {})python_moduler   r   r/   r0   splitextscriptr   )packager   python_commandexec_str_ext
executables          r   _GenerateEntrypointrJ      s     !29x. &zz>41F1FGHHWWgnn-FAs%(E\.!}Jzz*'778H		!	!(	++r   c                     t         j                  j                  | j                        xs d}t	        ||d      }dj                  |      S )at  Returns the Dockerfile entries required to append at the end before entrypoint.

  Including:
  - copy the parent directory of the main executable into a docker container.
  - inject an entrypoint that executes a script or python module inside that
    directory.

  Args:
    package: (Package) Represents the main application copied to and run in the
      container.
  .z4Copy the source directory into the docker container.r+   r,   )r/   r0   dirnamerC   r'   r   )rD   
parent_dir	copy_codes      r   _PreparePackageEntryrP      sD     www~~.5#*"DF)
 
	##r   c	           	         t        |       }	t        j                  dj                  | t	        |      t	        |                  }
|
t        |	      z  }
|
t        |	|||||      z  }
|
t        |      z  }
|
t        ||	      z  }
|
S )ak  Generates a Dockerfile for building an image.

  It builds on a specified base image to create a container that:
  - installs any dependency specified in a requirements.txt or a setup.py file,
  and any specified dependency packages existing locally or found from PyPI
  - copies all source needed by the main module, and potentially injects an
  entrypoint that, on run, will run that main module

  Args:
    base_image: (str) ID or name of the base image to initialize the build
      stage.
    main_package: (Package) Represents the main application to execute.
    container_workdir: (str) Working directory in the container.
    container_home: (str) $HOME directory in the container.
    requirements_path: (str) Rath of a requirements.txt file.
    setup_path: (str) Path of a setup.py file
    extra_requirements: (List[str]) Required dependencies to install from PyPI.
    extra_packages: (List[str]) User custom dependency packages to install.
    extra_dirs: (List[str]) Directories other than the work_dir required to be
      in the container.

  Returns:
    A string that represents the content of a Dockerfile.
  ab  
      FROM {base_image}
      # The directory is created by root. This sets permissions so that any user can
      # access the folder.
      RUN mkdir -m 777 -p {workdir} {container_home}
      WORKDIR {workdir}
      ENV HOME={container_home}

      # Keeps Python from generating .pyc files in the container
      ENV PYTHONDONTWRITEBYTECODE=1
      )
base_imageworkdircontainer_home)r2   r3   r4   r5   r6   )	r   r-   r.   r   r
   r   r=   rP   rJ   )rR   main_packagecontainer_workdirrT   r2   r3   r4   r5   r6   is_training_prebuilt_image_base
dockerfiles              r   _MakeDockerfilerY      s    B %C:$N! 
 
 &/0$^4  67* *+JKK*"%)+# * $\22*#L$CE E* 
r   c
                    d|g}|	rdgng }ddg|z   |z   dd|gz   }t         j                  j                  t         j                  j                  |t                    }|rt        nd}t         j                  j                  t         j                  j                  |t
                    }|rt
        nd}|xs t        }|xs t        }t        j                  |j                  t         j                  t        j                        |j                  t         j                  t        j                        |      }t        | f|||||||d	|
}d
j                  |      }t        j                  dj!                  |             t#        j$                  ||      }|dk(  rt        j&                  |||      S t)        j*                  dj!                  ||            }t-        j.                  |||      )a  Builds a Docker image.

  Generates a Dockerfile and passes it to `docker build` via stdin.
  All output from the `docker build` process prints to stdout.

  Args:
    base_image: (str) ID or name of the base image to initialize the build
      stage.
    host_workdir: (str) A path indicating where all the required sources
      locates.
    main_script: (str) A string that identifies the executable script under the
      working directory.
    output_image_name: (str) Name of the built image.
    python_module: (str) Represents the executable main_script in form of a
      python module, if applicable.
    requirements: (List[str]) Required dependencies to install from PyPI.
    extra_packages: (List[str]) User custom dependency packages to install.
    container_workdir: (str) Working directory in the container.
    container_home: (str) the $HOME directory in the container.
    no_cache: (bool) Do not use cache when building the image.
    **kwargs: Other arguments to pass to underlying method that generates the
      Dockerfile.

  Returns:
    A Image class that contains info of the built image.

  Raises:
    DockerError: An error occurred when executing `docker build`
  z-tz
--no-cachedockerbuildz--rmz-f-N)rC   package_pathrA   )rU   rT   rV   r2   r3   r4   r5    zRunning command: {})	input_strr   zN
        Docker failed with error code {code}.
        Command: {cmd}
        )coder%   )r/   r0   isfiler    _DEFAULT_SETUP_PATH_DEFAULT_REQUIREMENTS_PATH_DEFAULT_HOME_DEFAULT_WORKDIRr   Packagereplacesep	posixpathrY   r	   infor   r   ExecuteCommandImager-   r.   r   DockerError)rR   host_workdirmain_scriptoutput_image_namerA   requirementsr5   rV   rT   no_cachekwargstag_options
cache_argscommandhas_setup_pyr3   has_requirements_txtr2   home_dirwork_dirrU   rX   joined_commandreturn_code	error_msgs                            r   
BuildImager~      s   R ()+!)~r*w (),2E<+HI' \;N OP,&2"*ggll<!;<>4H0d,}(2"2(   7''	>!#,
 	 )%#	 		* 88G$.(( ''78))'ZH+A;;((H== ! FF8:I 

Y
==r   )N)FNNNNN)F)NNNNN)NNNNNT)"__doc__
__future__r   r   r   r   r/   ri   r   r-   googlecloudsdk.command_lib.air   )googlecloudsdk.command_lib.ai.custom_jobsr   $googlecloudsdk.command_lib.ai.dockerr   googlecloudsdk.corer	   	six.movesr
   rd   re   rb   rc   _AUTONAME_PREFIX_AUTOGENERATED_TAG_LENGTHr   r   r'   r=   rJ   rP   rY   r~   r   r   r   <module>r      s    B &  '  	  	  0 @ 6 # ! " 1 *  IF
" */)-"&*.&*"&?D,6$4 '+#'+#'#@N " "!%"U>r   