### this works on linux only

import re
try:
    import fcntl
    import subprocess
    import signal
    import os
    import shutil
    from gluon.fileutils import read_file, write_file    
except:
    session.flash='sorry, only on Unix systems'
    redirect(URL(request.application,'default','site'))

forever=10**8

def kill():
    p = cache.ram('gae_upload',lambda:None,forever)
    if not p or p.poll()!=None:
        return 'oops'
    os.kill(p.pid, signal.SIGKILL)
    cache.ram('gae_upload',lambda:None,-1)

class EXISTS(object):
    def __init__(self, error_message='file not found'):
        self.error_message = error_message
    def __call__(self, value):
        if os.path.exists(value):
            return (value,None)
        return (value,self.error_message)

def deploy():
    regex = re.compile('^\w+$')
    apps = sorted(file for file in os.listdir(apath(r=request)) if regex.match(file))
    form = SQLFORM.factory(
        Field('appcfg',default=GAE_APPCFG,label='Path to appcfg.py',
              requires=EXISTS(error_message=T('file not found'))),
        Field('google_application_id',requires=IS_ALPHANUMERIC()),
        Field('applications','list:string',
              requires=IS_IN_SET(apps,multiple=True),
              label=T('web2py apps to deploy')),
        Field('email',requires=IS_EMAIL(),label=T('GAE Email')),
        Field('password','password',requires=IS_NOT_EMPTY(),label=T('GAE Password')))
    cmd = output = errors= ""
    if form.accepts(request,session):
        try:
            kill()
        except:
            pass
        ignore_apps = [item for item in apps \
                           if not item in form.vars.applications]
        regex = re.compile('\(applications/\(.*')
        yaml = apath('../app.yaml', r=request)
        if not os.path.exists(yaml):
            example = apath('../app.example.yaml', r=request)
            shutil.copyfile(example,yaml)            
        data = read_file(yaml)
        data = re.sub('application:.*','application: %s' % form.vars.google_application_id,data)
        data = regex.sub('(applications/(%s)/.*)|' % '|'.join(ignore_apps),data)
        write_file(yaml, data)

        path = request.env.applications_parent
        cmd = '%s --email=%s --passin update %s' % \
            (form.vars.appcfg, form.vars.email, path)
        p = cache.ram('gae_upload',
                      lambda s=subprocess,c=cmd:s.Popen(c, shell=True,
                                                        stdin=s.PIPE,
                                                        stdout=s.PIPE,
                                                        stderr=s.PIPE, close_fds=True),-1)
        p.stdin.write(form.vars.password+'\n')
        fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
        fcntl.fcntl(p.stderr.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
    return dict(form=form,command=cmd)

def callback():
    p = cache.ram('gae_upload',lambda:None,forever)
    if not p or p.poll()!=None:
        return '<done/>'
    try:
        output = p.stdout.read()
    except:
        output=''
    try:
        errors = p.stderr.read()
    except:
        errors=''
    return (output+errors).replace('\n','<br/>')
