U
    ee@                     @   s  d 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dlm	Z	 ddl
mZmZ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 e  dd	lmZm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#m$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8m9Z9m:Z: ddl;m<Z<m=Z=m>Z>m?Z? eeej@jAZBeeCZDej@EdeeDdd d'ddZFdd ZGdd ZHdd ZId d! ZJG d"d# d#ejKZLG d$d% d%ZMeNd&kre&  dS )(z
Tool for packaging Python apps for Android
==========================================

This module defines the entry point for command line and programmatic use.
    user_data_dirNwraps)environ)joindirnamerealpathexists
expanduserbasename)platform)check)VersionInvalidVersion)__version__)	Bootstrap)Contextbuild_recipes)Distributionpretty_log_dists)main)get_recipe_order_and_bootstrap)	loggerinfowarningsetup_color	Out_StyleOut_Foreinfo_notify	info_mainshprint)get_dep_names_of_package)Recipe)RECOMMENDED_NDK_APIRECOMMENDED_TARGET_APIprint_recommendations)current_directoryBuildInterruptingExceptionload_sourcermdirtoolsZexternalTc                    s   | j |d}t|ttfs |g}|d kr>|d ddd}dd   fdd|D }|j||rfd	nd |d
d |d krdd fdd|D } fdd|D }|j||rd nd	|dd | jf ||i d S )Ndescriptionr   -_c                 S   s   |  dr| S d|  S )Nr.   z--)
startswithx r3   >/tmp/pip-unpacked-wheel-h4dze4ss/pythonforandroid/toolchain.py
add_dashes;   s    z&add_boolean_option.<locals>.add_dashesc                    s   g | ]} |qS r3   r3   .0r2   r5   r3   r4   
<listcomp>>   s     z&add_boolean_option.<locals>.<listcomp>z(this is the default)
store_true)helpdestactionc                 S   s"   |  d} d| krd|  S d|  S )Nr.   r/   Zno_zno-)lstripr1   r3   r3   r4   add_noC   s    
z"add_boolean_option.<locals>.add_noc                    s   g | ]} |qS r3   r3   r6   )r?   r3   r4   r9   F   s     c                    s   g | ]} |qS r3   r3   r6   r8   r3   r4   r9   G   s     store_false)add_argument_group
isinstancelisttuplestripreplaceadd_argumentset_defaults)parsernamesZno_namesdefaultr<   r-   groupoptsr3   )r5   r?   r4   add_boolean_option3   s0     
  
 rN   c                    s   t   fdd}|S )zDecorator for ToolchainCL methods. If present, the method will
    automatically make sure a dist has been built before continuing
    or, if no dists are present or can be obtained, will raise an
    error.
    c                    sn   | j }|| j |j| j| j| j| jd | j}|j	r\|
 rH|  td t|||  | |f| d S )NZuser_sdk_dirZuser_ndk_dirZuser_android_apiZuser_ndk_apizBNo dist exists that meets your requirements, so one will be built.)ctxZ	set_archs_archsprepare_build_environmentsdk_dirndk_dirandroid_apindk_api_distneeds_buildfolder_existsdeleter   build_dist_from_args)selfargskwrP   distfuncr3   r4   wrapper_funcU   s    z+require_prebuilt_dist.<locals>.wrapper_funcr   )ra   rb   r3   r`   r4   require_prebuilt_distN   s    rc   c              
   C   s,   t j| |jt|j|j|j|j|j|j	dS )z|Parses out any distribution-related arguments, and uses them to
    obtain a Distribution class instance for the build.
    )namerecipesarchsrV   force_buildrequire_perfect_matchallow_replace_dist)
r   get_distribution	dist_namesplit_argument_listrequirementsarchrV   rg   rh   ri   )rP   r]   r3   r3   r4   dist_from_argsh   s    ro   c              	   C   sz  t |j| }t|ddd}t|dkr<|d dkr<g }t| |j||d\}}}t|	t|t kspt
|| _|| _td|j td|j ||_td	|jd
|j td| j tdd
| j tdj| jrdnd| jrdndd || _| | |jr(|   t||| t|ddt|ddd | j  td tdt| j| jj dS )zNParses out any bootstrap related arguments, and uses them to build
    a dist.blacklist_requirements ,   r   )	blacklistzThe selected bootstrap is {}z!# Creating dist with {} bootstrapz,Dist will have name {} and requirements ({}), z7Dist contains the following requirements as recipes: {}z6Dist will also contain modules ({}) installed from pipz;Dist will be build in mode {build_mode}{with_debug_symbols}debugreleasez (with debug symbols))
build_modewith_debug_symbolsprivateNignore_setup_pyF)Zignore_project_setup_pyz6# Your distribution was created successfully, exiting.z!Dist can be found at (for now) {})r   get_bootstrap	bootstrapgetattrsplitlenr   re   setintersectionAssertionErrorZrecipe_build_orderpython_modulesr   formatrd   r    distributionr   r   build_as_debuggablery   prepare_bootstraprX   Zprepare_distr   Zassemble_distributiondist_dir)rP   r_   r]   bsrt   Zbuild_orderr   r3   r3   r4   r[   w   sh       

	

  
r[   c                 C   s   t | sg S td| S )Nz[ ,]+)r   rer   )arg_listr3   r3   r4   rl      s    rl   c                   @   s   e Zd ZdZdd ZdS )NoAbbrevParsera  We want to disable argument abbreviation so as not to interfere
    with passing through arguments to build.py, but in python2 argparse
    doesn't have this option.

    This subclass alternative is follows the suggestion at
    https://bugs.python.org/issue14910.
    c                 C   s   g S Nr3   )r\   option_stringr3   r3   r4   _get_option_tuples   s    z!NoAbbrevParser._get_option_tuplesN)__name__
__module____qualname____doc__r   r3   r3   r3   r4   r      s   r   c                   @   sP  e Zd Zdd Zedd Zdd Zdd Zed	d
 Z	edd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zedd  Zed!d" Zed#d$ Zed%d& Zd'd( Zd)d* Zed+d, Zed-d. Zed/d0 Zed1d2 Zd3d4 Zd5d6 Z d7d8 Z!d9d: Z"d;d< Z#d=d> Z$d?d@ Z%dAdB Z&dCdD Z'dEdF Z(dGS )HToolchainCLc              	   C   s	  t j}| | t|dkrX|d drX|d drX||d ||d tdd}tj	ddd	}tj	dd
d	 |j
dddddd |j
dddddgdd |j
dddddd |j
dddddd |j
d d!d"d#td$td% |j
d&d'd(d d)d |j
d*td d+td, |j
d-d.dd/dd0d1 td2}d3|krFd4}|j
dd5|d6|d |j
d7d8d9g d: |j
d;d<d=dd> |j
d?d@dd> |j
dAdBdCddD |j
dEdBdFddD |j
dGdHd d> |j
dIdJd d> t|dKgddLdM t|dNgddOdM t|dPgdQdRdM |j
dSdTdUdVdWd |j
dXdYdZd[d |j
d\d]d^d_d |j
d`dadddbdcgddde t|dfgddgdM |   |jdhdidj}dkdl }||dm|gdndo ||dp|gdqdo}|j
drdddsdt ||dudv|gdw ||dxdygdz|gd{ ||d|d}gd~|gd{ ||ddgd|gd{ ||ddgd|gd{ ||dd|gdw}|j
dddd ||ddgd|gd{}	|	j
ddd |	j
dddddd ||ddgd|gd{}
|
j
dpddd ||ddgd|gd{}|j
ddd |j
dddd tj	|gddd}|j
ddd9g dd |j
ddd9g dd |j
ddddd d |j
dddddd |j
dddddd |j
ddddddd |j
ddddQddd |j
dddd dd |j
dddd dd |j
dddd dd |j
dddd dd ||dd|gdw ||dd|gdw ||dd|gdw ||dd|gdw ||dd|gdw ||ddgd|gd{ ||ddgd|gd{ ||ddgd|gd{}|j
ddd ||dd|gdw ||dd|gdw ||ddgd|gd{ |j
dddtd |t jdd  \}}||_t|dr|jd k	r| jd|jg7  _t|dr<|jdkr<| jdg7  _t|dr`|jr`| jdg7  _t|drz|jrzd|_t|dYr|jdZkr| jdX|jg7  _t|d]r|jd^kr| jd\|jg7  _|| _|jd kr|   t!d t"|j# |j$rt%&t'j( t) | _*t+|ddQ| j*_t+|dddk| j*_,t+|dd| j*_d}t+|dd d k	rt+|d}t-j./t-j.0|dst-j./t-j.0|drdQ}t|drg }|rt+|ddrzt1d dd t2|jdQdQdQdD }t1dt3|  dd t4t56| j*D }t4|7t4|}t|d#krht|j8d#krT| j8d7  _8| j8d0|7  _8W n t9k
r   t:d Y nX t;|j8D ]J}d|kr|<dd\}}|t-j=d|< t1d|| || qd0||_8| >| |j?| _?| j*@| j? |jA| _A|jB| _B|jC| _C|jD| _D|jE| j*_E|jF| j*_F|jG| _HtI|jJ| j*_J|jK| j*_K|j| j*_|j| j*_|jLdd}t+| || d S )N   rs   z--colorz--storage-dirzFA packaging tool for turning Python scripts and apps into Android APKsr,   Fz)Generic arguments applied to all commands)add_helpr-   zArguments for dist buildingz--debugrv   r:   z'Display debug output and all build info)r<   r=   rK   r;   coloralwaysneverautoz7Enable or disable color output (default enabled on tty))r<   choicesr;   z	--sdk-dirz	--sdk_dirrS   rq   z/The filepath where the Android SDK is installed)r<   rK   r;   z	--ndk-dirz	--ndk_dirrT   z/The filepath where the Android NDK is installedz--android-apiz--android_apirU   r   zGThe Android API level to build against defaults to {} if not specified.)r<   rK   typer;   z--ndk-versionz--ndk_versionndk_versionzEDEPRECATED: the NDK version is now found automatically or not at all.z	--ndk-apizThe Android API level to compile against. This should be your *minimal supported* API, not normally the same as your --android-api. Defaults to min(ANDROID_API, {}) if not specified.)r   rK   r;   z--symlink-bootstrap-filesz--ssymlink_bootstrap_filessymlink_bootstrap_fileszxIf True, symlinks the bootstrap files creation. This is useful for development only, it could also cause weird problems.)r=   r<   rK   r;   python-for-android ~/.python-for-androidstorage_dirz@Primary storage directory for downloads and builds (default: {})z--archzThe archs to build for.append)r;   r=   rK   z--dist-namez--dist_namez-The name of the distribution to use or create)r;   rK   z--requirementszDependencies of your app, should be recipe names or Python modules. NOT NECESSARY if you are using Python 3 with --use-setup-pyz--recipe-blacklistzZBlacklist an internal recipe from use. Allows disabling Python 3 core modules to save sizeZrecipe_blacklist)r;   r<   rK   z--blacklist-requirementsrp   z--bootstrapzAThe bootstrap to build with. Leave unset to choose automatically.z--hookz;Filename to a module that contains python-for-android hookszforce-buildz2Whether to force compilation of a new distribution)rK   r-   zrequire-perfect-matchz=Whether the dist recipes must perfectly match those requestedzallow-replace-distTz9Whether existing dist names can be automatically replacedz--local-recipesz--local_recipeslocal_recipesz./p4a-recipesz#Directory to look for local recipesz--activity-class-nameactivity_class_namezorg.kivy.android.PythonActivityz-The full java class name of the main activityz--service-class-nameservice_class_namezorg.kivy.android.PythonServicez1Full java package name of the PythonService classz--java-build-tooljava_build_toolZantZgradlezkThe java build tool to use when packaging the APK, defaults to automatically selecting an appropriate tool.)r<   rK   r   r;   z	copy-libsz6Copy libraries instead of using biglink (Android 4.3+)subparser_namezThe command to run)r<   r;   c                 _   s*   d|krt jjdk r|d | j||S )z
            argparse in python2 doesn't support the aliases option,
            so we just don't provide the aliases there.
            aliases   )sysversion_infomajorpop
add_parser)
subparsersr]   kwargsr3   r3   r4   r   `  s    
z(ToolchainCL.__init__.<locals>.add_parserrecommendationsz!List recommended p4a dependencies)parentsr;   re   zList the available recipesz	--compactz-Produce a compact list suitable for scripting)r=   rK   r;   
bootstrapszList the available bootstraps)r;   r   	clean_allz	clean-allz#Delete all builds, dists and caches)r   r;   r   clean_distszclean-distszDelete all distsclean_bootstrap_buildszclean-bootstrap-buildszDelete all bootstrap buildsclean_buildszclean-buildszDelete all buildscleanzDelete build components.	component+zThe build component(s) to delete. You can pass any number of arguments from "all", "builds", "dists", "distributions", "bootstrap_builds", "downloads".)nargsr;   clean_recipe_buildzclean-recipe-buildz]Delete the build components of the given recipe. By default this will also delete built distsrecipezThe recipe name)r;   z--no-clean-distsno_clean_distsz'If passed, do not delete existing dists)rK   r<   r=   r;   clean_download_cachezclean-download-cachez.Delete cached downloads for requirement builds*zcThe recipes to clean (space-separated). If no recipe name is provided, the entire cache is cleared.export_distzexport-distz%Copy the named dist to the given path
output_dirzThe output dir to copy toz	--symlinkz#Symlink the dist instead of copying)r=   r;   z'common options for packaging (apk, aar))r   r   r-   z--add-assetassetsz)Put this in the assets folder in the apk.z--add-resource	resourcesz&Put this in the res folder in the apk.	--privaterz   zQthe directory with the app source code files (containing your main.py entrypoint))r<   r;   requiredrK   z--use-setup-pyuse_setup_pyz<Process the setup.py of a project if present. (Experimental!z--ignore-setup-pyr{   zDon't run the setup.py of a project if present. This may be required if the setup.py is not designed to work inside p4a (e.g. by installing dependencies that won't work or aren't desired on Androidz	--releaserx   store_constrw   zXBuild your app as a non-debug release build. (Disables gdb debugging among other things))r<   r=   constrK   r;   z--with-debug-symbolsry   z)Will keep debug symbols from `.so` files.z
--keystorekeystorestorez^Keystore for JAR signing key, will use jarsigner default if not specified (release build only)z	--signkeysignkeyz7Key alias to sign PARSER_APK. with (release build only)z--keystorepw
keystorepwzPassword for keystorez--signkeypw	signkeypwzPassword for key aliasaarzBuild an AARapkzBuild an APKaabzBuild an AABcreatez)Compile a set of requirements into a distrf   z'List the available target architecturesdistributionsdistsz-List the currently available (compiled) distsdelete_distzdelete-distzDelete a compiled dist	sdk_toolsz	sdk-toolsz+Run the given binary from the SDK tools distoolzThe binary tool name to runadbzRun adb from the given SDKlogcatzRun logcat from the given SDKbuild_statuszbuild-statusz;Print some debug information about current built componentsz-vz	--versionversion)r=   r   setup.pypyproject.tomlrm   z1Analyzing package dependencies. MAY TAKE A WHILE.c                 S   s   g | ]}|  qS r3   lower)r7   depr3   r3   r4   r9   l  s    z(ToolchainCL.__init__.<locals>.<listcomp>)Zkeep_version_pins	recursiveverbosezDependencies obtained: c                 S   s   g | ]}|  qS r3   r   )r7   r   r3   r3   r4   r9   v  s    rr   zXProcessing failed, is this project a valid package? Will continue WITHOUT setup.py deps.z==z
VERSION_{}z!Recipe {}: version "{}" requestedr.   r/   )Mr   argvwarn_on_carriage_return_argsr   r0   r   r   r   argparseArgumentParserrG   intr   r%   r$   r   rN   _read_configurationadd_subparsersr   parse_known_argsunknown_argshasattrrz   rx   ry   r{   r   r   r   r]   r   
print_helpexitr   r   rv   r   setLevelloggingDEBUGr   rP   r~   r   ospathr
   r   r   r"   strr   r#   list_recipesr   rm   
ValueErrorr   rl   r   r   warn_on_deprecated_argsr   Z
setup_dirsrS   rT   rU   rV   r   r   rn   rQ   r	   r   Z	copy_libsrF   )r\   r   rI   Zgeneric_parserdefault_storage_dirr   r   Zparser_recipesZparser_cleanZparser_clean_recipe_buildZparser_clean_download_cacheZparser_export_distZparser_packagingZparser_sdk_toolsr]   unknownZhave_setup_py_or_similarZproject_dirrm   dependenciesZall_recipesrequirementr   commandr3   r3   r4   __init__   sT   
                  	
               	             
                                         

    

	

 





zToolchainCL.__init__c              	   C   s8   | D ].}d|krt dt|dd t d qd S )Nz.Argument '{}' contains a carriage return (\r).rq   zjInvoking this program via scripts which use CRLF instead of LF line endings will have undefined behaviour.)r   r   r   rF   )r]   Z	check_argr3   r3   r4   r     s    z(ToolchainCL.warn_on_carriage_return_argsc                 C   s   t |dddk	rtjtj|jds@tjtj|jdrt |ddst |ddstd td	 td
 td td td td td td td |jdk	rtd dtkrtd dS )zW
        Print warning messages for any deprecated arguments that were passed.
        rz   Nr   r   r   Fr{   z*  **** FUTURE BEHAVIOR CHANGE WARNING ****z0Your project appears to contain a setup.py file.z(Currently, these are ignored by default.z(This will CHANGE in an upcoming version!rq   z3To ensure your setup.py is ignored, please specify:z    --ignore-setup-pyz5To enable what will some day be the default, specify:z    --use-setup-pyzT--ndk-version is deprecated and no longer necessary, the value you passed is ignoredZANDROIDNDKVERzR$ANDROIDNDKVER is deprecated and no longer necessary, the value you set is ignored)	r~   r   r   r
   r   rz   r   r   r   r\   r]   r3   r3   r4   r     s,    

z#ToolchainCL.warn_on_deprecated_argsc                 C   sd   | j jsd S t| ds&td| j j| _t| j|rRtd| t| j||  ntd| d S )Nhook_modulezpythonforandroid.hookzHook: execute {}zHook: ignore {})r]   hookr   r)   r  r   r   r~   )r\   rd   r3   r3   r4   r    s    
 zToolchainCL.hookc                 C   s   t d}d|krd}|S )Nr   r   r   r   )r\   Zuddr3   r3   r4   r     s    zToolchainCL.default_storage_dirc               	   C   sb   t dsd S td td} |  }W 5 Q R X dd |D }|D ]}|D ]}tj| qJqBd S )Nz.p4azReading .p4a configurationc                 S   s    g | ]}| d st|qS )#)r0   shlexr   )r7   liner3   r3   r4   r9     s    
z3ToolchainCL._read_configuration.<locals>.<listcomp>)r
   r   open	readlinesr   r   r   )fdlinesr  argr3   r3   r4   r     s    
zToolchainCL._read_configurationc              
   C   s  | j }|jr&tdtt| ntt|D ]}zt||}W nV t	t
fk
rn   td| Y n2 tk
r   ddl}|  td| Y nX t|j}tdj|tt|d tdj|td	 |jrtd
j|td	 |jr4tdj|td	 q4dS )a  
        Prints recipes basic info, e.g.
        .. code-block:: bash
            python3      3.7.1
                depends: ['hostpython3', 'sqlite3', 'openssl', 'libffi']
                conflicts: []
                optional depends: ['sqlite3', 'libffi', 'openssl']
        r   zRecipe "{}" could not be loadedr   Nz5Recipe "{}" could not be loaded due to a syntax errorzl{Fore.BLUE}{Style.BRIGHT}{recipe.name:<12} {Style.RESET_ALL}{Fore.LIGHTBLUE_EX}{version:<8}{Style.RESET_ALL})r   ForeStyler   z5    {Fore.GREEN}depends: {recipe.depends}{Fore.RESET})r   r  z7    {Fore.RED}conflicts: {recipe.conflicts}{Fore.RESET}zC    {Fore.YELLOW}optional depends: {recipe.opt_depends}{Fore.RESET})rP   compactprintr   r   r#   r   sorted
get_recipeIOErrorr   r   r   SyntaxError	traceback	print_excr   r   r   r   	conflictsZopt_depends)r\   r]   rP   rd   r   r  r   r3   r3   r4   re     sF    	
     zToolchainCL.recipesc                 C   sF   t  D ]8}t || j}tdj|ttd tdj|td qdS )z0List all the bootstraps available to build with.z3{Fore.BLUE}{Style.BRIGHT}{bs.name}{Style.RESET_ALL})r   r  r  z8    {Fore.GREEN}depends: {bs.recipe_depends}{Fore.RESET})r   r  N)r   Zall_bootstrapsr|   rP   r  r   r   r   )r\   _argsr   r3   r3   r4   r     s       zToolchainCL.bootstrapsc                 C   sT   |j }| j| j| j| j| j| jd}|D ]&}||krBtd||| | q(d S )N)allr   r   Zbuildsbootstrap_buildsZ	downloadsz7Asked to clean "{}" but this argument is not recognised)r   r   r   r   r   r   r(   r   )r\   r]   
componentsZcomponent_clean_methodsr   r3   r3   r4   r   $  s     zToolchainCL.cleanc                 C   s"   |  | | | | | dS )zkDelete all build components; the package cache, package builds,
        bootstrap builds and distributions.N)r   r   r   r  r3   r3   r4   r   6  s    

zToolchainCL.clean_allc                 C   s   | j }t|j dS )zQDelete all compiled distributions in the internal distribution
        directory.N)rP   r*   r   )r\   r  rP   r3   r3   r4   r   =  s    zToolchainCL.clean_distsc                 C   s   t t| jjd dS )z Delete all the bootstrap builds.r  N)r*   r   rP   	build_dir)r\   r  r3   r3   r4   r   C  s    z"ToolchainCL.clean_bootstrap_buildsc                 C   s4   | j }t|j t|j t| j jd}t| dS )a'  Delete all build caches for each recipe, python-install, java code
        and compiled libs collection.

        This does *not* delete the package download cache or the final
        distributions.  You can also use clean_recipe_build to delete the build
        of a specific recipe.
        Zlibs_collectionsN)rP   r*   r  Zpython_installs_dirr   )r\   r  rP   Zlibs_dirr3   r3   r4   r   L  s
    

zToolchainCL.clean_buildsc                 C   s<   t |j| j}td|j |  |js8| 	| dS )aV  Deletes the build files of the given recipe.

        This is intended for debug purposes. You may experience
        strange behaviour or problems with some recipes if their
        build has made unexpected state changes. If this happens, run
        clean_builds, or attempt to clean other recipes until things
        work again.
        zCleaning build for {} recipe.N)
r#   r  r   rP   r   r   rd   Zclean_buildr   r   )r\   r]   r   r3   r3   r4   r   Z  s
    	zToolchainCL.clean_recipe_buildc                 C   s   | j }t|dr^|jr^|jD ]>}t|j|}t|rLt| td| qt	d| qn.t|jr|t|j td nt
d|j dS )a
   Deletes a download cache for recipes passed as arguments. If no
        argument is passed, it'll delete *all* downloaded caches. ::

            p4a clean_download_cache kivy,pyjnius

        This does *not* delete the build caches or final distributions.
        re   z Download cache removed for: "{}"z*No download cache found for "{}", skippingzDownload cache removed.zNo cache found at "{}"N)rP   r   re   r   Zpackages_pathr
   r*   r   r   r   r  )r\   r]   rP   packageZremove_pathr3   r3   r4   r   i  s    




z ToolchainCL.clean_download_cachec                 C   sR   | j }t||}|jrtd|jr:ttjd|j|j	 nttj
d|j|j	 dS )zCopies a created dist to an output dir.

        This makes it easy to navigate to the dist to investigate it
        or call build.py, though you do not in general need to do this
        and can use the apk command instead.
        zYou asked to export a dist, but there is no dist with suitable recipes available. For now, you must  create one first with the create argument.z-sz-rN)rP   ro   rX   r(   symlinkr!   shlnr   r   cp)r\   r]   rP   r_   r3   r3   r4   r     s    
zToolchainCL.export_distc                 C   s   | j }t|| j}||_|S r   )rP   ro   r]   r   )r\   rP   r_   r3   r3   r4   rW     s    zToolchainCL._distc                 C   s"  d}| j }| jD ]@}d|kr,|d\}}n| }}|dtj|d | g7 }q| jD ]@}d|krt|d\}}n|}d}|dtj|d | g7 }qXt|D ]z\}	}
|
d}|d |krt|dkrd	|d t
t|d f||	< q|	d t|k rt
t||	d  ||	d < qd	S )
a3  
        Manually fixing these arguments at the string stage is
        unsatisfactory and should probably be changed somehow, but
        we can't leave it until later as the build.py scripts assume
        they are in the current directory.
        works in-place
        :param args: parser args
        )
z--dirr   z	--add-jarz--add-sourcez--whitelistz--blacklistz--presplashz--iconz	--icon-bgz	--icon-fg:z--assetrq   z
--resource=r   rs   N)r   r   r   r   r   abspathr   	enumerater   r   r	   r   )r]   Zfix_argsr   ZassetZ	asset_srcZ
asset_destresourceZresource_srcZresource_destir  Zargxr3   r3   r4   	_fix_args  s,    



zToolchainCL._fix_argsc                 C   sz   t j }| jdkrv| jr,tt| j|d< | jr<| j|d< | jrL| j|d< | j	r^| j	|d< n| jrvd|krv| j|d< |S )zx
        prepares envitonment dict with the necessary flags for signing an apk
        :param args: parser args
        rw   ZP4A_RELEASE_KEYSTOREZP4A_RELEASE_KEYALIASZP4A_RELEASE_KEYSTORE_PASSWDZP4A_RELEASE_KEYALIAS_PASSWD)
r   r   copyrx   r   r	   r   r   r   r   )r]   envr3   r3   r4   _prepare_release_env  s    




z ToolchainCL._prepare_release_envc              	   C   s  | j }| j}t|j|}|| | | | |}t|j	 | 
d t| j jtjd< tdt|j	d}||j}| 
d | 
d tt|jd}	dd	 }
|	j|
d
 |	d }td| t|ddtdk rtd| tdstd| j j|d< | j j|d< td}tdrRttd|j !ddd|d}|j"dkrv|dkrptdd}n<|j"d kr|d!krd"}n|dkrd#}ntd$|j"t|d%|dd|d}W 5 Q R X ||fS )&z
        Creates an android package using gradle
        :param args: parser args
        :param package_type: one of 'apk', 'aar', 'aab'
        :return (gradle output, build_args)
        Zbefore_apk_buildZANDROID_APIbuildzbuild.pyZafter_apk_buildZbefore_apk_assemblezbuild-toolsc                 S   s4   zt | ddW S  tk
r.   t d Y S X d S )Nr   rq   0)r   rF   r   )version_textr3   r3   r4   sort_key  s    z,ToolchainCL._build_package.<locals>.sort_key)keyz7Detected highest available build tools version to be {}r   rq   z25.0z2build_tools >= 25 is required, but %s is installedgradlewzgradlew file is missingZANDROID_NDK_HOMEZANDROID_HOMEz	./gradlewz/usr/bin/dos2unixZdos2unixutf8   T)Z_tailZ	_criticalZ_envrv   r   zaab is meant only for distribution and is not available in debug mode. Instead, you can use apk while building for debugging purposes.ZassembleDebugrw   )r   r   ZassembleReleaseZbundleReleasezUnknown build mode {} for apk()r   )#rP   rW   r   r|   r}   r   r'  r*  r'   r   r  r   rU   r   r   r)   r   Zparse_args_and_make_packager   listdirrS   sortr   r   r   rF   r(   r
   rT   r  Commandr!   _pathdecoderx   )r\   r]   package_typerP   r_   r   r)  r+  
build_argsZbuild_tools_versionsr.  Zbuild_tools_versionr1  outputZgradle_taskr3   r3   r4   _build_package  sx    






	


 
  




 zToolchainCL._build_packagec                 C   sN  d| }d}|  d td td}d}	t| D ]"}
||
}|r8| d }	 q\q8|	std |jd	krxd
}nd}|D ]H}t		t
|||}|rt|dkrtd|d  |d }	 qqtdtd|	 d| }|r<td t|	dt|  }d||j|}td| ttj|	| nttj|	d dS )aK  
        Finishes the package after the gradle script run
        :param args: the parser args
        :param output: RunningCommand output
        :param build_args: build args as returned by build.parse_args
        :param package_type: one of 'apk', 'aar', 'aab'
        :param output_dir: where to put the package file
        z*-{}.%sTZafter_apk_assemblez.# Copying android package to current directoryz.*Package: (.*\.apk)$Nr   zA# Android package filename not found in build output. Guessing...rw   )rw   zrelease-unsigned)rv   rs   z;More than one built APK found... guessing you just built {}r0  zCouldn't find the built APKz # Found android package file: {}.z'# Add version number to android packagez{}-{}{}z# Android package renamed to {}z./)r  r    r   compilereversed
splitlinesmatchgroupsrx   globr   r   r   r   r(   r   r   r!   r  r   )r\   r]   r;  r:  r9  r   Zpackage_globZpackage_add_versionZ
package_reZpackage_filer  msuffixessuffixZpackage_filesZpackage_extensionpackage_nameZpackage_file_destr3   r3   r4   _finish_package,  sN    





  zToolchainCL._finish_packagec                 C   s>   | j |dd\}}t| jjddd|j}| |||d| d S )Nr   r9  r+  outputsr<  r   rW   r   rx   rH  r\   r]   r;  r:  r   r3   r3   r4   r   b  s    zToolchainCL.apkc                 C   s:   | j |dd\}}t| jjddd}| |||d| d S )Nr   rI  r+  rJ  )r<  r   rW   r   rH  rL  r3   r3   r4   r   h  s    zToolchainCL.aarc                 C   s>   | j |dd\}}t| jjddd|j}| |||d| d S )Nr   rI  r+  rJ  ZbundlerK  rL  r3   r3   r4   r   n  s    zToolchainCL.aabc                 C   s   dS )z~Create a distribution directory if it doesn't already exist, run
        any recipes if necessary, and build the apk.
        Nr3   r  r3   r3   r4   r   t  s    zToolchainCL.createc                 C   s2   t djtd | jjD ]}t d|j qdS )z8List the target architectures available to be built for.zB{Style.BRIGHT}Available target architectures are:{Style.RESET_ALL}r  z    {}N)r  r   r   rP   rf   rn   )r\   r  rn   r3   r3   r4   rf   {  s
    zToolchainCL.archsc                 C   s   |  | dS )z"The same as :meth:`distributions`.N)r   r  r3   r3   r4   r     s    zToolchainCL.distsc                 C   sD   | j }t|}|r0tdjtd t|t ntdjtd dS )zXLists all distributions currently available (i.e. that have already
        been built).zE{Style.BRIGHT}Distributions currently installed are:{Style.RESET_ALL}rM  zB{Style.BRIGHT}There are no dists currently built.{Style.RESET_ALL}N)rP   r   Zget_distributionsr  r   r   r   )r\   r  rP   r   r3   r3   r4   r     s    
zToolchainCL.distributionsc                 C   s&   | j }| std d S |  d S )NzJNo dist exists that matches your specifications, exiting without deleting.)rW   rY   r   rZ   )r\   r  r_   r3   r3   r4   r     s
    zToolchainCL.delete_distc                 C   sn   | j }|j| j| j| j| jd tt|jd|j	}||j
dddd}|D ]}tj| tj  qNdS )a'  Runs the android binary from the detected SDK directory, passing
        all arguments straight to it. This binary is used to install
        e.g. platform-tools for different API level targets. This is
        intended as a convenience function if android is not in your
        $PATH.
        rO   r+   Trs   Z_iterZ_out_bufsizeZ_err_to_outN)rP   rR   rS   rT   rU   rV   r  r6  r   r   r   r   stdoutwriteflush)r\   r]   rP   Zandroidr;  r  r3   r3   r4   r     s        zToolchainCL.sdk_toolsc                 C   s   |  |j dS )zRuns the adb binary from the detected SDK directory, passing all
        arguments straight to it. This is intended as a convenience
        function if adb is not in your $PATH.
        N_adbr   r  r3   r3   r4   r     s    zToolchainCL.adbc                 C   s   |  dg|j  dS )zRuns ``adb logcat`` using the adb binary from the detected SDK
        directory. All extra args are passed as arguments to logcat.r   NrR  r  r3   r3   r4   r     s    zToolchainCL.logcatc                 C   s   | j }|j| j| j| j| jd tdkr>tt	|jdd}ntt	|jdd}t
d ||dddd	}|D ]}tj| tj  qpd
S )zVCall the adb executable from the SDK, passing the given commands as
        arguments.rO   )win32cygwinzplatform-toolszadb.exer   zStarting adb...Trs   rN  N)rP   rR   rS   rT   rU   rV   r   r  r6  r   r   r   rO  rP  rQ  )r\   commandsrP   r   r;  r  r3   r3   r4   rS    s    zToolchainCL._adbc                 C   s
   t   d S r   )r&   r  r3   r3   r4   r     s    zToolchainCL.recommendationsc                 C   s   t djtd t| jjd}t|rJt|D ]}t dj|t	td q0t djtd t| jjd}t|rt
t|D ]n}|dd	 }|dd
d }djt|t	d}|r|dd| d jt	d7 }|djtd7 }t | q~dS )z)Print the status of the specified build. z[{Style.BRIGHT}Bootstraps whose core components are probably already built:{Style.RESET_ALL}rM  r  z6    {Fore.GREEN}{Style.BRIGHT}{filen}{Style.RESET_ALL})filenr  r  zG{Style.BRIGHT}Recipes that are probably already built:{Style.RESET_ALL}Zother_buildsr.   r   rs   Nz5    {Style.BRIGHT}{Fore.GREEN}{name}{Style.RESET_ALL})r  rd   r  z ({Fore.BLUE}with ru   z{Fore.RESET}))r  z{Style.RESET_ALL})r  r   r   r   rP   r  r
   r   r4  r   r  r   )r\   r  Zbootstrap_dirrW  Zother_builds_dirrd   r   Z
recipe_strr3   r3   r4   r     sD      
  zToolchainCL.build_statusN))r   r   r   r   staticmethodr   r   r  propertyr   r   re   r   r   r   r   r   r   r   r   rc   r   rW   r'  r*  r<  rH  r   r   r   r   rf   r   r   r   r   r   r   rS  r   r   r3   r3   r3   r4   r      sb      m
 

(		


'
R6



r   __main__)NTNN)Or   appdirsr   r   	functoolsr   rC  r   r   r   os.pathr   r   r	   r
   r   r   r   r  r   r   Z"pythonforandroid.checkdependenciesr   Zpackaging.versionr   r   r  Zpythonforandroidr   Zpythonforandroid.bootstrapr   Zpythonforandroid.buildr   r   Zpythonforandroid.distributionr   r   Zpythonforandroid.entrypointsr   Zpythonforandroid.graphr   Zpythonforandroid.loggerr   r   r   r   r   r   r   r    r!   Zpythonforandroid.pythonpackager"   Zpythonforandroid.reciper#   Z pythonforandroid.recommendationsr$   r%   r&   Zpythonforandroid.utilr'   r(   r)   r*   r   curdirZuser_dir__file__Ztoolchain_dirinsertrN   rc   ro   r[   rl   r   r   r   r   r3   r3   r3   r4   <module>   sf    ,      
5        7
