sbin/sync/ldt_fablib/__init__.py
changeset 60 10e4b6eae0e5
parent 59 4671c9fd69b5
child 61 c5ea47746855
equal deleted inserted replaced
59:4671c9fd69b5 60:10e4b6eae0e5
     1 from fabric.api import run, local, env, cd, put, prefix, sudo, lcd
       
     2 from fabric.context_managers import settings
       
     3 from fabric.contrib.files import exists, upload_template
       
     4 from fabric.contrib.project import rsync_project
       
     5 from mercurial import commands, ui, hg, cmdutil
       
     6 from fabric.tasks import Task
       
     7 from fabric.colors import green
       
     8 import config
       
     9 import imp
       
    10 import os
       
    11 import os.path
       
    12 import re
       
    13 import shutil
       
    14 import urlparse
       
    15 
       
    16 
       
    17 
       
    18 __all__ = ["check_folder_access", "syncdb", "collectstatic", 
       
    19     "export_version", "do_sync_web", "create_config", "clean_export_folder", "relaunch_server", 
       
    20     "do_sync_ldt", "sync_install_build", "do_create_virtualenv", "clean_rsync_folder", "rsync_export",
       
    21     "SyncComp"] 
       
    22 
       
    23 def get_export_path(version):
       
    24     base_path = os.path.join(env.base_export_path,env.export_prefix).rstrip("/")
       
    25     return os.path.expanduser(base_path) + "_%s" % (str(version))
       
    26 
       
    27 def clean_export_folder(path):
       
    28     print("Removing %s" % path)
       
    29     if os.path.isdir(path):
       
    30         shutil.rmtree(path, ignore_errors=True)
       
    31 
       
    32 def do_export_version(path, **export_keys):
       
    33     print("Export version %s : %s " % (path,repr(export_keys)))
       
    34 
       
    35     for export_key, version in export_keys.items():
       
    36         export_path = os.path.join(path,export_key)
       
    37         
       
    38         repo_url = env.repos[export_key]
       
    39         url_part = urlparse.urlparse(repo_url)
       
    40         if url_part.scheme or url_part.netloc:
       
    41             # this is a remote repo. Let's clone first
       
    42             clone_path = os.path.join(path,'clone',export_keys)
       
    43             os.makedirs(clone_path)
       
    44             local("hg clone \"%s\" \"%s\"" % (repo_url,clone_path))
       
    45         else:
       
    46             clone_path = repo_url
       
    47         
       
    48         with lcd(clone_path):
       
    49             local("hg archive -r \'%s\' \"%s\"" % (str(version),export_path))
       
    50     
       
    51     print("Export version %s done"%repr(export_keys))
       
    52 
       
    53     
       
    54 def get_remote_env(remotepath, remotevirtualenvpath, platform_web_module, settings_key):
       
    55     activate_path = os.path.join(remotevirtualenvpath, "bin/activate")
       
    56     with prefix("source \"%s\"" % activate_path), prefix("export PYTHONPATH=\"%s\"" % remotepath), cd(remotepath):
       
    57         tempfilepath = run("mktemp -t ldtplatform.XXXXXX")
       
    58         with settings(warn_only=True):
       
    59             run("echo \"import os\" > %s" % (tempfilepath))
       
    60             map(lambda str_echo: run("echo \"%s\" >> %s" % (str_echo, tempfilepath)),
       
    61                 ["os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings')" % (platform_web_module),
       
    62                  "from django.conf import settings",
       
    63                  "print settings.%s" % (settings_key)])
       
    64             res = run("python < %s" % (tempfilepath))
       
    65         run("rm -f \"%s\"" % (tempfilepath))
       
    66     return res
       
    67     
       
    68     
       
    69     
       
    70 def rsync_export(path, remotepath, filters):
       
    71     print("Rsync %s to %s",(path,remotepath))
       
    72     
       
    73     filter_option_str = "--progress --stats"
       
    74     if filters:
       
    75         filter_option_str += " " + " ".join(["--filter \"%s\"" % (f) for f in filters])
       
    76     
       
    77     run("mkdir -p \"%s\"" % remotepath)
       
    78     rsync_project(remotepath, local_dir=path, extra_opts=filter_option_str, delete=True)
       
    79     print("Rsync %s to %s done",(path,remotepath))
       
    80     
       
    81 def clean_rsync_folder(remotepath):
       
    82     print("clean rsync folder %s" % remotepath)
       
    83     run("rm -fr \"%s\"" % remotepath)
       
    84     
       
    85 def build_src(path):
       
    86     print("Build source dist at %s" % path)
       
    87     f = None
       
    88     try:
       
    89         f, pathname, description = imp.find_module("setup", [path])
       
    90         print(" 2 Build source dist at %s" % path)
       
    91         setup_mod = imp.load_module("setup", f, pathname, description)
       
    92         print(" 3 Build source dist at %s" % path)
       
    93     finally:
       
    94         if f:
       
    95             f.close()
       
    96         
       
    97     setup_mod.launch_setup("setup.py", ['sdist'])
       
    98     
       
    99     print("Build source dist at %s done" % path)
       
   100     
       
   101 
       
   102 def get_src_version(mod_name, path):
       
   103     print("get src version for %s at %s" % (mod_name,path))
       
   104     f = None
       
   105     try:
       
   106         f, pathname, description = imp.find_module(mod_name, [path])
       
   107         ldt_mod = imp.load_module(mod_name, f, pathname, description)
       
   108     finally:
       
   109         if f:
       
   110             f.close()
       
   111     version = ldt_mod.VERSION
       
   112     version_str = ldt_mod.get_version()
       
   113     
       
   114     return (version, version_str) 
       
   115     
       
   116 
       
   117 def sync_build(path):
       
   118     print("Sync build %s" % path)
       
   119     with cd(env.remote_path['ldt_base']):
       
   120         filename = os.path.basename(path)
       
   121         res_trans = put(path, os.path.join(env.remote_path['ldt_base'], filename))
       
   122         print("Sync build %s to %s" % (path,repr(res_trans)))
       
   123         return res_trans
       
   124 
       
   125 def remove_build(path):
       
   126     print("remove build build %s" % path)
       
   127     run("rm \"%s\"" % path)
       
   128         
       
   129 
       
   130 def install_build(remotepath, remotevirtualenvpath, module_to_uninstall= None):
       
   131     print("Install build %s in %s" % (remotepath, remotevirtualenvpath))
       
   132     activate_path = os.path.join(remotevirtualenvpath, "bin/activate")
       
   133     
       
   134     with prefix("source %s" % activate_path):
       
   135         if module_to_uninstall:
       
   136             with settings(warn_only=True):
       
   137                 run("pip uninstall -y %s" % module_to_uninstall)
       
   138         run("pip install \"%s\"" % remotepath)
       
   139 
       
   140 def collectstatic(remotepath, remotevirtualenvpath, platform_web_module):
       
   141     print("Collect static in %s with %s" % (remotepath, remotevirtualenvpath))
       
   142     remotestaticsitepath = get_remote_env(remotepath, remotevirtualenvpath, platform_web_module, "STATIC_ROOT")
       
   143     activate_path = os.path.join(remotevirtualenvpath, "bin/activate")
       
   144     with prefix("source \"%s\"" % activate_path), prefix("export PYTHONPATH=\"%s\"" % remotepath), cd(remotepath):
       
   145         #remocve old files optio -c of collect static fail !
       
   146         run("rm -fr \"%s\"" % (remotestaticsitepath))
       
   147         run("python manage.py collectstatic --noinput")
       
   148 
       
   149 def syncdb(remotepath, remotevirtualenvpath):
       
   150     activate_path = os.path.join(remotevirtualenvpath, "bin/activate")
       
   151     with prefix("source \"%s\"" % activate_path), prefix("export PYTHONPATH=\"%s\"" % remotepath), cd(remotepath):
       
   152         run("python manage.py syncdb --migrate --noinput")
       
   153         
       
   154 def create_config(export_path):    
       
   155     print("Create config from %s" % (export_path,))
       
   156     remotepath = env.remote_path['src']
       
   157     remote_config_path = os.path.join(remotepath, env.platform_web_module, "config.py")
       
   158     template_path = os.path.join(export_path, "src", env.platform_web_module, "config.py.tmpl")
       
   159     
       
   160     context = {
       
   161         'base_dir': os.path.join(remotepath, env.platform_web_module).rstrip("/")+"/",
       
   162         'asctime': '%(asctime)s',
       
   163         'levelname': '%(levelname)s',
       
   164         'message': '%(message)s',
       
   165         'module': '%(module)s',
       
   166     }
       
   167     context.update(env.config['web'])
       
   168     
       
   169     if not exists(remote_config_path, verbose=True):
       
   170         upload_template(template_path, remote_config_path, context=context)
       
   171 
       
   172 def export_version(**kwargs):
       
   173     print("export version %s" % (repr(kwargs)))
       
   174     
       
   175     export_path = kwargs.get('path', None)
       
   176     
       
   177     if not export_path:    
       
   178         export_path = get_export_path("_".join(["%s_%s" % (k,v) for k,v in kwargs.items()]))
       
   179     
       
   180     clean_export_folder(export_path)
       
   181     
       
   182     do_export_version(export_path,**kwargs)
       
   183     
       
   184     return export_path
       
   185 
       
   186 def do_create_virtualenv(remote_venv_export_path, remotevirtualenvpath):
       
   187     print("Create virtualenv export_path : %s - remote venvpath : %s" % (remote_venv_export_path, remotevirtualenvpath))
       
   188     activate_path = os.path.join(remotevirtualenvpath, "bin/activate")
       
   189     if "remote_baseline_venv" in env and env.remote_baseline_venv:
       
   190         prefix_str = "source \"%s\"" % os.path.join(env.remote_baseline_venv, "bin/activate")
       
   191     else:
       
   192         prefix_str = "echo"
       
   193     with settings(warn_only=True):
       
   194         run("rm -fr \"%s\"" % remotevirtualenvpath)
       
   195     run("mkdir -p \"%s\"" % remotevirtualenvpath)
       
   196     with prefix(prefix_str), cd(os.path.join(remote_venv_export_path,"virtualenv","web")):
       
   197         run("python create_python_env.py")
       
   198         run("python project-boot.py \"%s\"" % remotevirtualenvpath)
       
   199     with prefix("source \"%s\"" % activate_path):
       
   200         run("pip install -r \"%s\"" % os.path.join(remote_venv_export_path,"virtualenv","web","res","srvr_requirements.txt"))
       
   201 
       
   202 def do_sync_comp(key, export_path):
       
   203     print("do_sync_comp with  path %s" % (export_path))
       
   204     
       
   205     src_path = os.path.join(export_path,"src")
       
   206     # find setup.py
       
   207     for root, _, files in os.walk(src_path):
       
   208         if "setup.py" in files:
       
   209             src_path = root
       
   210     
       
   211     build_src(src_path)
       
   212     (_,version_str) = get_src_version(key, src_path)
       
   213     build_path = os.path.join(src_path,"dist","%s-%s.tar.gz" % (key,version_str))
       
   214     sync_install_build(build_path, key)
       
   215         
       
   216 
       
   217 def sync_install_build(build_path, module_to_uninstall=None):
       
   218     res_trans = None
       
   219     try:
       
   220         res_trans = sync_build(build_path)
       
   221         install_build(res_trans[0], env.remote_path['virtualenv'], module_to_uninstall)        
       
   222     finally:
       
   223         if res_trans:
       
   224             remove_build(res_trans[0])
       
   225 
       
   226 
       
   227 def do_sync_web(version, export_path):
       
   228     print("do_sync_web with version %s and path %s" % (version,export_path))
       
   229     #sync web
       
   230     web_path = os.path.join(export_path,"web/") 
       
   231     rsync_export(web_path, env.remote_path['web'], env.rsync_filters['web'])
       
   232     #sync src
       
   233     src_path = os.path.join(export_path,"src/") 
       
   234     rsync_export(src_path, env.remote_path['src'], env.rsync_filters['src'])
       
   235         
       
   236     
       
   237 def check_folder_access():
       
   238     print("Check folder access")
       
   239     # get remote user
       
   240     for folder_path in env.folders:
       
   241         if not os.path.isabs(folder_path):
       
   242             folder_path = env.remote_path['web'].rstrip("/")+ "/" + folder_path
       
   243             with settings(warn_only=True):
       
   244                 if not exists(folder_path):
       
   245                     run("mkdir -p \"%s\"" % folder_path)
       
   246                 run("chown -R -c :%s \"%s\"" % (env.web_group, folder_path))
       
   247                 run("chmod -R -c g+w \"%s\"" % folder_path)
       
   248 
       
   249 def get_comp_versions_dict(export_path_web):
       
   250     comp_versions = {}
       
   251     with open(os.path.join(export_path_web, 'src', 'requirement.txt')) as f:
       
   252         for line in f:
       
   253             m = re.match('^(\w+)\s+\(\s*\=\=\s*([\.\d\w]+)\s*\)', line)
       
   254             if m:
       
   255                 key, version_req = m.groups()
       
   256                 if "." in version_req:
       
   257                     version_req = "V" + ".".join(["%02d" % (int(s)) if s.isdigit() else s for s in version_req.split(".")])
       
   258                 comp_versions[key] = version_req
       
   259     
       
   260     return comp_versions
       
   261 
       
   262 def do_relaunch_server(do_collectstatic, do_syncdb):
       
   263     check_folder_access()
       
   264     if do_syncdb:
       
   265         syncdb(env.remote_path['src'], env.remote_path['virtualenv'])
       
   266     if do_collectstatic:
       
   267         collectstatic(env.remote_path['src'], env.remote_path['virtualenv'], env.platform_web_module)
       
   268     sudo(env.web_relaunch_cmd, shell=False)
       
   269 
       
   270 
       
   271 class SyncComp(Task):
       
   272     
       
   273     def __init__(self, key):
       
   274         self.key = key
       
   275 
       
   276     def __get_name(self):
       
   277         return "sync_" + self.key
       
   278     
       
   279     name = property(__get_name)
       
   280     
       
   281     def run(self, version):
       
   282         print(green("sync ldt with version %s" % version))
       
   283         export_path_web = export_version(web=version)    
       
   284         export_path_web_full = os.path.join(export_path_web,'web')
       
   285         comp_versions = get_comp_versions_dict(export_path_web_full)
       
   286 
       
   287         export_path = export_version(**{self.key:comp_versions[self.key]})
       
   288         export_path_full = os.path.join(export_path,self.key)
       
   289         do_sync_comp(self.key, export_path_full)
       
   290         clean_export_folder(export_path)
       
   291         clean_export_folder(export_path_web)
       
   292         
       
   293         do_relaunch_server(do_collectstatic=True, do_syncdb=True)