
    h              
       (   S SK r S SK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
JrJrJr  S SKJr  SSKJr  SSKJrJrJrJr  SSKJrJrJr  \
(       a  S S	KJr   " S
 S5      rS\S\4S jrS\S\S\\   S\\   S\4
S jrS r S\\\4   S\4S jr!g)    N)Path)TYPE_CHECKINGDictListOptional)msg   )Errors)check_spacy_env_varsdownload_fileensure_pathyget_checksum)get_hashmake_tempdirupload_file)	CloudPathc            
           \ rS rSrSrSS.S\S\4S jjrS\S	\S
\SS4S jrSSS.S\S	\	\   S
\	\   S\	S   4S jjr
SSS.S\S	\	\   S
\	\   S\	S   4S jjrS\S	\S
\SS4S jrS\S\4S jrSrg)RemoteStorage   zPush and pull outputs to and from a remote file storage.

Remotes can be anything that `smart_open` can support: AWS, GCS, file system,
ssh, etc.
gz)compressionproject_rooturlc                <    Xl         [        U5      U l        X0l        g N)rootr   r   r   )selfr   r   r   s       S/home/james-whalen/.local/lib/python3.13/site-packages/weasel/cli/remote_storage.py__init__RemoteStorage.__init__   s     	$&    pathcommand_hashcontent_hashreturnr   c                 :   U R                   U-  nUR                  5       (       d  [        SU S35      eU R                  XU5      nUR                  5       (       a  U$ [	        5        nX`R                  [        U5      5      -  nU R                  (       a  SU R                   3OSn[        R                  " XxS9 n	U	R                  [        U5      [        U5      S9  SSS5        [        Xu5        SSS5        U$ ! , (       d  f       N#= f! , (       d  f       U$ = f)a  Compress a file or directory within a project and upload it to a remote
storage. If an object exists at the full URL, nothing is done.

Within the remote storage, files are addressed by their project path
(url encoded) and two user-supplied hashes, representing their creation
context and their file contents. If the URL already exists, the data is
not uploaded. Paths are archived and compressed prior to upload.
zCannot push z: does not exist.zw:wmode)arcnameN)r   existsIOErrormake_urlr   encode_namestrr   tarfileopenaddr   )
r   r"   r#   r$   locr   tmptar_locmode_stringtar_files
             r   pushRemoteStorage.push    s     ii$zz||L->?@@mmD=::<<J^s,,SY77G595E5EBt//013Kg8HSXs4y9 9%  
 98 ^ 
s%   'AD:#C:D:
D	D
DNr#   r$   c                D  ^ U R                   U-  nUR                  5       (       a  gU R                  XUS9nUc  U$ UR                  R                  5       (       d  UR                  R	                  SS9  [        5        nXeR                  S   -  n[        XW5        U R                  (       a  SU R                   3OSn[        R                  " XxS9 n	S	 mU4S
 jn
U
" XR                   5        SSS5        SSS5        U$ ! , (       d  f       N= f! , (       d  f       U$ = f)zRetrieve a file from the remote cache. If the file already exists,
nothing is done.

If the command_hash and/or content_hash are specified, only matching
results are returned. If no results are available, an error is raised.
Nr:   T)parentszr:rr(   c                     [         R                  R                  U 5      n[         R                  R                  U5      n[         R                  R                  X#/5      nXB:H  $ r   )osr"   abspathcommonprefix)	directorytargetabs_directory
abs_targetprefixs        r   is_within_directory/RemoteStorage.pull.<locals>.is_within_directoryZ   sF    (*	(B%'WW__V%<
!#!5!5}6Q!R%66r!   c                 >  > U R                  5        HR  n[        R                  R                  XR                  5      nT" X5      (       a  M;  [        [        R                  5      e   [        R                  S:  a  U R                  USS9  g U R                  U5        g )N)      data)filter)
getmembersr@   r"   joinname
ValueErrorr
   E201sysversion_info
extractall)tarr"   membermember_pathrH   s       r   safe_extract(RemoteStorage.pull.<locals>.safe_extract`   sp    &)nn&6F*,'',,t[[*IK#6t#I#I&0&= = '7 ++w6NN4N?NN40r!   )r   r+   findparentmkdirr   partsr   r   r0   r1   )r   r"   r#   r$   destr   r4   r5   r6   r7   rZ   rH   s              @r   pullRemoteStorage.pull8   s     yy4;;==iiliS;J ;;%%''!!$!/3		"-c+9=9I9I4#3#3"45s\\'<71 !995- =	  6 
/ =<	  6 
s%   >ADC?-D?
D		D
Dc                   U R                  [        U5      5      n/ nUb3  Ub0  U R                  U-  U-  U-  nUR                  5       (       a  U/O/ nOUbO  U R                  U-  U-  R                  5       (       a)  [	        U R                  U-  U-  R                  5       5      nOU R                  U-  R                  5       (       al  U R                  U-  R                  5        H"  nUR                  UR                  5       5        M$     Ub&  U Vs/ s H  ofR                  S   U:X  d  M  UPM     nn[        U5      S:  a   UR                  S S9  U(       a  US   $ S$ s  snf ! [         a    [        R                  " S5         N5f = f)zFind the best matching version of a file within the storage,
or `None` if no match can be found. If both the creation and content hash
are specified, only exact matches will be returned. Otherwise, the most
recent matching file is preferred.
Nr=   r	   c                 6    U R                  5       R                  $ r   )statst_mtime)xs    r   <lambda>$RemoteStorage.find.<locals>.<lambda>   s    (9(9r!   )keyzkUnable to sort remote files by last modified. The file(s) pulled from the cache may not be the most recent.)r.   r/   r   r+   listiterdirextendr_   lensort	Exceptionr   warn)r   r"   r#   r$   rQ   urlsr   sub_dirs           r   r\   RemoteStorage.findm   s\    D	*#(@((T/L0<?CJJLLC5bD%4,.6688TXX_|;DDFG4'')) $488:GKK 12  ;++/Q4C99R=L3PC4DQt9>		9	:  tBx)T) R  Hs   E!+E!E& & F	F	c                 \    U R                   U R                  [        U5      5      -  U-  U-  $ )zCConstruct a URL from a subpath, a creation hash and a content hash.)r   r.   r/   )r   r"   r#   r$   s       r   r-   RemoteStorage.make_url   s*    xx$**3t955D|SSr!   rQ   c                 @    [         R                  R                  U5      $ )z&Encode a subpath into a URL-safe name.)urllibparse
quote_plus)r   rQ   s     r   r.   RemoteStorage.encode_name   s    ||&&t,,r!   )r   r   r   )__name__
__module____qualname____firstlineno____doc__r   r/   r   r8   r   ra   r\   r-   r.   __static_attributes__ r!   r   r   r      s     EI 'T ' '
 S   8 '+&*33 sm	3
 sm3 
+	3r '+&*"*"* sm	"*
 sm"* 
+	"*HTT T TC TK T- - -r!   r   r3   r%   c                     [        U 5      $ r   )r   )r3   s    r   get_content_hashr      s    r!   	site_hashenv_hashdepscmdc                    [        5         [        U5       Vs/ s H  n[        U5      PM     nnX/U-   nUR                  U5        SR	                  U5      R                  S5      n[        R                  " U5      R                  5       $ s  snf )zCreate a hash representing the execution of a command. This includes the
currently installed packages, whatever environment variables have been marked
as relevant, and the command.
 utf8)	r   sortedr   rm   rP   encodehashlibmd5	hexdigest)r   r   r   r   depdep_checksumshashescreation_bytess           r   get_command_hashr      sv     28,?,3\#&,M?"]2F
MM#WWV_++F3N;;~&0022	 @s   B
c                  H   [         R                  " 5       n [         R                  (       a$  U R                  [         R                  " 5       5        [        5       nU  Hx  n[        U5      nUR                  5        HV  nUR                  S   R                  S5      (       d  M(  UR                  UR                  S   R                  SS5      5        MX     Mz     SR                  [        U5      5      R                  S5      n[        R                   " U5      R#                  5       $ )zHash the current Python environment's site-packages contents, including
the name and version of the libraries. The list we're hashing is what
`pip freeze` would output.
r=   z	dist-infoz
.dist-infor   r   )sitegetsitepackagesENABLE_USER_SITErm   getusersitepackagessetr   rl   r_   endswithr2   replacerP   r   r   r   md5sumr   )	site_dirspackagessite_dirsubpathpackage_bytess        r   get_site_hashr      s    
 $$&I1134uH>'')G}}R ))+66W]]2.66|RHI * 
 GGF8,-44V<M>>-(2244r!   envc                     0 nU R                  5        HF  u  p#UR                  S5      (       a'  [        R                  R	                  USS S5      X'   MB  X1U'   MH     [        U5      $ )zConstruct a hash of the environment variables that will be passed into
the commands.

Values in the env dict may be references to the current os.environ, using
the syntax $ENV_VAR to mean os.environ[ENV_VAR]
$   Nr   )items
startswithr@   environgetr   )r   env_varsrj   values       r   get_env_hashr      s\     Hiik
C  JJNN59b9HM!SM	 "
 Hr!   )"r   r@   r   rT   r0   urllib.parserx   pathlibr   typingr   r   r   r   wasabir   errorsr
   utilr   r   r   r   r   r   r   cloudpathlibr   r   r/   r   r   r   r   r   r!   r   <module>r      s     	  
    6 6   R R 6 6&C- C-L$ 3 33!3)-d3:>s)335$d38n  r!   