o
    i`                     @   s  d dl 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mZ d dlmZ d dlmZmZmZmZ d dlZd dlZd dlZd dlmZ d dlmZmZmZmZ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(m)Z)m*Z* d dl+m,Z,m-Z-m.Z. d dl/m0Z0 d dl1m2Z2m3Z3 e4e5Z6dee7 dee7 fddZ8eee7 ee8f Z9de7ddfddZ:dede7fddZ;dede<fddZ=dededefddZ>G d d! d!eZ?de@e? fd"d#ZAG d$d% d%eZBd&e7d'ee7 deBfd(d)ZCd*e7d+e7d'ee7 deBfd,d-ZDG d.d/ d/e7eZEG d0d1 d1eZFd&e7deFfd2d3ZGG d4d5 d5eZHde7d6eddfd7d8ZId9e7deeB fd:d;ZJd*e7de@eB fd<d=ZKg d>ZLg d?ZMd@e"dAede,fdBdCZNd@e"d&e7dDeFddfdEdFZOG dGdH dHeZPdIePd@e"ddfdJdKZQd@e"ddfdLdMZR		N	d[deeedf ejSdOdPf dQee<ej$dRdSdPf dTeee7df ej$dUdVdWdXf defdYdZZTdS )\    N)Enum)cycle)PathPurePosixPath)dedent)	AnnotatedAnyOptionalUnion)Client)AfterValidator	BaseModelEmailStrTypeAdapterValidationError)Text)RichToolkit)Option)login)	APIClientStreamLogErrorTooManyRetriesError)	AppConfigget_app_configwrite_app_config)Identity)get_rich_toolkithandle_http_errorsvreturnc                 C   sx   | d u rd S |   } | sd S | drtdt| }| r#tdd|jv r,td| }td|s:td|S )N~zcannot start with '~'z%must be a relative path, not absolutez..z!cannot contain '..' path segmentsz[A-Za-z0-9._/ -]+zGcontains invalid characters (allowed: letters, numbers, space, / . _ -))	strip
startswith
ValueErrorr   is_absolutepartsas_posixre	fullmatch)r   path
normalized r+   U/home/ubuntu/.local/lib/python3.10/site-packages/fastapi_cloud_cli/commands/deploy.pyvalidate_app_directory   s$   

r-   deployment_idc              
   C   s   t d|  z*t }|d|  d}|  t d W d    W d S 1 s)w   Y  W d S  tyI } zt d| W Y d }~d S d }~ww )Nz$Cancelling upload for deployment: %s/deployments/z/upload-cancelledz2Upload cancellation notification sent successfullyz5Failed to notify server about upload cancellation: %s)loggerdebugr   postraise_for_status	Exception)r.   clientresponseer+   r+   r,   _cancel_upload@   s   &r8   r)   c                 C   s   | j S N)namer)   r+   r+   r,   _get_app_nameM   s   r<   c                    sN   g d}t  fdd|D rdS  jdkrdS  jdks# jdr%dS dS )	N)z.venv__pycache__z.mypy_cachez.pytest_cachez.gitz
.gitignore.fastapicloudignorec                 3   s    | ]}| j v V  qd S r9   )r%   ).0partr;   r+   r,   	<genexpr>]   s    z(_should_exclude_entry.<locals>.<genexpr>Tz.pycz.envz.env.F)anysuffixr:   r"   )r)   parts_to_excluder+   r;   r,   _should_exclude_entryR   s   

rE   tar_pathc                 C   s   t d|  tj| tdgdd}t d| d}t|d(}|D ]}| r(q!|| }t d| |j	||d	 |d
7 }q!W d    n1 sIw   Y  t d| |S )Nz&Starting archive creation for path: %sr>   F)should_exclude_entryadditional_ignore_pathsignore_hiddenzArchive will be created at: %sr   zw:zstzAdding %s to archive)arcname   z*Archive created successfully with %s files)
r0   r1   rignorewalkrE   fastaropenis_dirrelative_toappend)r)   rF   files
file_counttarfilenamerJ   r+   r+   r,   archivei   s*   


rW   c                   @   s&   e Zd ZU eed< eed< eed< dS )Teamidslugr:   N)__name__
__module____qualname__str__annotations__r+   r+   r+   r,   rX      s   
 rX   c                  C   sR   t  } | d}|  | d }W d    n1 sw   Y  dd |D S )Nz/teams/datac                 S      g | ]}t |qS r+   )rX   model_validater?   teamr+   r+   r,   
<listcomp>       z_get_teams.<locals>.<listcomp>r   getr3   json)r5   r6   r`   r+   r+   r,   
_get_teams   s   
rj   c                   @   s*   e Zd ZU eed< eed< ee ed< dS )AppResponserY   rZ   	directoryN)r[   r\   r]   r^   r_   r	   r+   r+   r+   r,   rk      s   
 rk   app_idrl   c                 C   sX   t  }|jd|  d|id}|  t| W  d    S 1 s%w   Y  d S )N/apps/rl   ri   )r   patchr3   rk   rb   ri   )rm   rl   r5   r6   r+   r+   r,   _update_app   s   $rq   team_idapp_namec                 C   sV   t  }|jd|| |dd}|  t| W  d    S 1 s$w   Y  d S )Nrn   )r:   rr   rl   ro   )r   r2   r3   rk   rb   ri   )rr   rs   rl   r5   r6   r+   r+   r,   _create_app   s   
$rt   c                   @   sZ   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZedd defddZdS )DeploymentStatuswaiting_uploadready_for_buildbuilding
extractingextracting_failedbuilding_imagebuilding_image_failed	deployingdeploying_failed	verifyingverifying_failedverifying_skippedsuccessfailedstatusr   c                 C   s\   | j d| jd| jd| jd| jd| jd| jd| jd| jd	| j	d
| j
d| jd| jd| jdi| S )NzWaiting for uploadzReady for buildBuilding
ExtractingzExtracting failedzBuilding imagezBuild failed	DeployingzDeploying failed	VerifyingzVerifying failedzVerification skippedSuccessFailed)rv   rw   rx   ry   rz   r{   r|   r}   r~   r   r   r   r   r   )clsr   r+   r+   r,   to_human_readable   s"   z"DeploymentStatus.to_human_readableN)r[   r\   r]   rv   rw   rx   ry   rz   r{   r|   r}   r~   r   r   r   r   r   classmethodr^   r   r+   r+   r+   r,   ru      s"    ru   c                   @   s>   e Zd ZU eed< eed< eed< eed< eed< eed< dS )CreateDeploymentResponserY   rm   rZ   r   dashboard_urlurlN)r[   r\   r]   r^   r_   ru   r+   r+   r+   r,   r      s   
 r   c                 C   sR   t  }|d|  d}|  t| W  d    S 1 s"w   Y  d S )Nrn   r/   )r   r2   r3   r   rb   ri   )rm   r5   r6   r+   r+   r,   _create_deployment   s
   $r   c                   @   s&   e Zd ZU eed< eeef ed< dS )RequestUploadResponser   fieldsN)r[   r\   r]   r^   r_   dictr+   r+   r+   r,   r      s   
 r   archive_pathc           	   
   C   sN  t d|  t d|| j t }t n}t d |d|  d}|  t	|
 }t d|j t d t|d}|j|j|jd	|id
}W d    n1 sYw   Y  |  t d t d |d|  d}|  t d W d    n1 sw   Y  W d    d S W d    d S 1 sw   Y  d S )Nz-Starting deployment upload for deployment: %sz Archive path: %s, size: %s byteszRequesting upload URL from APIr/   z/uploadzReceived upload URL: %szStarting file upload to S3rbfile)r`   rS   z"File upload completed successfullyz%Notifying API that upload is completez/upload-completez%Upload notification sent successfully)r0   r1   statst_sizer   r   r2   r3   r   rb   ri   r   rO   r   )	r.   r   fastapi_clientr5   r6   upload_dataarchive_fileupload_responsenotify_responser+   r+   r,   _upload_deployment   s@   




Pr   app_slugc                 C   sl   t  &}|d|  }|jdkr	 W d    d S |  | }W d    n1 s,w   Y  t|S )Nrn   i  )r   rh   status_coder3   ri   rk   rb   )r   r5   r6   r`   r+   r+   r,   _get_app  s   



r   c                 C   sZ   t  }|jdd| id}|  | d }W d    n1 s!w   Y  dd |D S )Nrn   rr   )paramsr`   c                 S   ra   r+   )rk   rb   r?   appr+   r+   r,   re   )  rf   z_get_apps.<locals>.<listcomp>rg   )rr   r5   r6   r`   r+   r+   r,   	_get_apps"  s   r   )
u+   🚀 Preparing for liftoff! Almost there...uA   👹 Sneaking past the dependency gremlins... Don't wake them up!u>   🤏 Squishing code into a tiny digital sandwich. Nom nom nom.u;   🐱 Removing cat videos from our servers to free up space.uM   🐢 Uploading at blazing speeds of 1 byte per hour. Patience, young padawan.uN   🔌 Connecting to server... Please stand by while we argue with the firewall.uQ   💥 Oops! We've angered the Python God. Sacrificing a rubber duck to appease it.u3   🧙 Sprinkling magic deployment dust. Abracadabra!uB   👀 Hoping that @tiangolo doesn't find out about this deployment.uF   🍪 Cookie monster detected on server. Deploying anti-cookie shields.)uS   😅 Well, that's embarrassing. We're still waiting for the deployment to finish...u9   🤔 Maybe we should have brought snacks for this wait...u   🥱 Yawn... Still waiting...uK   🤯 Time is relative... Especially when you're waiting for a deployment...toolkitpath_to_deployc              	   C   s  | j d| ddd |   | d!}t|dd t }W d    n1 s)w   Y  W d    n1 s8w   Y  |   | jdd	d
d |D d}|   | jdddd}|   d }|s| d#}t|dd t|j}W d    n1 s~w   Y  W d    n1 sw   Y  |   |s|  d t	
d| jddd |D d}|r|jn| jdt|d}|   |r|jnd}	| jdd|	pddttd}
|
r|
nd }|   | j dd d |   |  d!|j d" |  d#| d" |  d$|pd% d" |   | jd&d'td(d)d*td+d,d*gd}|   |d,kr4|  d- t	
d.|r||jkr}| jd/d00}t| t|j|d1}|d2|pWd% d3 W d    n	1 sgw   Y  W d    n	1 sww   Y  n@|}n=| jd4d0.}t| t|j||d1}W d    n	1 sw   Y  |d5|j  W d    n	1 sw   Y  t|j|jd6}t|| |S )7NzSetting up and deploying [blue]z[/blue]r)   tagzFetching teams...z-Error fetching teams. Please try again later.)default_messagez&Select the team you want to deploy to:rd   c                 S      g | ]
}t |j|d qS r:   value)r   r:   rc   r+   r+   r,   re   Q      z"_configure_app.<locals>.<listcomp>r   optionsz Do you want to create a new app?r   T)r   defaultzFetching apps...z,Error fetching apps. Please try again later.z=No apps found in this team. You can create a new app instead.rK   z%Select the app you want to deploy to:c                 S   r   r   )r   rZ   r   r+   r+   r,   re   p  r   )r   zWhat's your app name?)titler    z>Path to the directory containing your app (e.g. src, backend):dirz:[italic]Leave empty if it's the current directory[/italic])r   r   r   placeholder	validatorzDeployment configuration:summaryzTeam: [bold]z[/bold]zApp name: [bold]zDirectory: [bold].zDoes everything look right?confirmzYes, start the deployment!deployr   zNo, let me start overcancelzDeployment cancelled.r   zUpdating app directory...r   )rl   zApp directory updated to ''zCreating app...z$App created successfully! App slug: )rm   rr   )print
print_lineprogressr   rj   askr   r   rY   typerExitrZ   inputr<   rl   r   AppDirectoryr:   r   rq   logrt   r   r   )r   r   r   teamsrd   create_new_appselected_appappsrs   initial_directorydirectory_inputrl   choicer   
app_configr+   r+   r,   _configure_appA  s   
	



 

r   
deploymentc                 C   s&  t t}| jddd |   | d|j d|j d |   d}t }t }| jt|dd	d
}t	 }z|
|jD ]{}	t | }|	jdkrY|t|	j  |	jdkr|d |d|j d|j d |d |d|j d|j d  n7|	jdkr|d |d|j d|j d td|dkrt t}t | dkrt||_t }qAW n* tttfy }
 z|td|
 d|j d|j d  tdd d }
~
ww W d    n1 sw   Y  W d    d S W d    d S 1 sw   Y  d S )Nu+   Checking the status of your deployment 👀cloudr   z'You can also check the status at [link=][/link]g        T   )inline_logslines_to_showmessagecompleter   z)You can also check the app logs at [link=u3   🐔 Ready the chicken! Your app is ready at [link=r   u>   😔 Oh no! Something went wrong. Check out the logs at [link=rK         z4
                [error]Build log streaming failed: zX[/]

                Unable to stream build logs. Check the dashboard for status: [link=z[/link]
                )r   WAITING_MESSAGESr   r   r   time	monotonicr   nextr   stream_build_logsrY   typer   r   	from_ansir   rstripr   r   r   LONG_WAIT_MESSAGESr   r   r   TimeoutError	set_errorr   r!   )r   rm   r   messagestime_elapsed
started_atlast_message_changed_atr   r5   r   r7   r+   r+   r,   _wait_for_deployment  s   








Rr   c                   @   s   e Zd ZU eed< dZee ed< dZee ed< dZ	ee ed< dZ
ee ed< dZee ed< dZee ed< dZee ed	< dS )
SignupToWaitingListemailNr:   organizationrole	team_sizelocationuse_casesecret_code)r[   r\   r]   r   r_   r:   r	   r^   r   r   r   r   r   r   r+   r+   r+   r,   r     s   
 r   resultc              
   C   s   | dB}t )}t| |jd|  d}|  W d    n1 s&w   Y  W d    n1 s5w   Y  |d W d    d S 1 sJw   Y  d S )NzSending your request...z/users/waiting-listro   u9   Let's go! Thanks for your interest in FastAPI Cloud! 🚀)r   r   r   r2   
model_dumpr3   r   )r   r   r   r5   r6   r+   r+   r,   _send_waitlist_form  s   

"r   c                 C   s  ddl m} | jddd |   | jddttd}|   td	|i}| j	d
ddr|   |d| j
d}|jdddd |jdddd |jdddd |jdddd |jdddd |jdddd |jd d!d"d | }ztd	|i|}W n ty   | d# Y d S w |   | j	d$d%dr|   t||  tt tjg d&tjtjd'd( W d    d S 1 sw   Y  d S d S ))Nr   )FormzkWe're currently in private beta. If you want to be notified when we launch, please fill out the form below.waitlistr   zEnter your email:T)requiredr   r   z?Do you want to get access faster by giving us more information?zWaitlist form)styler:   NamezJohn Doe)labelr   r   Organizationz	Acme Inc.rd   rX   zTeam Ar   Role	Developerr   LocationzSan Franciscor   z%How do you plan to use FastAPI Cloud?zI'm building a web appr   zSecret code123456z.[error]Invalid form data. Please try again.[/]zDo you agree to
- Terms of Service: [link=https://fastapicloud.com/legal/terms]https://fastapicloud.com/legal/terms[/link]
- Privacy Policy: [link=https://fastapicloud.com/legal/privacy-policy]https://fastapicloud.com/legal/privacy-policy[/link]
terms)rO   z-gu!   raycast://confetti?emojis=🐔⚡F)stdoutstderrcheck)rich_toolkit.formr   r   r   r   r   r   r   rb   r   r   	add_inputrunr   r   
contextlibsuppressr4   
subprocessDEVNULL)r   r   r   r   formr+   r+   r,   _waitlist_form   s~   "r  Fz:A path to the folder containing the app you want to deploy)help	skip_waitz	--no-waitz"Skip waiting for deployment statusprovided_app_idz--app-idzApplication ID to deploy toFASTAPI_CLOUD_APP_ID)r  envvarc                 C   s  t d t d| || t }t }| sht d |jddd |  |jr8| r8|j	ddd n|j	d	dd |  |j
d
dtdddtdddgd}|dkr_t  n	t| td|jddd |  | pxt }t d| t|}|r|r|j|kr|	d| d|j d |  |j	ddd tdd|r|}n|r|j}nt d t||d}|  |j}|r|	d| d n|	d |  |jd d!d"3}	t|	 t d#| t|}
W d   n1 sw   Y  |
st d$ |	d% W d   n	1 sw   Y  |
s5|  |s0|j	d&dd tdt }t d' t|d( }t| pLt | |jd)d*S}	t|	> t d+|
j t|
j}z|	d,|j  |	d- t |j| |	d. W n t!y   t"|j  w W d   n	1 sw   Y  W d   n	1 sw   Y  W d   n	1 sw   Y  |  |st d/ t#||
j|d0 nt d1 |	d2|j$ d3|j$ d4 W d   dS W d   dS 1 sw   Y  dS )5uB   
    Deploy a [bold]FastAPI[/bold] app to FastAPI Cloud. 🚀
    zDeploy command startedz*Deploy path: %s, skip_wait: %s, app_id: %sz3User not logged in, prompting for login or waitlistzWelcome to FastAPI Cloud!FastAPIr   z.Your session has expired. Please log in again.infoz4You need to be logged in to deploy to FastAPI Cloud.zWhat would you like to do?authzLogin to my existing accountr   r   zJoin the waiting listr   r   rK   zStarting deploymentzDeploying from path: %sz[error]Error: Provided app ID (z#) does not match the local config (z).[/]zRun [bold]fastapi cloud unlink[/] to remove the local config, or remove --app-id / unset FASTAPI_CLOUD_APP_ID to use the configured app.tipNz(No app config found, configuring new app)r   zDeploying to app [blue]z
[/blue]...zDeploying app...zChecking app...T)	transientzChecking app with ID: %szApp not found in APIz>App not found. Make sure you're logged in the correct account.zeIf you deleted this app, you can run [bold]fastapi cloud unlink[/] to unlink the local configuration.zCreating archive for deploymentzarchive.tarzCreating deploymentr   zCreating deployment for app: %sz2Deployment created successfully! Deployment slug: zUploading deployment...z!Deployment uploaded successfully!z"Waiting for deployment to complete)r   z%Skipping deployment wait as requestedz-Check the status of your deployment at [link=r   r   )%r0   r1   r   r   is_logged_inprint_titler   token
is_expiredr   r   r   r   r  r   r   r   cwdr   rm   r   r   r   r   r   tempfileTemporaryDirectoryrW   rY   r   r   rZ   r   KeyboardInterruptr8   r   r   )r)   r  r  identityr   r   r   r   target_app_idr   r   temp_dirr   r   r+   r+   r,   r   q  s   


	













 

 ~$r   )NFN)Ur
  loggingr'   r  r  r   enumr   	itertoolsr   pathlibr   r   textwrapr   typingr   r   r	   r
   rN   rL   r   httpxr   pydanticr   r   r   r   r   	rich.textr   rich_toolkitr   rich_toolkit.menur    fastapi_cloud_cli.commands.loginr   fastapi_cloud_cli.utils.apir   r   r   fastapi_cloud_cli.utils.appsr   r   r   fastapi_cloud_cli.utils.authr   fastapi_cloud_cli.utils.clir   r   	getLoggerr[   r0   r^   r-   r   r8   r<   boolrE   rW   rX   listrj   rk   rq   rt   ru   r   r   r   r   r   r   r   r   r   r   r   r   r  Argumentr   r+   r+   r+   r,   <module>   s    

$	)
z
L
W


