î
ªÍ X•9  ã               @   sÊ   d  d l  m Z d  d l Z d  d l 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 d  d l m Z d	 d
 l m Z m Z m Z m Z d Z Gd d „  d e ƒ Z d S)é    )Úunicode_literalsN)Úimport_module)Úapps)Úsettings)ÚMigrationGraph)ÚMigrationRecorder)Úsixé   )ÚAmbiguityErrorÚBadMigrationErrorÚInconsistentMigrationHistoryÚNodeNotFoundErrorZ
migrationsc               @   s¸   e  Z d  Z d Z d d 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 d d d d „ Z d S)ÚMigrationLoaderan  
    Loads migration files from disk, and their status from the database.

    Migration files are expected to live in the "migrations" directory of
    an app. Their names are entirely unimportant from a code perspective,
    but will probably follow the 1234_name.py convention.

    On initialization, this class will scan those directories, and open and
    read the python files, looking for a class called Migration, which should
    inherit from django.db.migrations.Migration. See
    django.db.migrations.migration for what that looks like.

    Some migrations will be marked as "replacing" another set of migrations.
    These are loaded into a separate set of migrations away from the main ones.
    If all the migrations they replace are either unapplied or missing from
    disk, then they are injected into the main set, replacing the named migrations.
    Any dependency pointers to the replaced migrations are re-pointed to the
    new migration.

    This does mean that this class MUST also talk to the database as well as
    to disk, but this is probably fine. We're already not just operating
    in memory.
    TFc             C   s;   | |  _  d  |  _ d  |  _ | |  _ | r7 |  j ƒ  n  d  S)N)Ú
connectionÚdisk_migrationsÚapplied_migrationsÚignore_no_migrationsÚbuild_graph)Úselfr   Úloadr   © r   úI/home/ubuntu/projects/ifolica/build/django/django/db/migrations/loader.pyÚ__init__.   s    				zMigrationLoader.__init__c             C   s>   | t  j k r t  j | St j | ƒ j } d | t f Sd  S)Nz%s.%s)r   ZMIGRATION_MODULESr   Zget_app_configÚnameÚMIGRATIONS_MODULE_NAME)ÚclsÚ	app_labelZapp_package_namer   r   r   Úmigrations_module6   s    z!MigrationLoader.migrations_modulec             C   sm  i  |  _  t ƒ  |  _ t ƒ  |  _ xEt j ƒ  D]7} |  j | j ƒ } | d k rk |  j j | j ƒ q. n  | t	 j
 k } y t | ƒ } Wne t k
 rñ } zE d t | ƒ k rÜ t t | ƒ k rÜ |  j j | j ƒ w. n  ‚  WYd d } ~ Xnj Xt | d ƒ s|  j j | j ƒ q. n  t | d ƒ sB|  j j | j ƒ q. n  | r[t j j | ƒ n  |  j j | j ƒ t j j | j ƒ } t ƒ  } x_ t j | ƒ D]N } | j d ƒ rœ| j d d ƒ d }	 |	 d d	 k rê| j |	 ƒ qêqœqœWxt | D]l }
 t d
 | |
 f ƒ } t | d ƒ s<t d |
 | j f ƒ ‚ n  | j |
 | j ƒ |  j  | j |
 f <qõWq. Wd S)zI
        Loads the migrations from all INSTALLED_APPS from disk.
        NzNo module namedÚ__file__Ú__path__z.pyÚ.r	   r   z_.~z%s.%sÚ	Migrationz-Migration %s in app %s has no Migration class)r   ÚsetÚunmigrated_appsÚmigrated_appsr   Zget_app_configsr   ÚlabelÚaddÚsysÚmodulesr   ÚImportErrorÚstrr   Úhasattrr   ÚmovesÚreload_moduleÚosÚpathÚdirnamer   ÚlistdirÚendswithÚrsplitr   r!   )r   Z
app_configÚmodule_nameZ
was_loadedÚmoduleÚeÚ	directoryZmigration_namesr   Úimport_nameÚmigration_nameZmigration_moduler   r   r   Ú	load_disk>   sP    	$	zMigrationLoader.load_diskc             C   s   |  j  j | | f S)zEGets the migration exactly named, or raises `graph.NodeNotFoundError`)ÚgraphÚnodes)r   r   Úname_prefixr   r   r   Úget_migrationv   s    zMigrationLoader.get_migrationc             C   sº   g  } xH |  j  D]= \ } } | | k r | j | ƒ r | j | | f ƒ q q Wt | ƒ d k r| t d | | f ƒ ‚ n: t | ƒ d k r§ t d | | f ƒ ‚ n |  j  | d Sd S)zJReturns the migration(s) which match the given app label and name _prefix_r	   z>There is more than one migration for '%s' with the prefix '%s'r   z1There no migrations for '%s' with the prefix '%s'N)r   Ú
startswithÚappendÚlenr
   ÚKeyError)r   r   r=   ÚresultsÚlÚnr   r   r   Úget_migration_by_prefixz   s    z'MigrationLoader.get_migration_by_prefixc             C   s  | d d k r  | d d k s/ | |  j  k r3 | S| d | k rG d  S| d |  j k r^ d  S| d |  j k rú yP | d d k r¢ t |  j  j | d ƒ ƒ d St |  j  j | d ƒ ƒ d SWqú t k
 rö |  j rÞ d  St d | d ƒ ‚ Yqú Xn  t d | d ƒ ‚ d  S)Nr	   Ú	__first__Z
__latest__r   z(Dependency on app with no migrations: %szDependency on unknown app: %s)	r;   r#   r$   ÚlistZ
root_nodesÚ
leaf_nodesÚ
IndexErrorr   Ú
ValueError)r   ÚkeyZcurrent_appr   r   r   Ú	check_keyŠ   s     /"	zMigrationLoader.check_keyc             C   s^   xW | j  D]L } | d | d k s
 | d d k r: q
 n  |  j j | | | d d ƒq
 Wd S)z…
        Internal dependencies need to be added first to ensure `__first__`
        dependencies find the correct root node.
        r   r	   rG   Úskip_validationTN)Údependenciesr;   Úadd_dependency)r   rL   Ú	migrationÚparentr   r   r   Úadd_internal_dependencies¦   s    $z)MigrationLoader.add_internal_dependenciesc             C   sÈ   xl | j  D]a } | d | d k r* q
 n  |  j | | d ƒ } | d  k	 r
 |  j j | | | d d ƒq
 q
 WxR | j D]G } |  j | | d ƒ } | d  k	 ry |  j j | | | d d ƒqy qy Wd  S)Nr   rN   T)rO   rM   r;   rP   Z
run_before)r   rL   rQ   rR   Úchildr   r   r   Úadd_external_dependencies±   s    #z)MigrationLoader.add_external_dependenciesc                s!  ˆ  j  ƒ  ˆ  j d k r( t ƒ  ˆ  _ n t ˆ  j ƒ } | j ƒ  ˆ  _ t ƒ  ˆ  _ i  ˆ  _ xY ˆ  j j	 ƒ  D]H \ } } ˆ  j j
 | | ƒ ˆ  j | | ƒ | j rk | ˆ  j | <qk qk Wx- ˆ  j j	 ƒ  D] \ } } ˆ  j | | ƒ qÇ Wx° ˆ  j j	 ƒ  D]Ÿ \ } } ‡  f d d †  | j Dƒ } t | ƒ r>ˆ  j j | ƒ n ˆ  j j | ƒ t | ƒ sgt | ƒ r€ˆ  j j | | j ƒ q÷ ˆ  j j | | j ƒ q÷ Wy ˆ  j j ƒ  Wnot k
 r} zOi  } xM ˆ  j j	 ƒ  D]< \ } } x- | j D]" } | j | t ƒ  ƒ j | ƒ qìWqÖW| j | k r| j | j t ƒ  ƒ } t ‡  f d d †  | Dƒ ƒ }	 |	 sd j d d „  | Dƒ ƒ }
 t d j | j | j d	 | j d
 |
 ƒ | j ƒ } | | _ t | d ƒ sát j ƒ  d | _  n  t! j" t | t j ƒ  d ƒ qn  | ‚ WYd d } ~ Xn Xd S)z÷
        Builds a migration dependency graph using both the disk and database.
        You'll need to rebuild the graph if you apply migrations. This isn't
        usually a problem as generally migration stuff runs in a one-shot process.
        Nc                s   g  |  ] } | ˆ  j  k ‘ q Sr   )r   )Ú.0Útarget)r   r   r   ú
<listcomp>Ý   s   	 z/MigrationLoader.build_graph.<locals>.<listcomp>c             3   s!   |  ] } | ˆ  j  j k Vq d  S)N)r;   r<   )rV   Ú	candidate)r   r   r   ú	<genexpr>ü   s    z.MigrationLoader.build_graph.<locals>.<genexpr>z, c             s   s   |  ] } d  | Vq d S)z%s.%sNr   )rV   Úcr   r   r   rZ   þ   s    zÅMigration {0} depends on nonexistent node ('{1}', '{2}'). Django tried to replace migration {1}.{2} with any of [{3}] but wasn't able to because some of the replaced migrations are already applied.r   r	   Ú__traceback__é   )#r:   r   r"   r   r   r   r;   Úreplacementsr   ÚitemsÚadd_noderS   ÚreplacesrU   Úallr&   ÚdiscardÚanyZremove_replaced_nodesZremove_replacement_nodeZvalidate_consistencyr   Ú
setdefaultÚnodeÚgetÚjoinÚformatÚoriginÚ	__cause__r+   r'   Úexc_infor\   r   Úreraise)r   ÚrecorderrL   rQ   Zapplied_statusesÚexcZreverse_replacementsZreplacedZ
candidatesZis_replacedÚtriesÚ	exc_valuer   )r   r   r   ¾   sV    
		$ 	#zMigrationLoader.build_graphc          	      sç   t  | ƒ } | j ƒ  ‰  xÈ ˆ  D]À } | |  j j k r= q n  xŸ |  j j | j D]Š } | ˆ  k rQ | |  j k r¤ t ‡  f d d †  |  j | j Dƒ ƒ r¤ qQ q¤ n  t	 d j
 | d | d | d | d | j ƒ ƒ ‚ qQ qQ Wq Wd S)zs
        Raise InconsistentMigrationHistory if any applied migrations have
        unapplied dependencies.
        c             3   s   |  ] } | ˆ  k Vq d  S)Nr   )rV   Úm)Úappliedr   r   rZ     s    z;MigrationLoader.check_consistent_history.<locals>.<genexpr>zHMigration {}.{} is applied before its dependency {}.{} on database '{}'.r   r	   N)r   r   r;   r<   Znode_mapÚparentsr^   rb   ra   r   ri   Úalias)r   r   rn   rQ   rR   r   )rs   r   Úcheck_consistent_history  s    )	z(MigrationLoader.check_consistent_historyc                s~   i  ‰  t  ƒ  } xU |  j j ƒ  D]D \ } } | ˆ  k rG | j | ƒ n  ˆ  j | t  ƒ  ƒ j | ƒ q W‡  f d d †  | Dƒ S)zÛ
        Looks through the loaded graph and detects any conflicts - apps
        with more than one leaf migration. Returns a dict of the app labels
        that conflict with the migration names that conflict.
        c                s   i  |  ] } ˆ  | | “ q Sr   r   )rV   r   )Ú	seen_appsr   r   ú
<dictcomp>4  s   	 z4MigrationLoader.detect_conflicts.<locals>.<dictcomp>)r"   r;   rI   r&   re   )r   Zconflicting_appsr   r9   r   )rw   r   Údetect_conflicts(  s    	 z MigrationLoader.detect_conflictsNc             C   s(   |  j  j d | d | d t |  j ƒ ƒ S)zÉ
        Returns a ProjectState object representing the most recent state
        that the migrations we loaded represent.

        See graph.make_state for the meaning of "nodes" and "at_end"
        r<   Úat_endZ	real_apps)r;   Z
make_staterH   r#   )r   r<   rz   r   r   r   Úproject_state6  s    zMigrationLoader.project_state)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Úclassmethodr   r:   r>   rF   rM   rS   rU   r   rv   ry   r{   r   r   r   r   r      s   8Pr   )Ú
__future__r   r.   r'   Ú	importlibr   Zdjango.appsr   Zdjango.confr   Zdjango.db.migrations.graphr   Zdjango.db.migrations.recorderr   Zdjango.utilsr   Ú
exceptionsr
   r   r   r   r   Úobjectr   r   r   r   r   Ú<module>   s   "