
    V4                         S r SSKrSSKrSSKJ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Jr   " S	 S
5      rg)z'Utilities for app migrate gen1-to-gen2.    N)path)
exceptions)log)
properties)yaml)filesc                   n    \ rS rSrSrSrSrSrSrSr	Sr
S	rS
rS rS rS rS rS rS rS rS rS rSrg)Gen1toGen2Migration   zCUtility class for migrating Gen 1 App Engine applications to Gen 2.zapp.yamlzmigration_progress.jsondefault)python27servicer   app_yamlprocessed_filesc                 X   [         R                  " U5        Xl        [        R                  " 5       U l        UR                  (       a/  [        R                  R                  UR                  5      U l	        OO[         R                  " S5        [        R                  R                  U R
                  U R                  5      U l	        [        R                  R                  UR                  5      U l        [        R                   R"                  R$                  R'                  5       U l        g)zInitializes the Gen1toGen2Migration utility class.

Args:
  api_client: The AppEngine API client.
  args: The argparse arguments.
z:appyaml not provided. Using app.yaml in current directory.N)r   debug
api_clientosgetcwd	input_dirappyamlr   relpathappyaml_pathinfojoinDEFAULT_APPYAMLabspath
output_dirr   VALUEScoreprojectGet)selfr   argss      4lib/googlecloudsdk/command_lib/app/migration_util.py__init__Gen1toGen2Migration.__init__+   s     IIdO OYY[DN ||''//$,,7d	hhKL'',,t~~t7K7KLdggoodoo6DO$$))11557DL    c                 D   U R                  5       nUR                  U R                  5      (       a  UR                  U R                  5      nO+U R                  n[        R
                  R                  S5        [        R                  " SR                  U5      5        U R                  R                  X R                  5      (       d   [        R                  " U R                  5      eU R                  5       nU(       a  U R                  U5        gU R!                  U5        g)zStarts the migration process.

Raises:
  MissingGen1ApplicationError: If the provided project does not contain an
  AppEngine version with a Gen1 runtime.
z:Service name not found in app.yaml. Using default service.zservice_name: {0}N)ValidateAppyamlAndGetContentsgetSERVICE_FIELDDEFAULT_SERVICE_NAMEr   statusPrintr   formatr   CheckGen1AppIdr!   r   MissingGen1ApplicationError)CheckOutputDirectoryAndGetMigrationStatusStartNewMigrationResumeMigration)r#   app_yaml_contentservice_nameis_new_migrations       r%   StartMigration"Gen1toGen2Migration.StartMigration?   s     99;D..//%))$*<*<=l..l	jj
F HH ''56 ??)),EE224<<@@ EEG
\*
<(r(   c                 d   [         R                  " U R                  5      (       d   [        R                  " U R                  5      e[
        R                  " U R                  5      nUR                  S5      U R                  ;  a+  [        R                  " U R                  U R                  5      eU$ )zValidates the app.yaml file and returns its contents.

Returns:
  The contents of the app.yaml file.

Raises:
  FileNotFoundError: If the app.yaml file is not found.
  UnsupportedRuntimeError: If the runtime in app.yaml is not a valid Gen 1
  runtime.
runtime)
r   existsr   r   FileNotFoundErrorr   	load_pathr+   SUPPORTED_GEN1_RUNTIMESUnsupportedRuntimeError)r#   appyaml_contents     r%   r*   1Gen1toGen2Migration.ValidateAppyamlAndGetContents]   s     ;;t(())(():):;; nnT%6%67O9%T-I-II..


T99  r(   c                    [         R                  R                  U R                  5      (       dP  [         R                  " U R                  5        [
        R                  " SR                  U R                  5      5        g[         R                  " U R                  5      (       d0  [
        R                  " SR                  U R                  5      5        gU R                  [         R                  " U R                  5      ;   a0  [
        R                  " SR                  U R                  5      5        g[        R                  " U R                  5      e)an  Check if output directory exists and decide the migration status.

If an output directory does not exist, we create one and decide that it is a
new migration.

Returns:
  Boolean: True for new migration, False for resuming migration.

Raises:
  InvalidOutputDirectoryError: If the output directory is not empty and does
  not contain a migration_progress.json file.
zCreating directory: {0}TzOutput directory {0} is empty.z8Output directory {0} is not empty. Resuming migration...F)r   r   r=   r   makedirsr   r   r0   listdirMIGRATION_PROGRESS_FILEwarningr   InvalidOutputDirectoryError)r#   s    r%   r3   =Gen1toGen2Migration.CheckOutputDirectoryAndGetMigrationStatusu   s     77>>$//**kk$//"	hh(//@A ::doo&&	hh/66tGH ##rzz$//'BB	kk
D
K
Koo
  
0
0
AAr(   c                 ^   [         R                  " SR                  U R                  5      5        [        R
                  R                  U R                  5      n[        R                  " U R                  U R                  [        R                  " SU[        R                  " U R                  5      R                  5      SS9  [         R                  R!                  S5        [        R
                  R#                  U R                  U R$                  5      n0 nU R'                  U[        R
                  R#                  U R                  U5      UU5        [        R
                  R#                  U R                  S5      nU R)                  XX55        [         R                  R!                  S5        g)	zLFlow for starting a new migration.

Args:
  service_name: The service name.
input_dir: {0}z*.pyT)ignoredirs_exist_okz!Copying files to output directoryrequirements.txtMigration completed.N)r   r   r0   r   r   r   basenamer   shutilcopytreer   ignore_patternspathlibPurePathnamer.   r/   r   rG   WriteMigratedYamlWriteMigratedCode)r#   r7   appyaml_filenameprogress_filemigration_progressrequirements_files         r%   r4   %Gen1toGen2Migration.StartNewMigration   s6    HH$$T^^45ww''(9(9: OO%%$g&6&6t&G&L&L
  JJ89 GGLL$2N2NOM 	
T__&67	 T__6HI- JJ+,r(   c           	      r   [         R                  " SR                  U R                  5      5        [        R
                  R                  U R                  U R                  5      n[        R                  " U5       n[        R                  " U5      nSSS5        U R                  WR                  SS5      ;  a  [         R                  " SR                  U R                  5      5        U R                  U[        R
                  R                  U R                  [        R
                  R!                  U R                  5      5      UU5        [        R
                  R                  U R                  S5      nU R#                  XX%5        [         R$                  R'                  S5        g! , (       d  f       GN= f)zFlow for a resumed migration.

Args:
  service_name: The service name.

Raises:
  InvalidOutputDirectoryError: If the output directory is not empty and does
  not contain a migration_progress.json file.
rL   Nr    z8{0} not present in migration_progress. Will be migrated.rO   rP   )r   r   r0   r   r   r   r   r   rG   r   
FileReaderjsonloadr   r+   rX   rQ   rY   r.   r/   )r#   r7   r[   pfr\   r]   s         r%   r5   #Gen1toGen2Migration.ResumeMigration   s5    HH$$T^^45 GGLL$2N2NOM			-	(B99R= 
)  2 6 6z2 FF	hh
D
K
K
 

'',,t(8(89J9J(K
L

	 T__6HI- JJ+,- 
)	(s   :F''
F6c                    [         R                  " U R                  5      n[        R                  R                  U R                  5      nU R                  R                  U R                  XPR                  U5      n[        R                  " UR                  5      n[         R                  " U5       n	[        R                  " X5        SSS5        U R                  X0R                  '   [         R                  " US5       n
[         R                  " X:SS9  SSS5        ["        R$                  R'                  SR)                  U5      5        g! , (       d  f       N= f! , (       d  f       NN= f)a  Writes the migrated app.yaml to the output directory.

Args:
  service_name: The service name.
  output_path: The path to the output directory.
  migration_progress: The migration progress dictionary.
  progress_file: The path to the migration progress file.
Nw   indentz$Config modifications applied to {0}.)r   ReadFileContentsr   r   r   rQ   r   MigrateConfigYamlr!   PYTHON_GEN1_RUNTIMEr   rc   configAsString
FileWriterdumpAPP_YAML_FIELDrb   r   r.   r/   r0   )r#   r7   output_pathr\   r[   rB   rZ   responsemigrated_yaml_contentsfrd   s              r%   rX   %Gen1toGen2Migration.WriteMigratedYaml   s    ,,T->->?Oww''(9(9:00o'?'?H "YYx'>'>?			+	&!
ii&* 
' /3.?.?**+			-	-
ii"q1 
.JJ.556FG 
'	&
 
.	-s   1E?E
E
E+c           	      (   [         R                  " U R                  5       GHU  u  pVnU Vs/ s H5  nU[        R                  " U R
                  5      R                  :w  d  M3  UPM7     snUSS& U GH  n	[         R                  R                  XY5      n
[        R                  " U
5      R                  S:X  d  MI  U R                  U;   a9  XU R                     ;   a'  [        R                  " SR                  U
5      5        M  [        R                  R!                  SR                  U
5      5        ["        R$                  " U
5      nU R'                  X5      u  p[         R                  R                  U R
                  [         R                  R)                  XR                  5      5      n/ n[         R                  R+                  U5      (       a.  ["        R$                  " U5      nU(       a  UR-                  S5      nU H  nUU;  d  M  UR/                  U5        M     ["        R0                  " USR                  U5      5        [         R                  R+                  U5      (       a  [         R                  R3                  U5      S   S-   [5        [6        R6                  " 5       5      R-                  S5      S   -   S-   n[        R8                  " S	R                  U
U5      5        Un["        R0                  " XS
S9  U R                  U;  a  / X R                  '   X R                     R/                  U
5        ["        R:                  " US5       n[<        R>                  " UUSS9  SSS5        GM     GMX     gs  snf ! , (       d  f       GM!  = f)a  Writes the migrated code to the output directory.

Args:
  service_name: The service name.
  migration_progress: The migration progress dictionary.
  progress_file: The path to the migration progress file.
  requirements_file: The path to the requirements file.
Nz.pyz)File {0} already exists. Will be skipped.zCurrently on file: {0}
r   _.z0File {0} already exists. Will be renamed to {1}.F)	overwriterg   rh   ri   ) r   walkr   rU   rV   r   rW   r   r   PathsuffixPROCESSED_FILES_FIELDr   r   r0   r.   r/   r   rk   GetMigratedCoder   r=   splitappendWriteFileContentssplitextstrtimerH   ro   rb   rp   )r#   r7   r\   r[   r]   dirpathdirname	filenamesdfilename	file_pathfile_contenttransformed_coderequirements_listrr   existing_requirementsrequirements_file_contentsrequirementnew_output_pathrd   s                       r%   rY   %Gen1toGen2Migration.WriteMigratedCode  s    (*wwt~~'>#) a'""4??3888 gaj
  (GGLL3	<<	"))U2 ((,>>$2L2LMMHH;BB9M 
**

3::9E
F//	:,040D0D1
-
 oorwwy..I+ #%
WW^^-..).)?)?!*& *&@&F&Ft&L# /k"77#**;7 / 
!
!+@!A WW^^K((  -a0diik"((-a01   KKBII
 *K

!
!u
 ''/AA=?99:
77
8
?
?	
Js3rII("Q7 43{   (?D 43s   2M<"M<N
Nc                    U R                   R                  U R                  XR                  U5      nSn/ nUR                  R
                  nU H  nUR                  S:X  a  UR                  R                  nUR                  S:X  d  M;  UR                  R                  R                  nU H,  n	UR                  U	R                  R                  5       5        M.     M     XE4$ )a&  Calls MigrateCodeFile and gets the migrated code for a python file.

Args:
  file_content: The contents of the python file.
  service_name: The service name.

Returns:
  transformed_code: The migrated code for the python file.
  requirements_list: The list of requirements for the python file.
r`   codeAsStringpython3Requirements)r   MigrateCodeFiler!   rm   rs   additionalPropertieskeyvaluestring_valuearray_valueentriesr   strip)
r#   r   r7   	operationr   r   operation_responseproprequirementsentrys
             r%   r   #Gen1toGen2Migration.GetMigratedCodeV  s     //l$<$<lI "++@@"	^	#::22	*	*zz--55!E

"
"5#5#5#;#;#=
> " # ..r(   )r   r   r   r   r!   N)__name__
__module____qualname____firstlineno____doc__r   rG   r-   r@   r,   rm   rq   r   r&   r9   r*   r3   r4   r5   rX   rY   r   __static_attributes__ r(   r%   r
   r
      se    K/5")-".+8()<0!BF'-R%-N8P8d/r(   r
   )r   rb   r   r   rU   rR   r   googlecloudsdk.command_lib.appr   googlecloudsdk.corer   r   r   googlecloudsdk.core.utilr   r
   r   r(   r%   <module>r      s7    .  	     5 # * $ *Q/ Q/r(   