
    7V                        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	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lZddlZddlZd	Zd
ZdZdZdZ G d de      Z G d de      Z G d de      Z  G d de      Z!ejD                  fdZ#d Z$d Z%d#dZ&	 	 d$dZ'd%dZ(d Z)d Z*d Z+d Z,	 	 d$d Z-	 	 d$d!Z.	 d#d"Z/y)&z<Library that handles importing files for Deployment Manager.    )absolute_import)division)unicode_literalsN)
exceptions)yaml)filesimportspathnameoutputs/c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)_BaseImportzAn imported DM config object.c                 <    || _         || _        d | _        d | _        y N)	full_pathr   content	base_name)selfr   r   s      =lib/googlecloudsdk/command_lib/deployment_manager/importer.py__init__z_BaseImport.__init__.   s    DNDIDLDN    c                     | j                   S r   )r   r   s    r   GetFullPathz_BaseImport.GetFullPath4   s    >>r   c                     | j                   S r   )r   r   s    r   GetNamez_BaseImport.GetName7   s    99r   c                     || _         | S r   r   )r   r   s     r   
SetContentz_BaseImport.SetContent:   s    DLKr   c                 8    | j                   j                  d      S )N)z.jinjaz.py)r   endswithr   s    r   
IsTemplatez_BaseImport.IsTemplate>   s    >>""#455r   N)	__name__
__module____qualname____doc__r   r   r   r    r#    r   r   r   r   +   s    %6r   r   c                   <     e Zd ZdZd fd	Zd Zd Zd Zd Z xZ	S )!_ImportSyntheticCompositeTypeFilez9Performs common operations on an imported composite type.c                 d    |j                  d      d   }t        t        |   ||       || _        y )N:   )splitsuperr*   r   
properties)r   r   r0   r   	__class__s       r   r   z*_ImportSyntheticCompositeTypeFile.__init__E   s/    ??3"D	
+T;ItL DOr   c                 T    | j                   | j                  | _         | j                   S r   )r   r   r   s    r   GetBaseNamez-_ImportSyntheticCompositeTypeFile.GetBaseNameJ   s!    ~~yydn>>r   c                      y)NTr(   r   s    r   Existsz(_ImportSyntheticCompositeTypeFile.ExistsO   s    r   c                     | j                   Wd| j                  | j                  dgi}| j                  r| j                  |d   d   d<   t	        j
                  |      | _         | j                   S )z6Returns the content of the synthetic file as a string.	resourcestyper   r   r0   )r   r   r   r0   r   dump)r   r7   s     r   
GetContentz,_ImportSyntheticCompositeTypeFile.GetContentR   s_    ||$..$))!L MNi	26//	+q!,/YYy)dl<<r   c                     t         r   )NotImplementedError)r   unused_child_paths     r   BuildChildPathz0_ImportSyntheticCompositeTypeFile.BuildChildPath[   s    
r   r   
r$   r%   r&   r'   r   r3   r5   r;   r?   __classcell__r1   s   @r   r*   r*   B   s    A!

r   r*   c                   <     e Zd ZdZd fd	Zd Zd Zd Zd Z xZ	S )_ImportFilez/Performs common operations on an imported file.c                 :    |r|n|}t         t        |   ||       y r   )r/   rD   r   r   r   r   r1   s      r   r   z_ImportFile.__init__b   s    4YD	+t%i6r   c                     | j                   .t        j                  j                  | j                        | _         | j                   S r   )r   osr
   basenamer   r   s    r   r3   z_ImportFile.GetBaseNamef   s0    ~~ww''7dn>>r   c                 T    t         j                  j                  | j                        S r   )rH   r
   isfiler   r   s    r   r5   z_ImportFile.Existsk   s    77>>$..))r   c           	      :   | j                   1	 t        j                  | j                        | _         | j                   S | j                   S # t        j                  $ r=}t        j                  d| j                  dt        j                  |            d }~ww xY w)NzUnable to read file 'z'. )	r   r   ReadFileContentsr   Errorr   ConfigErrorsix	text_type)r   es     r   r;   z_ImportFile.GetContentn   s    ||Q--dnn= <<4<< [[ Q$$.2nncmmA>NOQ 	QQs   $A
 
B8BBc                     t        |      r|S t        j                  j                  t        j                  j	                  t        j                  j                  | j                        |            S r   )_IsUrlrH   r
   normpathjoindirnamer   r   
child_paths     r   r?   z_ImportFile.BuildChildPathw   sL    j77
RWW__T^^4jAC Cr   r   r@   rB   s   @r   rD   rD   _   s     77
*Cr   rD   c                   T     e Zd ZdZd	 fd	Zd Zd Zd Zd
dZd Z	e
d        Z xZS )
_ImportUrlz,Class to perform operations on a URL import.c                 \    | j                  |      }|r|n|}t        t        |   ||       y r   )_ValidateUrlr/   r[   r   rF   s      r   r   z_ImportUrl.__init__   s-    !!),I4YD	*d$Y5r   c                     | j                   _t        j                  t        j                  j
                  j                  j                  | j                        j                        | _         | j                   S r   )
r   	posixpathrI   rP   movesurllibparseurlparser   r
   r   s    r   r3   z_ImportUrl.GetBaseName   sQ    ~~ ))
))


 
 
)
)$..
9
>
>@dn>>r   c                 @    | j                   ry| j                  d      S )NTF)raise_exceptionsr   _RetrieveContentr   s    r   r5   z_ImportUrl.Exists   s     ||  % 88r   c                 R    | j                   | j                          | j                   S r   rf   r   s    r   r;   z_ImportUrl.GetContent   s"    ||
<<r   c                     t        j                  | j                        }	 |j                          |j                  | _        y# t         j                  j
                  $ r}|r|Y d}~yd}~ww xY w)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   re   rrR   s       r   rg   z_ImportUrl._RetrieveContent   s`     	T^^$A 66DL (( 	s   A A. A))A.c                     t        |      r|S t        j                  j                  j                  j                  | j                  |      S r   )rT   rP   r`   ra   rb   urljoinr   rX   s     r   r?   z_ImportUrl.BuildChildPath   s7    j99!!))$..*EEr   c                    t         j                  j                  j                  j	                  |       }|j
                  dvr&t        j                  d| d|j
                  d      |j                  r|j                  dk(  rt        j                  d| z        |j                  s|j                  s|j                  rt        j                  d| z        | S )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.)rP   r`   ra   rb   rc   schemer   rO   r
   paramsqueryfragment)url
parsed_urls     r   r]   z_ImportUrl._ValidateUrl   s     !!''005J 11""*##%& & ??joo4""#BS#HIIJ,,
0C0C""
O  Jr   r   )T)r$   r%   r&   r'   r   r3   r5   r;   rg   r?   staticmethodr]   rA   rB   s   @r   r[   r[   ~   s9    46
9

6F
  r   r[   c                     |t         k(  r| S g }| D ]A  }t         |v r&|j                  |j                  |t                      1|j                  |       C |S )a  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                     t         j                  j                  j                  j	                  |       }|j
                  xr |j                  S )z4Returns true if the passed resource_handle is a url.)rP   r`   ra   rb   rc   ru   netloc)resource_handleparseds     r   rT   rT      s5    99!!**?;&		(6==(r   c                 .    t        j                  d|       S )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                 H    t        |       rt        | |      S t        | |      S r   )rT   r[   rD   )r   r   s     r   _BuildFileImportObjectr      s$    Ii&&y$''r   c                     |r,t        |      st        j                  d      t        ||      S | rt	        |       S |rt	        |      S t        j                  d      )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   rO   r*   r   configtemplatecomposite_typer0   s       r   _BuildImportObjectr     sd     &~6""#CDD,^ZHH!&))!(++  ? 	@ @r   c           
         d}t        | j                        sFt        j                  j	                  t        j                  j                  | j                              }| j                         }t        j                  |      }g }|r]t        |v rT|t           }|D ]E  }t        |vr*t        j                  dt        d| j                  d      g }|r|rt        |t                 st        j                  |      5  t        j                  |t                 }t!        |      }ddd       t#        |      dkD  rbt$        |v r-t        j                  d|t$           d| j                  d      |j'                  |D 	cg c]  }	t$        |	t        |	i c}	       t#        |      dk(  r|d	   |t        <   t$        |vr|t           |t$        <   |j)                  |       H |S # 1 sw Y   xY wc c}	w )
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 .r-   zCannot use import name z for path glob in file z that matches multiple objects.r   )rT   r   rH   r
   rW   abspathr;   r   loadIMPORTSPATHr   rO   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   ?(G'G3
'G0	c                 2   t         j                  j                  j                  j                  j
                  j                         }t        | |      }g }|D ]<  }| j                  |t                 }|j                  t        ||t                        > |S )ad  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corer0   VALUESdeployment_managerglob_importsGetBoolr   r?   r   r~   r   r   )parent_objectr   yaml_importschild_objectsyaml_importrY   s         r   _GetImportObjectsr   N  s     $((33::,,wwy  &68, -!k--k$.?@J/
K<MNO " 
r   c                     | j                         dz   }| j                         dz   }t        ||      }|j                         sg S t	        |      }|j                  |       |S )a7  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   r5   r   r~   )r   schema_pathschema_nameschema_objectimport_objectss        r   _HandleTemplateImportr   i  si     ))+i7+%%')3+(kB-				I %]3. &	r   c           	         g }|j                  t        |             i }g }|r(|j                         }d}|j                         |v rs|j	                         ||j                            k(  rd}nLt        j                  d|j	                         d||j                            d|j                         d      |r|j                         r|j                  t        |             | j                  |j                         |j                               }|j	                         ||j                         <   |j                  |       |r(|S )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   rO   r#   r   
ImportFiler;   r~   )messagesconfig_objectr   import_resource_mapimport_resourcesr   process_objectimport_resources           r   CreateImportsr     sU   " . )-89  "&&(MN "55

#
#
%
m335
67  $$&&( !6!6!89""$&' 	'  
	!	!	#3MBC ++$$&**, , .o 6C5N5N5P-//12o.? 	B 
r   c                 x    | j                  dd      j                  dd      }|d   j                         |dd z   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   r-   N)r   lower)r   	sanitizeds     r   _SanitizeBaseNamer     sC     S)11#s;) 
1				!"	--r   c                    t        | |||      }|r|S | r>|j                         rt        j                  d      |rt        j                  d      |S |r%|j                         st        j                  d      |j	                         }|t        |      d}|r||d<   d|ig|gd}g }|j                         d	z   }	|j                         d	z   }
t        |	|
      }|j                         rr|j                         }|d
   }t        j                  ||	      }|rDt        |v r<|t           j                         D ]"  }|j                  |d|z   dz   |z   dz   d       $ |r||d<   t        j                   |      }|j#                  |      S )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.r8   r0   r
   )r	   r7   r   r   )	file_hintz$(ref.r   ))r   valuer   )r   r#   r   ArgumentErrorr3   r   r   r   r   r5   r;   r   r   OUTPUTSkeysr~   r:   r    )r   r   r   r0   
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;/ $.OL! %i02.02+ . &&(94+""$y0+(kB-"--/N!&)K))NkBKw+-$W-224+ ,s2[@3FH	I 5
 +K	99[). 
		~	..r   c                     t        ||||      }| j                  | j                  |j                               t	        | |            S )a  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
ConfigFiler;   r   )r   r   r   r   r0   r   s         r   BuildTargetConfigr   1  sW    ( V'/-;)35-
 
	%	%  )A)A)C DHm4 
& 
6 6r   c                 F   	 | j                   j                  |j                  |||            }|j                  }|j                  }|rt        j                  |j                        }
t        |
d         dk7  rt        j                  d      |
d   d   }d|vri |d<   |d   }t        j                   |      D ]
  \  }}|||<    t        j"                  |
      |_        |j%                  ||      S # t
        j                  $ r}	t        j                  |	      d}	~	ww xY w)	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manifestNr7   r-   zHManifest reuse with properties requires there only be a single resource.r   r0   r   )	manifestsGet$DeploymentmanagerManifestsGetRequestr   r	   apitools_exceptions	HttpErrorapi_exceptionsHttpExceptionr   r   r   r   r   ManifestErrorrP   	iteritemsr:   r   )clientr   
project_iddeployment_idmanifest_idr0   r   config_filer	   errorconfig_yamlsingle_resourceexisting_propertieskeyr   s                  r   BuildTargetConfigFromManifestr   O  s2   4.##55$  	6 	
H //KG ))K//0K
;{#$)$$-. . "+.q1O?*&(ol#),7mmJ/
U!&# 0))K0K		%	%['	%	JJ' 
	&	& .

&
&u
--.s   AC3 3D DD r   )NNNN)F)0r'   
__future__r   r   r   r   rH   r_   r   apitools.base.pyr   r   )googlecloudsdk.api_lib.deployment_managergooglecloudsdk.api_lib.utilr   googlecloudsdk.corer   googlecloudsdk.core.propertiesr   googlecloudsdk.core.utilr   rj   rP   six.moves.urllib.parser   r   r   r   r}   objectr   r*   rD   r[   sepr   rT   r   r   r   r   r   r   r   r   r   r   r   r(   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   