
    7V                        S r SSKJr  SSKJr  SSKJr  SSKrSSKrSSKrSSKrSSK	J
r  SSKJ
r
  SSKJ
r  SSKJr  SSKrSSKJr  SSKrSSKrSSKrS	rS
rSrSrSr " S S\5      r " S S\5      r " S S\5      r  " S S\5      r!\RD                  4S jr#S r$S r%S#S jr&  S$S jr'S%S jr(S r)S r*S r+S r,  S$S  jr-  S$S! jr. S#S" jr/g)&z<Library that handles importing files for Deployment Manager.    )absolute_import)division)unicode_literalsN)
exceptions)yaml)filesimportspathnameoutputs/c                   6    \ rS rSrSrS rS rS rS rS r	Sr
g	)
_BaseImport+   zAn imported DM config object.c                 8    Xl         X l        S U l        S U l        g N)	full_pathr   content	base_name)selfr   r   s      =lib/googlecloudsdk/command_lib/deployment_manager/importer.py__init___BaseImport.__init__.   s    NIDLDN    c                     U R                   $ r   )r   r   s    r   GetFullPath_BaseImport.GetFullPath4   s    >>r   c                     U R                   $ r   )r   r   s    r   GetName_BaseImport.GetName7   s    99r   c                     Xl         U $ r   r   )r   r   s     r   
SetContent_BaseImport.SetContent:   s    LKr   c                 8    U R                   R                  S5      $ )N)z.jinjaz.py)r   endswithr   s    r   
IsTemplate_BaseImport.IsTemplate>   s    >>""#455r   )r   r   r   r   N)__name__
__module____qualname____firstlineno____doc__r   r   r    r$   r(   __static_attributes__ r   r   r   r   +   s    %6r   r   c                   H   ^  \ rS rSrSrS	U 4S jjrS rS rS rS r	Sr
U =r$ )
!_ImportSyntheticCompositeTypeFileB   z9Performs common operations on an imported composite type.c                 `   > UR                  S5      S   n[        [        U ]  X5        X l        g )N:   )splitsuperr2   r   
properties)r   r   r9   r   	__class__s       r   r   *_ImportSyntheticCompositeTypeFile.__init__E   s+    ??3"D	
+T;IL Or   c                 V    U R                   c  U R                  U l         U R                   $ r   )r   r   r   s    r   GetBaseName-_ImportSyntheticCompositeTypeFile.GetBaseNameJ   s!    ~~yydn>>r   c                     g)NTr0   r   s    r   Exists(_ImportSyntheticCompositeTypeFile.ExistsO   s    r   c                     U R                   c]  SU R                  U R                  S./0nU R                  (       a  U R                  US   S   S'   [        R
                  " U5      U l         U R                   $ )z6Returns the content of the synthetic file as a string.	resourcestyper   r   r9   )r   r   r   r9   r   dump)r   rC   s     r   
GetContent,_ImportSyntheticCompositeTypeFile.GetContentR   s_    ||$..$))!L MNi	26//	+q!,/YYy)dl<<r   c                     [         er   )NotImplementedError)r   unused_child_paths     r   BuildChildPath0_ImportSyntheticCompositeTypeFile.BuildChildPath[   s    
r   )r   r   r9   r   r*   r+   r,   r-   r.   r   r=   r@   rG   rL   r/   __classcell__r:   s   @r   r2   r2   B   s$    A!

 r   r2   c                   H   ^  \ rS rSrSrS	U 4S jjrS rS rS rS r	Sr
U =r$ )
_ImportFile_   z/Performs common operations on an imported file.c                 B   > U(       a  UOUn[         [        U ]  X5        g r   )r8   rR   r   r   r   r   r:   s      r   r   _ImportFile.__init__b   s    4YD	+t%i6r   c                     U R                   c.  [        R                  R                  U R                  5      U l         U R                   $ r   )r   osr
   basenamer   r   s    r   r=   _ImportFile.GetBaseNamef   s0    ~~ww''7dn>>r   c                 T    [         R                  R                  U R                  5      $ r   )rX   r
   isfiler   r   s    r   r@   _ImportFile.Existsk   s    77>>$..))r   c           	      H   U R                   c2   [        R                  " U R                  5      U l         U R                   $ U R                   $ ! [        R                   aA  n[
        R                  " SU R                  < S[        R                  " U5      < 35      eS nAff = f)NzUnable to read file 'z'. )	r   r   ReadFileContentsr   Errorr   ConfigErrorsix	text_type)r   es     r   rG   _ImportFile.GetContentn   s    ||Q--dnn= <<4<< [[ Q$$.2nncmmA>NOQ 	QQs   %A B! <BB!c                     [        U5      (       a  U$ [        R                  R                  [        R                  R	                  [        R                  R                  U R                  5      U5      5      $ r   )_IsUrlrX   r
   normpathjoindirnamer   r   
child_paths     r   rL   _ImportFile.BuildChildPathw   sO    j77
RWW__T^^4jAC Cr   r   r   r   rN   rP   s   @r   rR   rR   _   s&    77
*C Cr   rR   c                   b   ^  \ rS rSrSrSU 4S jjrS rS rS rSS jr	S r
\S	 5       rS
rU =r$ )
_ImportUrl~   z,Class to perform operations on a URL import.c                 d   > U R                  U5      nU(       a  UOUn[        [        U ]  X5        g r   )_ValidateUrlr8   rp   r   rU   s      r   r   _ImportUrl.__init__   s+    !!),I4YD	*d$Y5r   c                     U R                   c`  [        R                  " [        R                  R
                  R                  R                  U R                  5      R                  5      U l         U R                   $ r   )
r   	posixpathrY   rb   movesurllibparseurlparser   r
   r   s    r   r=   _ImportUrl.GetBaseName   sQ    ~~ ))
))


 
 
)
)$..
9
>
>@dn>>r   c                 D    U R                   (       a  gU R                  SS9$ )NTF)raise_exceptionsr   _RetrieveContentr   s    r   r@   _ImportUrl.Exists   s     ||  % 88r   c                 T    U R                   c  U R                  5         U R                   $ r   r~   r   s    r   rG   _ImportUrl.GetContent   s"    ||
<<r   c                     [         R                  " U R                  5      n UR                  5         UR                  U l        g! [         R                  R
                   a  nU(       a  Ue SnAgSnAff = f)a  Helper function for both Exists and GetContent.

Args:
  raise_exceptions: Set to false if you just want to know if the file
      actually exists.

Returns:
  True if we successfully got the content of the URL. Returns False is
  raise_exceptions is False.

Raises:
  HTTPError: If raise_exceptions is True, will raise exceptions for 4xx or
      5xx response codes instead of returning False.
NFT)requestsgetr   raise_for_statusr   	HTTPErrortextr   )r   r}   rrd   s       r   r   _ImportUrl._RetrieveContent   s`     	T^^$A 66DL (( 	s   A A5"	A00A5c                     [        U5      (       a  U$ [        R                  R                  R                  R                  U R                  U5      $ r   )rg   rb   rw   rx   ry   urljoinr   rk   s     r   rL   _ImportUrl.BuildChildPath   s:    j99!!))$..*EEr   c                    [         R                  R                  R                  R	                  U 5      nUR
                  S;  a)  [        R                  " SU < SUR
                  < S35      eUR                  (       a  UR                  S:X  a  [        R                  " SU -  5      eUR                  (       d"  UR                  (       d  UR                  (       a  [        R                  " SU -  5      eU $ )z,Make sure the url fits the format we expect.)httphttpszURL 'z' scheme was 'z''; it must be either 'https' or 'http'.r   zURL '%s' doesn't have a path.zCURL '%s' should only have a path, no params, queries, or fragments.)rb   rw   rx   ry   rz   schemer   ra   r
   paramsqueryfragment)url
parsed_urls     r   rs   _ImportUrl._ValidateUrl   s     !!''005J 11""*##%& & ??joo4""#BS#HIIJ,,
0C0C""
O  Jr   rn   r   )T)r*   r+   r,   r-   r.   r   r=   r@   rG   r   rL   staticmethodrs   r/   rO   rP   s   @r   rp   rp   ~   s9    46
9

6F
  r   rp   c                     U[         :X  a  U $ / nU  HE  n[         U;   a'  UR                  UR                  U[         5      5        M4  UR                  U5        MG     U$ )ay  Clean up path separators for globbing-resolved filenames.

Python's globbing library resolves wildcards with OS-native path separators,
however users could use POSIX paths even for configs in a Windows environment.
This can result in multi-separator-character paths where /foo/bar/* will
return a path match like /foo/bar\\baz.yaml.
This function will make paths separators internally consistent.

Args:
  filename_list: List of filenames resolved using python's glob library.
  native_separator: OS native path separator. Override for testing only.

Returns:
  List of filenames edited to have consistent path separator characters.
)POSIX_PATH_SEPARATORappendreplace)filename_listnative_separatorsanitized_pathsfs       r   _SanitizeWindowsPathsGlobsr      s[      --/aq QYY'79MNOQ	 
 
r   c                     [         R                  R                  R                  R	                  U 5      nUR
                  =(       a    UR                  $ )z4Returns true if the passed resource_handle is a url.)rb   rw   rx   ry   rz   r   netloc)resource_handleparseds     r   rg   rg      s5    99!!**?;&		(6==(r   c                 0    [         R                  " SU 5      $ )a  Returns true if the resource_handle matches composite type syntax.

Args:
  composite_type_name: a string of the name of the composite type.

Catches most syntax errors by checking that the string contains the substring
'/composite:' preceded and followed by at least one character, none of which
are colons, slashes, or whitespace. Periods may follow the substring, but not
proceed it.
z^[^/:.\s]+/composite:[^/:\s]+$)rematch)composite_type_names    r   _IsValidCompositeTypeSyntaxr      s     
35H	IIr   c                 N    [        U 5      (       a  [        X5      $ [        X5      $ r   )rg   rp   rR   )r   r   s     r   _BuildFileImportObjectr      s#    Ii&&y''r   c                     U(       a1  [        U5      (       d  [        R                  " S5      e[        X#5      $ U (       a  [	        U 5      $ U(       a  [	        U5      $ [        R                  " S5      e)z2Build an import object from the given config name.zInvalid composite type syntax.zHNo path or name for a config, template, or composite type was specified.)r   r   ra   r2   r   configtemplatecomposite_typer9   s       r   _BuildImportObjectr     se     &~66""#CDD,^HH!&))!(++  ? 	@ @r   c           
      ^   Sn[        U R                  5      (       dF  [        R                  R	                  [        R                  R                  U R                  5      5      nU R                  5       n[        R                  " U5      n/ nU(       Ga  [        U;   Gay  U[           nU GHi  n[        U;  a-  [        R                  " S[        < SU R                  < S35      e/ nU(       a  U(       a  [        U[           5      (       d  [        R                  " U5         [        R                  " U[           5      n[!        U5      nSSS5        [#        U5      S:  ak  [$        U;   a0  [        R                  " SU[$           < SU R                  < S35      eUR'                  U V	s/ s H  n	[$        U	[        U	0PM     sn	5        GM#  [#        U5      S:X  a  US	   U[        '   [$        U;  a  U[           U[$        '   UR)                  U5        GMl     U$ ! , (       d  f       N= fs  sn	f )
a  Extract the import section of a file.

If the glob_imports config is set to true, expand any globs (e.g. *.jinja).
Named imports cannot be used with globs that expand to more than one file.
If globbing is disabled or a glob pattern does not expand to match any files,
importer will use the literal string as the file path.

Args:
  import_object: The object in which to look for imports.
  globbing_enabled: If true, will resolved glob patterns dynamically.

Returns:
  A list of dictionary objects, containing the keys 'path' and 'name' for each
  file to import. If no name was found, we populate it with the value of path.

Raises:
 ConfigError: If we cannont read the file, the yaml is malformed, or
     the import object does not contain a 'path' field.
NzMissing required field z in import in file .r6   zCannot use import name z for path glob in file z that matches multiple objects.r   )rg   r   rX   r
   rj   abspathrG   r   loadIMPORTSPATHr   ra   r   ChDirglobr   lenNAMEextendr   )
import_objectglobbing_enabled
parent_dirr   yaml_contentr	   raw_importsiglob_matchesgs
             r   _GetYamlImportsr     s   ( *	''	(	(1H1H!IJJ$$&'7#,'g-w'K	Q$$=**,- 	- l	j$[[$1T7+,3LA, %
 |q QY((23D'2?2I2IKL L ..lCl4D!,lC
D
	\	a	q/$	QD'$nnQ9 : 
.) %$ Ds   !)H*H*

H'	c                 ,   [         R                  R                  R                  R                  R
                  R                  5       n[        XS9n/ nU H<  nU R                  U[           5      nUR                  [        XT[           5      5        M>     U$ )aT  Given a file object, gets all child objects it imports.

Args:
  parent_object: The object in which to look for imports.

Returns:
  A list of import objects representing the files imported by the parent.

Raises:
  ConfigError: If we cannont read the file, the yaml is malformed, or
     the import object does not contain a 'path' field.
)r   )googlecloudsdkcorer9   VALUESdeployment_managerglob_importsGetBoolr   rL   r   r   r   r   )parent_objectr   yaml_importschild_objectsyaml_importrl   s         r   _GetImportObjectsr   N  s     $((33::,,wwy  8, -!k--k$.?@J/
<MNO " 
r   c                     U R                  5       S-   nU R                  5       S-   n[        X5      nUR                  5       (       d  / $ [	        U5      nUR                  U5        U$ )a'  Takes a template and looks for its schema to process.

Args:
  import_object: Template object whose schema to check for and process

Returns:
  List of import_objects that the schema is importing.

Raises:
  ConfigError: If any of the schema's imported items are missing the
      'path' field.
.schema)r   r    r   r@   r   r   )r   schema_pathschema_nameschema_objectimport_objectss        r   _HandleTemplateImportr   i  sj     ))+i7+%%')3+(B-					I %]3. &	r   c           	         / nUR                  [        U5      5        0 n/ nU(       Ga9  UR                  5       nSnUR                  5       U;   av  UR	                  5       X5R                  5          :X  a  SnOO[
        R                  " SUR	                  5       < SX5R                  5          < SUR                  5       < S35      eU(       a  UR                  5       (       a  UR                  [        U5      5        U R                  UR                  5       UR                  5       S9nUR	                  5       X5R                  5       '   UR                  U5        U(       a  GM9  U$ )a  Constructs a list of ImportFiles from the provided import file names.

Args:
  messages: Object with v2 API messages.
  config_object: Parent file that contains files to import.

Returns:
  List of ImportFiles containing the name and content of the imports.

Raises:
  ConfigError: if the import files cannot be read from the specified
      location, the import does not have a 'path' attribute, or the filename
      has already been imported.
TFzFiles z and z both being imported as r   )r   r   )r   r   popr    r   r   ra   r(   r   
ImportFilerG   r   )messagesconfig_objectr   import_resource_mapimport_resourcesr   process_objectimport_resources           r   CreateImportsr     sT   " . )-89  "&&(MN "55

#
#
%
335
67  $$&&( !6!6!89""$&' 	'  
	!	!	#	#3MBC ++$$&**, , .o 6C5N5N5P//12o.? 	B 
r   c                 x    U R                  SS5      R                  SS5      nUS   R                  5       USS -   $ )zMake sure the base_name will be a valid resource name.

Args:
  base_name: Name of a template file, and therefore not empty.

Returns:
  base_name with periods and underscores removed,
      and the first letter lowercased.
r   -_r   r6   N)r   lower)r   	sanitizeds     r   _SanitizeBaseNamer     sC     S)11#s;) 
1				!"	--r   c                 z   [        U UUUS9nU(       a  U$ U (       aJ  UR                  5       (       a  [        R                  " S5      eU(       a  [        R                  " S5      eU$ U(       a+  UR                  5       (       d  [        R                  " S5      eUR	                  5       nU[        U5      S.nU(       a  X6S'   SU0/U/S.n/ nUR                  5       S	-   n	UR                  5       S	-   n
[        X5      nUR                  5       (       ax  UR                  5       nUS
   n[        R                  " XS9nU(       aH  [        U;   a>  U[           R                  5        H#  nUR                  USU-   S-   U-   S-   S.5        M%     U(       a  XS'   [        R                   " U5      nUR#                  U5      $ )a  Takes the path to a config and returns a processed config.

Args:
  config: Path to the yaml config file.
  template: Path to the template config file.
  composite_type: name of the composite type config.
  properties: Dictionary of properties, only used if
              the file is a template or composite type.

Returns:
  A tuple of base_path, config_contents, and a list of import objects.

Raises:
  ArgumentError: If using the properties flag for a config file
      instead of a template or composite type.
r   zlCreating deployments from templates with the --config flag is not supported. Please use the --template flag.zThe properties flag should only be used when using a template (--template) or composite type (--composite-type) as your config file.zRThe --template flag should only be used when using a template as your config file.rD   r9   r
   )r	   rC   r   r   )	file_hintz$(ref.r   ))r   valuer   )r   r(   r   ArgumentErrorr=   r   r   r    r   r@   rG   r   r   OUTPUTSkeysr   rF   r$   )r   r   r   r9   
config_objr   custom_resourcecustom_dictcustom_outputsr   r   r   schema_contentconfig_nameyaml_schemaoutput_namecustom_contents                    r   BuildConfigr     s   $ "+31?-79*
 $$CD D 
$$45 5
   ""$$78 8
 $$&) '.y9;/ $.L! %i02.02+ . &&(94+""$y0+(B-"--/N!&)K))NBKw+-$W-224+ ,s2[@3FH	I 5
 +	99[). 
		~	..r   c                     [        UUUUS9nU R                  U R                  UR                  5       S9[	        X5      S9$ )ac  Construct a TargetConfig from the provided config file with imports.

Args:
  messages: Object with v2 API messages.
  config: Path to the yaml config file.
  template: Path to the template config file.
  composite_type: name of the composite type config.
  properties: Dictionary of properties, only used if the full_path is a
      template or composite type.

Returns:
  TargetConfig containing the contents of the config file and the names and
  contents of any imports.

Raises:
  ConfigError: if the config file or import files cannot be read from
      the specified locations, or if they are malformed.
r   r#   r   r	   )r   TargetConfiguration
ConfigFilerG   r   )r   r   r   r   r9   r   s         r   BuildTargetConfigr   1  sU    ( V'/-;)35-
 
	%	%  )A)A)C DH4 
& 
6 6r   c                 T    U R                   R                  UR                  UUUS95      nUR                  nUR                  nU(       a  [        R                  " UR                  5      n
[        U
S   5      S:w  a  [        R                  " S5      eU
S   S   nSU;  a  0 US'   US   n[        R                   " U5       H	  u  pXU'   M     [        R"                  " U
5      Ul        UR%                  XxS9$ ! [
        R                   a  n	[        R                  " U	5      eSn	A	ff = f)	a  Construct a TargetConfig from a manifest of a previous deployment.

Args:
  client: Deployment Manager v2 API client.
  messages: Object with v2 API messages.
  project_id: Project for this deployment. This is used when pulling the
      the existing manifest.
  deployment_id: Deployment used to pull retrieve the manifest.
  manifest_id: The manifest to pull down for constructing the target.
  properties: Dictionary of properties, only used if the manifest has a
      single resource. Properties will override only. If the manifest
      has properties which do not exist in the properties hash will remain
      unchanged.

Returns:
  TargetConfig containing the contents of the config file and the names and
  contents of any imports.

Raises:
  HttpException: in the event that there is a failure to pull the manifest
      from deployment manager
  ManifestError: When the manifest being revived has more than one
      resource
)project
deploymentmanifestNrC   r6   zHManifest reuse with properties requires there only be a single resource.r   r9   r   )	manifestsGet$DeploymentmanagerManifestsGetRequestr   r	   apitools_exceptions	HttpErrorapi_exceptionsHttpExceptionr   r   r   r   r   ManifestErrorrb   	iteritemsrF   r   )clientr   
project_iddeployment_idmanifest_idr9   r  config_filer	   errorconfig_yamlsingle_resourceexisting_propertieskeyr   s                  r   BuildTargetConfigFromManifestr  O  s+   4.##55$  	6 	
H //KG ))K//0K
;{#$)$$-. . "+.q1O?*&(ol#),7mmJ/
!&# 0))K0K		%	%[	%	JJ' 
	&	& .

&
&u
--.s   AC8 8D'D""D'r   )NNNN)F)0r.   
__future__r   r   r   r   rX   rv   r   apitools.base.pyr   r  )googlecloudsdk.api_lib.deployment_managergooglecloudsdk.api_lib.utilr	  googlecloudsdk.corer   googlecloudsdk.core.propertiesr   googlecloudsdk.core.utilr   r   rb   six.moves.urllib.parser   r   r   r   r   objectr   r2   rR   rp   sepr   rg   r   r   r   r   r   r   r   r   r   r   r  r0   r   r   <module>r"     s    C &  '  	  	 > @ D $ % *  
 

 6& 6. :C+ C>K K\ @Bvv 6)J( .27;@:z6>>B." '+04T/n 7;6:6> ;?7Kr   