
    $                        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dlmZ ddlmZ ddlZddlmZ ddgZd Zd Zd ZddZd Zd Z G d de       Z!d Z"d Z#d Z$y)zEUtility methods to upload source to GCS and call Cloud Build service.    )absolute_import)division)unicode_literalsN)encoding)cloudbuild_util)storage_api)log)
properties)files)times)filter
Dockerfile.dockerignorec                 F   t         j                  j                  |       }t        j                  d|      }t        |      D ]6  }t         j                  j                  ||      }|j                  ||d       8 t        j                  |      D ]  \  }}	t        j                  |	j                               }
t        j                  |      }t        |
j                               |_        |j#                  ||
       |
j%                           |j%                          y)a  Create tarfile for upload to GCS.

  The third-party code closes the tarfile after creating, which does not
  allow us to write generated files after calling docker.utils.tar
  since gzipped tarfiles can't be opened in append mode.

  Args:
    upload_dir: the directory to be archived
    gen_files: Generated files to write to the tar
    paths: allowed paths in the tarfile
    gz: gzipped tarfile object
  wmodefileobjF)arcname	recursive)name)r   N)ospathabspathtarfileopensortedjoinaddsix	iteritemsioBytesIOencodeTarInfolengetvaluesizeaddfileclose)
upload_dir	gen_filespathsgzroottr   	full_pathr   contents
genfileobjtar_infos               -lib/googlecloudsdk/api_lib/app/cloud_build.py
_CreateTarr6   .   s     
	$$llR(!UmdT4(IEE)TUE3  i0ndHHOO-.JD)H
++-.HMIIh
I+ 1 '')    c                 `   t         j                  j                  | d      }t               }d}t         j                  j	                  |      rt        j                  |      }n|j                  d      }|r9t        t        t        |j                                     }|t        t              z  }|S )a  Helper function to read the .dockerignore on disk or in generated files.

  Args:
    upload_dir: the path to the root directory.
    gen_files: dict of filename to contents of generated files.

  Returns:
    Set of exclusion expressions from the dockerignore file.
  r   N)r   r   r   setexistsr   ReadFileContentsgetr   bool
splitlinesBLOCKLISTED_DOCKERIGNORE_PATHS)r+   r,   dockerignoreexcludeignore_contentss        r5   _GetDockerignoreExclusionsrC   I   s     j/:,E'/WW^^L!,,\:OmmO4O&99;<=Gs122G	.r7   c                     ddl }t        j                  j                  |       }|j                  j                  |t        |            }|j                  |       |S )a  Helper function to filter paths in root using dockerignore and skip_files.

  We iterate separately to filter on skip_files in order to preserve expected
  behavior (standard deployment skips directories if they contain only files
  ignored by skip_files).

  Args:
    upload_dir: the path to the root directory.
    source_files: [str], relative paths to upload.
    exclude: the .dockerignore file exclusions.

  Returns:
    Set of paths (relative to upload_dir) to include.
  r   N)dockerr   r   r   utilsexclude_pathslistintersection_update)r+   source_filesrA   rE   r/   r-   s         r5   _GetIncludedPathsrK   b   sH    "  
	$$
,,
$
$T4=
9%L)	,r7   c                    |xs i }t        | |      }t        | ||      }t        j                         5 }t        j                  t
        j                  j                  |d            }t        j                  d|      5 }t        | |||       ddd       |j                          t        j                         }	|	j                  |j                  |       ddd       y# 1 sw Y   RxY w# 1 sw Y   yxY w)a  Upload a gzipped tarball of the source directory to GCS.

  Note: To provide parity with docker's behavior, we must respect .dockerignore.

  Args:
    upload_dir: the directory to be archived.
    source_files: [str], relative paths to upload.
    object_ref: storage_util.ObjectReference, the Cloud Storage location to
      upload the source tarball to.
    gen_files: dict of filename to (str) contents of generated config and
      source context files.
  zsrc.tgzwbr   N)rC   rK   r   TemporaryDirectoryBinaryFileWriterr   r   r   gzipGzipFiler6   r*   r   StorageClientCopyFileToGCSr   )
r+   rJ   
object_refr,   dockerignore_contentsincluded_pathstemp_dirfr.   storage_clients
             r5   UploadSourcerZ   ~   s     o2)4ZK$, 57. !Xrww||Hi@AA	D!	,Y; 
-GGI ..0N  4 "!	,	, "!s%   AC+?CAC+C(	$C++C4c                 `    | yt        j                  | d      }t        |j                        S )zAReturns the service timeout in seconds given the duration string.Ns)default_suffix)r   ParseDurationinttotal_seconds)timeout_property_strbuild_timeout_durations     r5   GetServiceTimeoutSecondsrc      s5    ! ../C>AC	#11	22r7   c                 N    | yt        |       }t        j                  |      dz   S )zAReturns the service timeout duration string with suffix appended.Nr\   )rc   r    	text_type)ra   build_timeout_secss     r5   GetServiceTimeoutStringrg      s,    !/0DE	)	*S	00r7   c                   "     e Zd ZdZ fdZ xZS )InvalidBuildErrorzFError indicating that ExecuteCloudBuild was given a bad Build message.c                 J    t         t        |   dj                  |             y )NzeField [{}] was provided, but should not have been. You may be using an improper Cloud Build pipeline.)superri   __init__format)selffield	__class__s     r5   rl   zInvalidBuildError.__init__   s"    	
T+	==CVE]Lr7   )__name__
__module____qualname____doc__rl   __classcell__)rp   s   @r5   ri   ri      s    NL Lr7   ri   c                 B    |D ]  }t        | |d      t        |       y)zDValidates that a Build message doesn't have fields that we populate.N)getattrri   )buildfieldsro   s      r5   _ValidateBuildFieldsrz      s&    eueT".e$$ r7   c           	      *   t        j                         }t        j                  j                  j
                  j                         }t        j                  dj                  |             |j                  |j                  |dd| dg      g| g      S )a  Get the default build for this runtime.

  This build just uses the latest docker builder image (location pulled from the
  app/container_builder_image property) to run a `docker build` with the given
  tag.

  Args:
    output_image: GCR location for the output docker image (e.g.
      `gcr.io/test-gae/hardcoded-output-tag`)

  Returns:
    Build, a CloudBuild Build message with the given steps (ready to be given to
      FixUpBuild).
  zUsing builder image: [{0}]rx   z-t.)r   args)stepsimages)r   GetMessagesModuler
   VALUESappcontainer_builder_imageGetr	   debugrm   Build	BuildStep)output_imagemessagesbuilders      r5   GetDefaultBuildr      s     ..0(!!99==?'))(//89	W&-t\3%G   I J^ 
 
 r7   c                    t        j                         }t        j                  |       } | j                  r9| j                  j
                  j                  t        j                  d             t        | d       t        t        j                  j                  j                  j                               | _        |j"                  | _        |j'                  |j)                  |j"                  |j*                              | _        | S )a  Return a modified Build object with run-time values populated.

  Specifically:
  - `source` is pulled from the given object_ref
  - `timeout` comes from the app/cloud_build_timeout property
  - `logsBucket` uses the bucket from object_ref

  Args:
    build: cloudbuild Build message. The Build to modify. Fields 'timeout',
      'source', and 'logsBucket' will be added and may not be given.
    object_ref: storage_util.ObjectReference, the Cloud Storage location of the
      source tarball.

  Returns:
    Build, (copy) of the given Build message with the specified fields
      populated.

  Raises:
    InvalidBuildError: if the Build message had one of the fields this function
      sets pre-populated
  key)r   )sourcetimeout
logsBucket)bucketobject)storageSource)r   r   r   CopyProtoMessagesubstitutionsadditionalPropertiessortoperator
attrgetterrz   rg   r
   r   r   cloud_build_timeoutr   r   r   r   SourceStorageSourcer   r   )rx   rT   r   s      r5   
FixUpBuildr      s    , ..0(

#
#E
*% 	,,11& 2 ( uAB)//3357%-&&%**"" +  ! %, 
,r7   )N)%rt   
__future__r   r   r   rP   r"   r   r   r   apitools.base.pyr   !googlecloudsdk.api_lib.cloudbuildr   googlecloudsdk.api_lib.storager   googlecloudsdk.corer	   r
   googlecloudsdk.core.utilr   r   r    	six.movesr   r?   r6   rC   rK   rZ   rc   rg   
ValueErrorri   rz   r   r    r7   r5   <module>r      s   " L &  '  	  	  % = 6 # * * * 
 
 #/!@ 6285@31L
 L%0-r7   