
    MG                        S 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
Jr  SrS	rS
R                  \\S9rS\-   rS\-   r " S S\5      rS rS rS rS rS rS rS rS r " S S\5      r " S S\5      rSS jrg)zUtilities for deriving services and configs from paths.

Paths are typically given as positional params, like
`gcloud app deploy <path1> <path2>...`.
    N)env)yaml_parsing)
exceptions)log)fileszChttps://cloud.google.com/appengine/docs/standard/reference/app-yamlzChttps://cloud.google.com/appengine/docs/flexible/reference/app-yamlzusing the directions at {flex} (App Engine flexible environment) or {std} (App Engine standard environment) under the tab for your language.)flexstdz4As an alternative, create an app.yaml file yourself zAn app.yaml (or appengine-web.xml) file is required to deploy this directory as an App Engine application. Create an app.yaml file c                   N    \ rS rSrSrS r\S 5       r\S 5       r\	S 5       r
Srg)	Service2   a3  Represents data around a deployable service.

Attributes:
  descriptor: str, File path to the original deployment descriptor, which is
    either a `<service>.yaml` or an `appengine-web.xml`.
  source: str, Path to the original deployable artifact or directory, which
    is typically the original source directory, but could also be an artifact
    such as a fat JAR file.
  service_info: yaml_parsing.ServiceYamlInfo, Info parsed from the
    `<service>.yaml` file. Note that service_info.file may point to a
    file in a staged directory.
  upload_dir: str, Path to the source directory. If staging is required, this
    points to the staged directory.
  service_id: str, the service id.
  path: str, File path to the staged deployment `<service>.yaml` descriptor
    or to the original one, if no staging is used.
c                 4    Xl         X l        X0l        X@l        g N)
descriptorsourceservice_info
upload_dir)selfr   r   r   r   s        1lib/googlecloudsdk/command_lib/app/deployables.py__init__Service.__init__E   s     OK$ O    c                 .    U R                   R                  $ r   )r   moduler   s    r   
service_idService.service_idK   s    ###r   c                 .    U R                   R                  $ r   )r   filer   s    r   pathService.pathO   s    !!!r   c                 >    U H  nU" XU5      nU(       d  M  Us  $    g)a9  Return a Service from a path using staging if necessary.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file
      of any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will be invoked if there is a runtime
      and environment match.
  path_matchers: List[Function], ordered list of functions on the form
      fn(path, stager), where fn returns a Service or None if no match.
  appyaml: str or None, the app.yaml location to used for deployment.

Returns:
  Service, if one can be derived, else None.
N )clsr   stagerpath_matchersappyamlmatcherservices          r   FromPathService.FromPathS   s)      !g.g	 ! r   )r   r   r   r   N)__name__
__module____qualname____firstlineno____doc__r   propertyr   r   classmethodr)   __static_attributes__r"   r   r   r   r   2   sH    $! $ $ " "  r   r   c                    [         R                  R                  U 5      (       a  U O[         R                  R                  U S5      n[         R                  R	                  U5      u  pE[         R                  R                  U5      (       a  US;   a{  [         R                  R                  U5      n[        R                  R                  U5      nUR                  X6UR                  UR                  U5      n[        X6Xx=(       d    U5      $ g)a  Generate a Service from an <service>.yaml source path.

This function is a path matcher that returns if and only if:
- `path` points to either a `<service>.yaml` or `<app-dir>` where
  `<app-dir>/app.yaml` exists.
- the yaml-file is a valid <service>.yaml file.

If the runtime and environment match an entry in the stager, the service will
be staged into a directory.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file of
      any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will be invoked if there is a runtime
      and environment match.
  appyaml: str or None, the app.yaml location to used for deployment.

Raises:
  staging.StagingCommandFailedError, staging command failed.

Returns:
  Service, fully populated with entries that respect a potentially
      staged deployable service, or None if the path does not match the
      pattern described.
app.yaml)z.yamlz.ymlN)osr   isfilejoinsplitextexistsdirnamer   ServiceYamlInfoFromFileStageruntimer   r   )	r   r$   r&   r   _extapp_dirr   staging_dirs	            r   ServiceYamlMatcherrC   j   s    4 ww~~d++td>H2J*77J'&!WW^^JC+<$<ggooj)G//88DL,,zL4H4H+//:K :6LWMM	r   c                    [         R                  R                  U 5      u  p4[         R                  R                  U 5      (       a  US;   a  [         R                  R	                  [         R                  R                  U [         R                  5      5      nU nUR                  XeS[        R                  U5      n[         R                  R                  US5      n[        R                  R                  U5      n	[        XeX5      $ g)a  Generate a Service from a Java fatjar path.

This function is a path matcher that returns if and only if:
- `jar_path` points to  a jar file .

The service will be staged according to the stager as a jar runtime,
which is defined in staging.py.

Args:
  jar_path: str, Unsanitized absolute path pointing to a file of jar type.
  stager: staging.Stager, stager that will be invoked if there is a runtime
    and environment match.
  appyaml: str or None, the app.yaml location to used for deployment.

Raises:
  staging.StagingCommandFailedError, staging command failed.

Returns:
  Service, fully populated with entries that respect a staged deployable
      service, or None if the path does not match the pattern described.
)z.jarzjava-jarr4   N)r5   r   r8   r9   abspathr7   pardirr=   r   STANDARDr   r;   r<   r   )
jar_pathr$   r&   r?   r@   rA   r   rB   	yaml_pathr   s
             r   
JarMatcherrJ      s    , 77H%&!WW^^H#/ggoobggll8RYY?@GJ,,zJ&(K[*5I//88CL:BB	r   c                 :   [         R                  R                  U 5      (       a  U O[         R                  R                  U S5      n[         R                  R	                  U5      n[         R                  R                  U5      (       a  US:X  a  [         R                  R                  U5      nUR                  X5S[        R                  U5      n[         R                  R                  US5      n[        R                  R                  U5      n[        X5X5      $ g)a  Generate a Service from an Maven project source path.

This function is a path matcher that returns true if and only if:
- `path` points to either a Maven `pom.xml` or `<maven=project-dir>` where
  `<maven-project-dir>/pom.xml` exists.

If the runtime and environment match an entry in the stager, the service will
be staged into a directory.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file of
    any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will be invoked if there is a runtime
    and environment match.
  appyaml: str or None, the app.yaml location to used for deployment.

Raises:
  staging.StagingCommandFailedError, staging command failed.

Returns:
  Service, fully populated with entries that respect a potentially
      staged deployable service, or None if the path does not match the
      pattern described.
zpom.xmlzjava-maven-projectr4   Nr5   r   r6   r7   basenamer9   r:   r=   r   rG   r   r;   r<   r   	r   r$   r&   r   filenamerA   rB   rI   r   s	            r   PomXmlMatcherrP      s    2 ww~~d++tdI1N*WWj)(WW^^JH	$9ggooj)G,,z4H"||W6K[*5I//88CL:BB	r   c                 :   [         R                  R                  U 5      (       a  U O[         R                  R                  U S5      n[         R                  R	                  U5      n[         R                  R                  U5      (       a  US:X  a  [         R                  R                  U5      nUR                  X5S[        R                  U5      n[         R                  R                  US5      n[        R                  R                  U5      n[        X5X5      $ g)a  Generate a Service from an Gradle project source path.

This function is a path matcher that returns true if and only if:
- `path` points to either a Gradle `build.gradle` or `<gradle-project-dir>`
where `<gradle-project-dir>/build.gradle` exists.

If the runtime and environment match an entry in the stager, the service will
be staged into a directory.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file of
    any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will be invoked if there is a runtime
    and environment match.
  appyaml: str or None, the app.yaml location to used for deployment.

Raises:
  staging.StagingCommandFailedError, staging command failed.

Returns:
  Service, fully populated with entries that respect a potentially
      staged deployable service, or None if the path does not match the
      pattern described.
zbuild.gradlezjava-gradle-projectr4   NrL   rN   s	            r   BuildGradleMatcherrR      s    2 ww~~d++t
N2*WWj)(WW^^JH$>ggooj)G,,z4I"||W6K[*5I//88CL:BB	r   c                    [         R                  R                  [         R                  SS5      nU R	                  U5      (       a  U S[        U5      *  OU n[         R                  R                  USS5      n[         R                  R                  U5      (       d  g[        R                  " U5      nSU;   d  SU;   a  [        R                  " S5        UR                  XTS[        R                  U5      nU(       d  g[         R                  R                  US5      n[        R                  R!                  U5      n	[#        XTX5      $ )	a  Generate a Service from an appengine-web.xml source path.

This function is a path matcher that returns if and only if:
- `path` points to either `.../WEB-INF/appengine-web.xml` or `<app-dir>` where
  `<app-dir>/WEB-INF/appengine-web.xml` exists.
- the xml-file is a valid appengine-web.xml file according to the Java stager.

The service will be staged according to the stager as a java-xml runtime,
which is defined in staging.py.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file of
      any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will be invoked if there is a runtime
      and environment match.
  appyaml: str or None, the app.yaml location to used for deployment.

Raises:
  staging.StagingCommandFailedError, staging command failed.

Returns:
  Service, fully populated with entries that respect a staged deployable
      service, or None if the path does not match the pattern described.
zWEB-INFzappengine-web.xmlNz<application>z	<version>zM<application> and <version> elements in `appengine-web.xml` are not respectedzjava-xmlr4   )r5   r   r7   sependswithlenr6   r   ReadFileContentsr   warningr=   r   rG   r   r;   r<   r   )
r   r$   r&   suffixrA   r   xml_filerB   rI   r   s
             r   AppengineWebMatcherr[      s    2 77<<	+>?&#'==#8#8D3v;,d'ww||GY0CD*	
	#	###J/( K8$;KK 8 9 Z*cll$&+	ggll;
3)--66yA,	l	@@r   c                     U(       aI  [         R                  R                  U5      nUR                  X SUR                  U5      n[        X X45      $ g)a  Use optional app.yaml with a directory or a file the user wants to deploy.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file of
    any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will not be invoked.
  appyaml: str or None, the app.yaml location to used for deployment.

Returns:
  Service, fully populated with entries that respect a staged deployable
      service, or None if there is no optional --appyaml flag usage.
zgeneric-copyN)r   r;   r<   r=   r   r   )r   r$   r&   r   rB   s        r   ExplicitAppYamlMatcherr]   ,  sJ     //88AL,,wnl>N>N&(K7,<<	r   c                     AA[         R                  R                  U 5      (       a  [        R                  " [
        5        g)aY  Points out to the user that they need an app.yaml to deploy.

Args:
  path: str, Unsanitized absolute path, may point to a directory or a file of
      any type. There is no guarantee that it exists.
  stager: staging.Stager, stager that will not be invoked.
  appyaml: str or None, the app.yaml location to used for deployment.
Returns:
  None
N)r5   r   isdirr   errorNO_YAML_ERROR)r   r$   r&   s      r   UnidentifiedDirMatcherrb   B  s+     gWW]]4IIm	r   c                  L    [         [        [        [        [        [
        [        /$ )zGet list of path matchers ordered by descending precedence.

Returns:
  List[Function], ordered list of functions on the form fn(path, stager),
  where fn returns a Service or None if no match.
)rC   r[   rJ   rP   rR   r]   rb   r"   r   r   GetPathMatchersrd   S  s!     -z=02H
 r   c                   .    \ rS rSrSrSS jrS rS rSrg)	Servicesi`  z"Collection of deployable services.Nc                 |    [         R                  " 5       U l        U(       a  U H  nU R                  U5        M     gg)zInstantiate a set of deployable services.

Args:
  services: List[Service], optional list of services for quick
      initialization.

Raises:
  DuplicateServiceError: Two or more services have the same service id.
N)collectionsOrderedDict	_servicesAdd)r   servicesds      r   r   Services.__init__c  s1     !,,.DN!  r   c                     U R                   R                  UR                  5      nU(       a6  [        R                  " UR
                  UR
                  UR                  5      eXR                   UR                  '   g)zAdd a deployable service to the set.

Args:
  service: Service, to add.

Raises:
  DuplicateServiceError: Two or more services have the same service id.
N)rj   getr   r   DuplicateServiceErrorr   )r   r(   existings      r   rk   Services.Addr  s]     ~~!!'"4"45H,,X]]GLL-4-?-?A A)0NN7%%&r   c                 H    [        U R                  R                  5       5      $ )zmRetrieve the service info objects in the order they were added.

Returns:
  List[Service], list of services.
)listrj   valuesr   s    r   GetAllServices.GetAll  s     %%'((r   )rj   r   	r+   r,   r-   r.   r/   r   rk   rw   r2   r"   r   r   rf   rf   `  s    *1)r   rf   c                   *    \ rS rSrSrS rS rS rSrg)Configsi  zCollection of config files.c                 8    [         R                  " 5       U l        g r   )rh   ri   _configsr   s    r   r   Configs.__init__  s    ++-DMr   c                     UR                   nU R                  R                  U5      nU(       a,  [        R                  " UR
                  UR
                  U5      eXR                  U'   g)zAdd a ConfigYamlInfo to the set of configs.

Args:
  config: ConfigYamlInfo, the config to add.

Raises:
  exceptions.DuplicateConfigError, the config type is already in the set.
N)configr}   rp   r   DuplicateConfigErrorr   )r   r   config_typerr   s       r   rk   Configs.Add  sR     --K}}  -H++HMM6;;,79 9!'MM+r   c                 H    [        U R                  R                  5       5      $ )z~Retreive the config file objects in the order they were added.

Returns:
  List[ConfigYamlInfo], list of config file objects.
)ru   r}   rv   r   s    r   rw   Configs.GetAll  s     $$&''r   )r}   Nry   r"   r   r   r{   r{     s    #.( (r   r{   c                    U (       d  S/n U  Vs/ s H"  n[         R                  R                  U5      PM$     nn[        5       n[	        5       nU(       a  [        U5      S:  a  [        R                  " 5       e[         R                  R                  [         R                  R                  U5      5      (       d%  [        R                  " SR                  U5      5      e[         R                  R                  US   5      (       d  [        R                  " US   5      eU H  n[         R                  R                  U5      (       d  [        R                  " U5      e[        R                  R                  U5      n	U	(       a  UR                  U	5        Mv  [        R!                  XX#5      n
U
(       a  UR                  U
5        M  [        R"                  " U5      e   UR%                  5       UR%                  5       4$ s  snf )a)  Given a list of args, infer the deployable services and configs.

Given a deploy command, e.g. `gcloud app deploy ./dir other/service.yaml
cron.yaml WEB-INF/appengine-web.xml`, the deployables can be on multiple
forms. This method pre-processes and infers yaml descriptors from the
various formats accepted. The rules are as following:

This function is a context manager, and should be used in conjunction with
the `with` keyword.

1. If `args` is an empty list, add the current directory to it.
2. For each arg:
  - If arg refers to a config file, add it to the configs set.
  - Else match the arg against the path matchers. The first match will win.
    The match will be added to the services set. Matchers may run staging.

Args:
  args: List[str], positional args as given on the command-line.
  stager: staging.Stager, stager that will be invoked on sources that have
      entries in the stager's registry.
  path_matchers: List[Function], list of functions on the form
      fn(path, stager) ordered by descending precedence, where fn returns
      a Service or None if no match.
  appyaml: str or None, the app.yaml location to used for deployment.

Raises:
  FileNotFoundError: One or more argument does not point to an existing file
      or directory.
  UnknownSourceError: Could not infer a config or service from an arg.
  DuplicateConfigError: Two or more config files have the same type.
  DuplicateServiceError: Two or more services have the same service id.

Returns:
  Tuple[List[Service], List[ConfigYamlInfo]], lists of deployable services
  and configs.
.   z0File {0} referenced by --appyaml does not exist.r   )r5   r   rE   r{   rf   rV   r   MultiDeployErrorr9   FileNotFoundErrorformatr   ConfigYamlInfor<   rk   r   r)   UnknownSourceErrorrw   )argsr$   r%   r&   argpathsconfigsrl   r   r   r(   s              r   GetDeployablesr     su   J 
5D+/
04C277??34%
0I'Z(
5zA~''))77>>"''//'233(( *;;A6'?L L77>>%(##((q22d77>>$((..((11$7Fkk&t]DGll7

'
'
--  
	GNN,	,,1 1s   )G?r   )r/   rh   r5   googlecloudsdk.api_lib.appr   r   googlecloudsdk.command_lib.appr   googlecloudsdk.corer   googlecloudsdk.core.utilr   _STANDARD_APP_YAML_URL_FLEXIBLE_APP_YAML_URLr   APP_YAML_INSTRUCTIONSFINGERPRINTING_WARNINGra   objectr   rC   rJ   rP   rR   r[   r]   rb   rd   rf   r{   r   r"   r   r   <module>r      s     	 * 3 5 # * J  J I&$*@&A  ; G 5f 5p$ND"J#L+A\,"
')v ')T(f (>?-r   