initial commit

This commit is contained in:
Massimo Di Pierro
2011-11-22 23:30:42 -06:00
commit d421c1321b
580 changed files with 115527 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
#
# This files allows to delegate authentication for every URL within a domain
# to a web2py app within the same domain
# If you are logged in the app, you have access to the URL
# even if the URL is not a web2py URL
#
# in /etc/apache2/sites-available/default
#
# <VirtualHost *:80>
# WSGIDaemonProcess web2py user=www-data group=www-data
# WSGIProcessGroup web2py
# WSGIScriptAlias / /home/www-data/web2py/wsgihandler.py
#
# AliasMatch ^myapp/whatever/myfile /path/to/myfile
# <Directory /path/to/>
# WSGIAccessScript /path/to/web2py/scripts/access.wsgi
# </Directory>
# </VirtualHost>
#
# in yourapp/controllers/default.py
#
# def check_access():
# request_uri = request.vars.request_uri
# return 'true' if auth.is_logged_in() else 'false'
#
# start web2py as deamon
#
# nohup python web2py.py -a '' -p 8002
#
# now try visit:
#
# http://domain/myapp/whatever/myfile
#
# and you will have access ONLY if you are logged into myapp
#
URL_CHECK_ACCESS = 'http://127.0.0.1:8002/%(app)s/default/check_access'
def allow_access(environ,host):
import os
import urllib
import urllib2
import datetime
header = '%s @ %s ' % (datetime.datetime.now(),host) + '='*20
pprint = '\n'.join('%s:%s' % item for item in environ.items())
filename = os.path.join(os.path.dirname(__file__),'access.wsgi.log')
f = open(filename,'a')
try:
f.write('\n'+header+'\n'+pprint+'\n')
finally:
f.close()
app = environ['REQUEST_URI'].split('/')[1]
keys = [key for key in environ if key.startswith('HTTP_')]
headers = {}
for key in environ:
if key.startswith('HTTP_'):
headers[key[5:]] = environ[key] # this passes the cookies through!
try:
data = urllib.urlencode({'request_uri':environ['REQUEST_URI']})
request = urllib2.Request(URL_CHECK_ACCESS % dict(app=app),data,headers)
response = urllib2.urlopen(request).read().strip().lower()
if response.startswith('true'): return True
except: pass
return False
+141
View File
@@ -0,0 +1,141 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
autoroutes writes routes for you based on a simpler routing
configuration file called routes.conf. Example:
----- BEGIN routes.conf-------
127.0.0.1 /examples/default
domain1.com /app1/default
domain2.com /app2/default
domain3.com /app3/default
----- END ----------
It maps a domain (the left-hand side) to an app (one app per domain),
and shortens the URLs for the app by removing the listed path prefix. That means:
http://domain1.com/index is mapped to /app1/default/index
http://domain2.com/index is mapped to /app2/default/index
It preserves admin, appadmin, static files, favicon.ico and robots.txt:
http://domain1.com/favicon.ico /welcome/static/favicon.ico
http://domain1.com/robots.txt /welcome/static/robots.txt
http://domain1.com/admin/... /admin/...
http://domain1.com/appadmin/... /app1/appadmin/...
http://domain1.com/static/... /app1/static/...
and vice-versa.
To use, cp scripts/autoroutes.py routes.py
and either edit the config string below, or set config = "" and edit routes.conf
'''
config = '''
127.0.0.1 /examples/default
domain1.com /app1/default
domain2.com /app2/default
domain3.com /app3/defcon3
'''
if not config.strip():
try:
config_file = open('routes.conf','r')
try:
config = config_file.read()
finally:
config_file.close()
except:
config=''
def auto_in(apps):
routes = [
('/robots.txt','/welcome/static/robots.txt'),
('/favicon.ico','/welcome/static/favicon.ico'),
('/admin$anything','/admin$anything'),
]
for domain,path in [x.strip().split() for x in apps.split('\n') if x.strip() and not x.strip().startswith('#')]:
if not path.startswith('/'): path = '/'+path
if path.endswith('/'): path = path[:-1]
app = path.split('/')[1]
routes += [
('.*:https?://(.*\.)?%s:$method /' % domain,'%s' % path),
('.*:https?://(.*\.)?%s:$method /static/$anything' % domain,'/%s/static/$anything' % app),
('.*:https?://(.*\.)?%s:$method /appadmin/$anything' % domain,'/%s/appadmin/$anything' % app),
('.*:https?://(.*\.)?%s:$method /$anything' % domain,'%s/$anything' % path),
]
return routes
def auto_out(apps):
routes = []
for domain,path in [x.strip().split() for x in apps.split('\n') if x.strip() and not x.strip().startswith('#')]:
if not path.startswith('/'): path = '/'+path
if path.endswith('/'): path = path[:-1]
app = path.split('/')[1]
routes += [
('/%s/static/$anything' % app,'/static/$anything'),
('/%s/appadmin/$anything' % app, '/appadmin/$anything'),
('%s/$anything' % path, '/$anything'),
]
return routes
routes_in = auto_in(config)
routes_out = auto_out(config)
def __routes_doctest():
'''
Dummy function for doctesting autoroutes.py.
Use filter_url() to test incoming or outgoing routes;
filter_err() for error redirection.
filter_url() accepts overrides for method and remote host:
filter_url(url, method='get', remote='0.0.0.0', out=False)
filter_err() accepts overrides for application and ticket:
filter_err(status, application='app', ticket='tkt')
>>> filter_url('http://domain1.com/favicon.ico')
'http://domain1.com/welcome/static/favicon.ico'
>>> filter_url('https://domain2.com/robots.txt')
'https://domain2.com/welcome/static/robots.txt'
>>> filter_url('http://domain3.com/fcn')
'http://domain3.com/app3/defcon3/fcn'
>>> filter_url('http://127.0.0.1/fcn')
'http://127.0.0.1/examples/default/fcn'
>>> filter_url('HTTP://DOMAIN.COM/app/ctr/fcn')
'http://domain.com/app/ctr/fcn'
>>> filter_url('http://domain.com/app/ctr/fcn?query')
'http://domain.com/app/ctr/fcn?query'
>>> filter_url('http://otherdomain.com/fcn')
'http://otherdomain.com/fcn'
>>> regex_filter_out('/app/ctr/fcn')
'/app/ctr/fcn'
>>> regex_filter_out('/app1/ctr/fcn')
'/app1/ctr/fcn'
>>> filter_url('https://otherdomain.com/app1/default/fcn', out=True)
'/fcn'
>>> filter_url('http://otherdomain.com/app2/ctr/fcn', out=True)
'/app2/ctr/fcn'
>>> filter_url('http://domain1.com/app1/default/fcn?query', out=True)
'/fcn?query'
>>> filter_url('http://domain2.com/app3/defcon3/fcn#anchor', out=True)
'/fcn#anchor'
'''
pass
if __name__ == '__main__':
try:
import gluon.main
except ImportError:
import sys, os
os.chdir(os.path.dirname(os.path.dirname(__file__)))
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
import gluon.main
from gluon.rewrite import regex_select, load, filter_url, regex_filter_out
regex_select() # use base routing parameters
load(routes=__file__) # load this file
import doctest
doctest.testmod()
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import re
filename = sys.argv[1]
datafile = open(filename, 'r')
try:
data = '\n'+datafile.read()
finally:
datafile.close()
SPACE = '\n ' if '-n' in sys.argv[1:] else ' '
data = re.compile('(?<!\:)//(?P<a>.*)').sub('/* \g<a> */',data)
data = re.compile('[ ]+').sub(' ', data)
data = re.compile('\s*{\s*').sub(' {'+SPACE, data)
data = re.compile('\s*;\s*').sub(';'+SPACE, data)
data = re.compile(',\s*').sub(', ', data)
data = re.compile('\s*\*/\s*').sub('*/'+SPACE, data)
data = re.compile('\s*}\s*').sub(SPACE+'}\n', data)
data = re.compile('\n\s*\n').sub('\n', data)
data = re.compile(';\s+/\*').sub('; /*',data)
data = re.compile('\*/\s+/\*').sub(' ',data)
data = re.compile('[ ]+\n').sub('\n', data)
data = re.compile('\n\s*/[\*]+(?P<a>.*?)[\*]+/',re.DOTALL).sub(
'\n/*\g<a>*/\n',data)
data = re.compile('[ \t]+(?P<a>\S.+?){').sub('\g<a>{',data)
data = data.replace('}','}\n')
print data
+61
View File
@@ -0,0 +1,61 @@
import sys
import re
def cleancss(text):
text=re.compile('\s+').sub(' ', text)
text=re.compile('\s*(?P<a>,|:)\s*').sub('\g<a> ', text)
text=re.compile('\s*;\s*').sub(';\n ', text)
text=re.compile('\s*\{\s*').sub(' {\n ', text)
text=re.compile('\s*\}\s*').sub('\n}\n\n', text)
return text
def cleanhtml(text):
text=text.lower()
r=re.compile('\<script.+?/script\>', re.DOTALL)
scripts=r.findall(text)
text=r.sub('<script />', text)
r=re.compile('\<style.+?/style\>', re.DOTALL)
styles=r.findall(text)
text=r.sub('<style />', text)
text=re.compile(
'<(?P<tag>(input|meta|link|hr|br|img|param))(?P<any>[^\>]*)\s*(?<!/)>')\
.sub('<\g<tag>\g<any> />', text)
text=text.replace('\n', ' ')
text=text.replace('>', '>\n')
text=text.replace('<', '\n<')
text=re.compile('\s*\n\s*').sub('\n', text)
lines=text.split('\n')
(indent, newlines)=(0, [])
for line in lines:
if line[:2]=='</': indent=indent-1
newlines.append(indent*' '+line)
if not line[:2]=='</' and line[-1:]=='>' and \
not line[-2:] in ['/>', '->']: indent=indent+1
text='\n'.join(newlines)
text=re.compile('\<div(?P<a>( .+)?)\>\s+\</div\>').sub('<div\g<a>></div>',text)
text=re.compile('\<a(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</a\>').sub('<a\g<a>>\g<b></a>',text)
text=re.compile('\<b(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</b\>').sub('<b\g<a>>\g<b></b>',text)
text=re.compile('\<i(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</i\>').sub('<i\g<a>>\g<b></i>',text)
text=re.compile('\<span(?P<a>( .+)?)\>\s+(?P<b>[\w\s\(\)\/]+?)\s+\</span\>').sub('<span\g<a>>\g<b></span>',text)
text=re.compile('\s+\<br(?P<a>.*?)\/\>').sub('<br\g<a>/>',text)
text=re.compile('\>(?P<a>\s+)(?P<b>[\.\,\:\;])').sub('>\g<b>\g<a>',text)
text=re.compile('\n\s*\n').sub('\n',text)
for script in scripts:
text=text.replace('<script />', script, 1)
for style in styles:
text=text.replace('<style />', cleancss(style), 1)
return text
def read_file(filename):
f = open(filename, 'r')
try:
return f.read()
finally:
f.close()
file=sys.argv[1]
if file[-4:]=='.css':
print cleancss(read_file(file))
if file[-5:]=='.html':
print cleanhtml(read_file(file))
+17
View File
@@ -0,0 +1,17 @@
import re
def cleanjs(text):
text = re.sub('\s*}\s*','\n}\n',text)
text = re.sub('\s*{\s*',' {\n',text)
text = re.sub('\s*;\s*',';\n',text)
text = re.sub('\s*,\s*',', ',text)
text = re.sub('\s*(?P<a>[\+\-\*/\=]+)\s*',' \g<a> ',text)
lines = text.split('\n')
text=''
indent=0
for line in lines:
rline=line.strip()
if rline:
pass
return text
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cStringIO
import re
import sys
import tarfile
import urllib
import xml.parsers.expat as expat
"""
Update script for contenttype.py module.
Usage: python contentupdate.py /path/to/contenttype.py
If no path is specified, script will look for contenttype.py in current
working directory.
Internet connection is required to perform the update.
"""
OVERRIDE = [
('.pdb', 'chemical/x-pdb'),
('.xyz', 'chemical/x-pdb')
]
class MIMEParser(dict):
def __start_element_handler(self, name, attrs):
if name == 'mime-type':
if self.type:
for extension in self.extensions:
self[extension] = self.type
self.type = attrs['type'].lower()
self.extensions = []
elif name == 'glob':
pattern = attrs['pattern']
if pattern.startswith('*.'):
self.extensions.append(pattern[1:].lower())
def __init__(self, fileobj):
dict.__init__(self)
self.type = ''
self.extensions = ''
parser = expat.ParserCreate()
parser.StartElementHandler = self.__start_element_handler
parser.ParseFile(fileobj)
for extension, contenttype in OVERRIDE:
self[extension] = contenttype
if __name__ == '__main__':
try:
path = sys.argv[1]
except:
path = 'contenttype.py'
vregex = re.compile('database version (?P<version>.+?)\.?\n')
sys.stdout.write('Checking contenttype.py database version:')
sys.stdout.flush()
try:
pathfile = open(path)
try:
current = pathfile.read()
finally:
pathfile.close()
cversion = re.search(vregex, current).group('version')
sys.stdout.write('\t[OK] version %s\n' % cversion)
except Exception, e:
sys.stdout.write('\t[ERROR] %s\n' % e)
exit()
sys.stdout.write('Checking freedesktop.org database version:')
sys.stdout.flush()
try:
search = re.search('(?P<url>http://freedesktop.org/.+?/shared-mime-info-(?P<version>.+?)\.tar\.(?P<type>[gb]z2?))',
urllib.urlopen('http://www.freedesktop.org/wiki/Software/shared-mime-info').read())
url = search.group('url')
assert url != None
nversion = search.group('version')
assert nversion != None
ftype = search.group('type')
assert ftype != None
sys.stdout.write('\t[OK] version %s\n' % nversion)
except:
sys.stdout.write('\t[ERROR] unknown version\n')
exit()
if cversion == nversion:
sys.stdout.write('\nContenttype.py database is up to date\n')
exit()
try:
raw_input('\nContenttype.py database updates are available from:\n%s (approx. 0.5MB)\nPress enter to continue or CTRL-C to quit now\nWARNING: this will replace contenttype.py file content IN PLACE' % url)
except:
exit()
sys.stdout.write('\nDownloading new database:')
sys.stdout.flush()
fregex = re.compile('^.*/freedesktop\.org\.xml$')
try:
io = cStringIO.StringIO()
io.write(urllib.urlopen(url).read())
sys.stdout.write('\t[OK] done\n')
except Exception, e:
sys.stdout.write('\t[ERROR] %s\n' % e)
exit()
sys.stdout.write('Installing new database:')
sys.stdout.flush()
try:
tar = tarfile.TarFile.open(fileobj=io, mode='r:%s' % ftype)
try:
for content in tar.getnames():
if fregex.match(content):
xml = tar.extractfile(content)
break
finally:
tar.close()
data = MIMEParser(xml)
io = cStringIO.StringIO()
io.write('CONTENT_TYPE = {\n')
for key in sorted(data):
io.write(' \'%s\': \'%s\',\n' % (key, data[key]))
io.write(' }')
io.seek(0)
contenttype = open('contenttype.py', 'w')
try:
contenttype.write(re.sub(vregex, 'database version %s.\n' % nversion, re.sub('CONTENT_TYPE = \{(.|\n)+?\}', io.getvalue(), current)))
finally:
contenttype.close()
if not current.closed:
current.close()
sys.stdout.write('\t\t\t[OK] done\n')
except Exception, e:
sys.stdout.write('\t\t\t[ERROR] %s\n' % e)
+682
View File
@@ -0,0 +1,682 @@
import os,sys
from collections import deque
import string
import argparse
import cStringIO,operator
import cPickle as pickle
from collections import deque
import math
import re
import cmd
import readline
try:
from gluon import DAL
except ImportError as err:
print('gluon path not found')
class refTable(object):
def __init__(self):
self.columns = None
self.rows = None
def getcolHeader(self,colHeader):
return "{0}".format(' | '.join([string.join(string.strip('**{0}**'.format(item)),
'') for item in colHeader]))
def wrapTable(self,rows, hasHeader=False, headerChar='-', delim=' | ', justify='left',
separateRows=False, prefix='', postfix='', wrapfunc=lambda x:x):
def rowWrapper(row):
'''---
newRows is returned like
[['w'], ['x'], ['y'], ['z']]
---'''
newRows = [wrapfunc(item).split('\n') for item in row]
self.rows = newRows
'''---
rowList gives like newRows but
formatted like [[w, x, y, z]]
---'''
rowList = [[substr or '' for substr in item] for item in map(None,*newRows)]
return rowList
logicalRows = [rowWrapper(row) for row in rows]
columns = map(None,*reduce(operator.add,logicalRows))
self.columns = columns
maxWidths = [max(\
[len(str\
(item)) for \
item in column]\
) for column \
in columns]
rowSeparator = headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + \
len(delim)*(len(maxWidths)-1))
justify = {'center'\
:str\
.center,
'right'\
:str\
.rjust,
'left'\
:str.\
ljust\
}[justify\
.lower(\
)]
output=cStringIO.StringIO()
if separateRows:
print >> output, rowSeparator
for physicalRows in logicalRows:
for row in physicalRows:
print >> output,\
prefix + delim.join([\
justify(str(item),width) for (\
item,width) in zip(row,maxWidths)]\
) + postfix
if separateRows or hasHeader:
print >> output, rowSeparator; hasHeader=False
return output.getvalue()
def wrap_onspace(self,text,width):
return reduce(lambda line, word, width=width: '{0}{1}{2}'\
.format(line\
,' \n'[(len(\
line[line.rfind('\n'\
) + 1:]) + len(\
word.split('\n',1)[0]) >=\
width)],word),text.split(' '))
def wrap_onspace_strict(self,text,width):
wordRegex = re.compile(r'\S{'+str(width)+r',}')
return self.wrap_onspace(\
wordRegex.sub(\
lambda m: self.\
wrap_always(\
m.group(),width),text\
),width)
def wrap_always(self,text,width):
return '\n'.join(\
[ text[width*i:width*(i+1\
)] for i in xrange(\
int(math.ceil(1.*len(\
text)/width))) ])
class tableHelper():
def __init__(self):
self.oTable = refTable()
def getAsRows(self,data):
return [row.strip().split(',') for row in data.splitlines()]
def getTable_noWrap(self,data,header=None):
rows = self.getAsRows(data)
if header is not None:hRows = [header]+rows
else:hRows = rows
table = self.oTable.wrapTable(hRows, hasHeader=True)
return table
def getTable_Wrap(self,data,wrapStyle,header=None,width=65):
wrapper = None
if len(wrapStyle) > 1:
rows = self.getAsRows(data)
if header is not None:hRows = [header]+rows
else:hRows = rows
for wrapper in (self.oTable.wrap_always,
self.oTable.wrap_onspace,
self.oTable.wrap_onspace_strict):
return self.oTable.wrapTable(hRows\
,hasHeader=True\
,separateRows=True\
,prefix='| '\
,postfix=' |'\
,wrapfunc\
=lambda x:\
wrapper(x,width))
else:
return self.getTable_noWrap(data,header)
def getAsErrorTable(self,err):
return self.getTable_Wrap(err,None)
class console:
def __init__(self,prompt,banner=None):
self.prompt=prompt
self.banner=banner
self.commands={}
self.commandSort=[]
self.db=None
for i in dir(self):
if "cmd_"==i[:4]:
cmd=i.split("cmd_")[1].lower()
self.commands[cmd]=getattr(self,i)
try:self.commandSort.append((int(self\
.commands[cmd].__doc__.split(\
"|")[0]),cmd))
except:pass
self.commandSort.sort()
self.commandSort=[i[1] for i in self.commandSort]
self.var_DEBUG=False
self.var_tableStyle=''
self.configvars={}
for i in dir(self):
if "var_"==i[:4]:
var=i.split("var_")[1]
self.configvars[var]=i
def setBanner(self,banner):
self.banner=banner
def execCmd(self,db):
self.db=db
print self.banner
while True:
try:
command=raw_input(self.prompt)
try:
self.execCommand(command)
except:
self.execute(command)
except KeyboardInterrupt:break
except EOFError:break
except Exception,a:self.printError (a)
print ("\r\n\r\nBye!...")
sys.exit(0)
def printError(self,err):
sys.stderr.write("Error: {0}\r\n".format(str(err),))
if self.var_DEBUG:pass
def execute(self,cmd):
try:
if not '-table ' in cmd:
exec '{0}'.format(cmd)
else:
file=None
table=None
fields=[]
items=string.split(cmd,' ')
invalidParams=[]
table=self.getTable(items[1])
allowedParams=['fields','file']
for i in items:
if '=' in i and not string.split(i,'=')[0] in allowedParams:
try:
invalidParams.append(i)
except Exception, err:
raise Exception, 'invalid parameter\n{0}'.format(i)
else:
if 'file=' in i:
file=os.path.abspath(string.strip(string.split(i,'=')[1]))
if 'fields=' in i:
for field in string.split(string.split(i,'=')[1],','):
if field in self.db[table].fields:
fields.append(string.strip(field))
if len(invalidParams)>0:
print('the following parameter(s) is not valid\n{0}'.format(\
string.join(invalidParams,',')))
else:
try:
self.cmd_table(table,file,fields)
except Exception, err:
print('could not generate table for table {0}\n{1}'\
.format(table,err))
except Exception, err:
print('sorry, can not do that!\n{0}'.format(err))
def getTable(self,tbl):
for mTbl in db.tables:
if tbl in mTbl:
if mTbl.startswith(tbl):
return mTbl
def execCommand(self,cmd):
words=cmd.split(" ")
words=[i for i in words if i]
if not words:return
cmd,parameters=words[0].lower(),words[1:]
if not cmd in self.commands:
raise Exception("Command {0} not found. Try 'help'\r\n".format(cmd))
self.commands[cmd](*parameters)
'''---
DEFAULT COMMANDS (begins with cmd_)
---'''
def cmd_clear(self,numlines=100):
"""-5|clear|clear the screen"""
if os.name == "posix":
'''---
Unix/Linux/MacOS/BSD/etc
---'''
os.system('clear')
elif os.name in ("nt", "dos", "ce"):
'''---
Windows
---'''
os.system('CLS')
else:
'''---
Fallback for other operating systems.
---'''
print '\n'*numlines
def cmd_table(self,tbl,file=None,fields=[]):
"""-4|-table [TABLENAME] optional[file=None] [fields=None]|\
the default tableStyle is no_wrap - use the 'set x y' command to change the style\n\
style choices:
\twrap_always
\twrap_onspace
\twrap_onspace_strict
\tno_wrap (value '')\n
\t the 2nd optional param is a path to a file where the table will be written
\t the 3rd optional param is a list of fields you want displayed\n"""
table=None
for mTbl in db.tables:
if tbl in mTbl:
if mTbl.startswith(tbl):
table=mTbl
break
oTable=tableHelper()
'''---
tablestyle:
wrap_always
wrap_onspace
wrap_onspace_strict
or set set to "" for no wrapping
---'''
tableStyle=self.var_tableStyle
filedNotFound=[]
table_fields=None
if len(fields)==0:
table_fields=self.db[table].fields
else:
table_fields=fields
for field in fields:
if not field in self.db[table].fields:
filedNotFound.append(field)
if len(filedNotFound)==0:
rows=self.db(self.db[table].id>0).select()
rows_data=[]
for row in rows:
rowdata=[]
for f in table_fields:
rowdata.append('{0}'.format(row[f]))
rows_data.append(string.join(rowdata,','))
data=string.join(rows_data,'\n')
dataTable=oTable.getTable_Wrap(data,tableStyle,table_fields)
print('TABLE {0}\n{1}'.format(table,dataTable))
if file!=None:
try:
tail,head=os.path.split(file)
try:
os.makedirs(tail)
except:'do nothing, folders exist'
oFile=open(file,'w')
oFile.write('TABLE: {0}\n{1}'.format(table,dataTable))
oFile.close()
print('{0} has been created and populated with all available data from table {1}\n'.format(file,table))
except Exception, err:
print("EXCEPTION: could not create table {0}\n{1}".format(table,err))
else:
print('the following fields are not valid [{0}]'.format(string.join(filedNotFound,',')))
def cmd_help(self,*args):
'''-3|help|Show's help'''
alldata=[]
lengths=[]
for i in self.commandSort:alldata.append(\
self.commands[i].__doc__.split("|")[1:])
for i in alldata:
if len(i) > len(lengths):
for j in range(len(i)\
-len(lengths)):
lengths.append(0)
j=0
while j<len(i):
if len(i[j])>lengths[j]:
lengths[j]=len(i[j])
j+=1
print ("-"*(lengths[0]+lengths[1]+4))
for i in alldata:
print (("%-"+str(lengths[0])+"s - %-"+str(lengths[1])+"s") % (i[0],i[1]))
if len(i)>2:
for j in i[2:]:print (("%"+str(lengths[0]+9)+"s* %s") % (" ",j))
print
def cmd_vars(self,*args):
'''-2|vars|Show variables'''
print ("variables\r\n"+"-"*79)
for i,j in self.configvars.items():
value=self.parfmt(repr(getattr(self,j)),52)
print ("| %20s | %52s |" % (i,value[0]))
for k in value[1:]:print ("| %20s | %52s |" % ("",k))
if len(value)>1:print("| %20s | %52s |" % ("",""))
print ("-"*79)
def parfmt(self,txt,width):
res=[]
pos=0
while True:
a=txt[pos:pos+width]
if not a:break
res.append(a)
pos+=width
return res
def cmd_set(self,*args):
'''-1|set [variable_name] [value]|Set configuration variable value|Values are an expressions (100 | string.lower('ABC') | etc.'''
value=" ".join(args[1:])
if args[0] not in self.configvars:
setattr(self,"var_{0}".format(args[0]),eval(value))
setattr(self,"var_{0}".format(args[0]),eval(value))
def cmd_clearscreen(self,numlines=50):
'''---Clear the console.
---'''
if os.name == "posix":
'''---
Unix/Linux/MacOS/BSD/etc
---'''
os.system('clear')
elif os.name in ("nt", "dos", "ce"):
'''---
Windows
---'''
os.system('CLS')
else:
'''---
Fallback for other operating systems.
---'''
print '\n'*numlines
class dalShell(console):
def __init__(self):
pass
def shell(self,db):
console.__init__(self,prompt=">>> ",banner='dal interactive shell')
self.execCmd(db)
class setCopyDB():
def __init__(self):
'''---
non source or target specific vars
---'''
self.strModel=None
self.dalPath=None
self.db=None
'''---
source vars
---'''
self.sourceModel=None
self.sourceFolder=None
self.sourceConnectionString=None
self.sourcedbType=None
self.sourcedbName=None
'''---
target vars
---'''
self.targetdbType=None
self.targetdbName=None
self.targetModel=None
self.targetFolder=None
self.targetConnectionString=None
self.truncate=False
def _getDal(self):
mDal=None
if self.dalPath is not None:
global DAL
sys.path.append(self.dalPath)
mDal=__import__('dal',globals={},locals={},fromlist=['DAL'],level=0)
DAL=mDal.DAL
return mDal
def instDB(self,storageFolder,storageConnectionString,autoImport):
self.db=DAL(storageConnectionString,folder=os.path.abspath(storageFolder),auto_import=autoImport)
return self.db
def delete_DB_tables(self,storageFolder,storageType):
print 'delete_DB_tablesn\n\t{0}\n\t{1}'.format(storageFolder,storageType)
dataFiles=[storageType,"sql.log"]
try:
for f in os.listdir(storageFolder):
if ".table" in f:
fTable="{0}/{1}".format(storageFolder,f)
os.remove(fTable)
print('deleted {0}'.format(fTable))
for dFile in dataFiles:
os.remove("{0}/{1}".format(storageFolder,dFile))
print('deleted {0}'.format("{0}/{1}".format(storageFolder,dFile)))
except Exception, errObj:
print(str(errObj))
def truncatetables(self,tables=[]):
if len(tables)!=0:
try:
print 'table value: {0}'.format(tables)
for tbl in self.db.tables:
for mTbl in tables:
if mTbl.startswith(tbl):
self.db[mTbl].truncate()
except Exception, err:
print('EXCEPTION: {0}'.format(err))
else:
try:
for tbl in self.db.tables:
self.db[tbl].truncate()
except Exception, err:
print('EXCEPTION: {0}'.format(err))
def copyDB(self):
other_db=DAL("{0}://{1}".format(self.targetdbType,self.targetdbName),folder=self.targetFolder)
print 'creating tables...'
for table in self.db:
other_db.define_table(table._tablename,*[field for field in table])
'''
should there be an option to truncAte target DB?
if yes, then change args to allow for choice
and set self.trancate to the art value
if self.truncate==True:
other_db[table._tablename].truncate()
'''
print 'exporting data...'
self.db.export_to_csv_file(open('tmp.sql','wb'))
print 'importing data...'
other_db.import_from_csv_file(open('tmp.sql','rb'))
other_db.commit()
print 'done!'
print 'Attention: do not run this program again or you end up with duplicate records'
def createfolderPath(self,folder):
try:
if folder!=None:os.makedirs(folder)
except Exception, err:
pass
if __name__ == '__main__':
oCopy=setCopyDB()
db=None
targetDB=None
dbfolder=None
clean=False
model=None
truncate=False
parser=argparse.ArgumentParser(description='\
samplecmd line:\n\
-f ./blueLite/db_storage -i -y sqlite://storage.sqlite -Y sqlite://storage2.sqlite -d ./blueLite/pyUtils/sql/blueSQL -t True',
epilog = '')
reqGroup=parser.add_argument_group('Required arguments')
reqGroup.add_argument('-f','--sourceFolder'\
,required=True\
,help="path to the 'source' folder of the 'source' DB")
reqGroup.add_argument('-F','--targetFolder'\
,required=False\
,help="path to the 'target' folder of the 'target' DB")
reqGroup.add_argument('-y','--sourceConnectionString'\
,required=True\
,help="source db connection string ()\n\
------------------------------------------------\n\
\
sqlite://storage.db\n\
mysql://username:password@localhost/test\n\
postgres://username:password@localhost/test\n\
mssql://username:password@localhost/test\n\
firebird://username:password@localhost/test\n\
oracle://username/password@test\n\
db2://username:password@test\n\
ingres://username:password@localhost/test\n\
informix://username:password@test\n\
\
------------------------------------------------")
reqGroup.add_argument('-Y','--targetConnectionString'\
,required=True\
,help="target db type (sqlite,mySql,etc.)")
autoImpGroup=parser.add_argument_group('optional args (auto_import)')
autoImpGroup.add_argument('-a','--autoimport'\
,required=False\
,help='set to True to bypass loading of the model')
"""
*** removing -m/-M options for now --> i need a
better regex to match db.define('bla')...with optional db.commit()
modelGroup=parser.add_argument_group('optional args (create model)')
modelGroup.add_argument('-m','--sourcemodel'\
,required=False\
,help='to create a model from an existing model, point to the source model')
modelGroup.add_argument('-M','--targetmodel'\
,required=False\
,help='to create a model from an existing model, point to the target model')
"""
miscGroup=parser.add_argument_group('optional args/tasks')
miscGroup.add_argument('-i','--interactive'\
,required=False\
,action='store_true'\
,help='run in interactive mode')
miscGroup.add_argument('-d','--dal'\
,required=False\
,help='path to dal.py')
miscGroup.add_argument('-t','--truncate'\
,choices=['True','False']\
,help='delete the records but *not* the table of the SOURCE DB')
miscGroup.add_argument('-b','--tables'\
,required=False\
,type=list\
,help='optional list (comma delimited) of SOURCE tables to truncate, defaults to all')
miscGroup.add_argument('-c','--clean'\
,required=False\
,help='delete the DB,tables and the log file, WARNING: this is unrecoverable')
args=parser.parse_args()
db=None
mDal=None
try:
oCopy.sourceFolder=args.sourceFolder
oCopy.targetFolder=args.sourceFolder
sourceItems=string.split(args.sourceConnectionString,'://')
oCopy.sourcedbType=sourceItems[0]
oCopy.sourcedbName=sourceItems[1]
targetItems=string.split(args.targetConnectionString,'://')
oCopy.targetdbType=sourceItems[0]
oCopy.targetdbName=sourceItems[1]
except Exception, err:
print('EXCEPTION: {0}'.format(err))
if args.dal:
try:
autoImport=True
if args.autoimport:autoImport=args.autoimport
#sif not DAL in globals:
#if not sys.path.__contains__():
oCopy.dalPath=args.dal
mDal=oCopy._getDal()
db=oCopy.instDB(args.sourceFolder,args.sourceConnectionString,autoImport)
except Exception, err:
print('EXCEPTION: could not set DAL\n{0}'.format(err))
if args.truncate:
try:
if args.truncate:
if args.tables:tables=string.split(string.strip(args.tables),',')
else:oCopy.truncatetables([])
except Exception, err:
print('EXCEPTION: could not truncate tables\n{0}'.format(err))
try:
if args.clean:oCopy.delete_DB_tables(oCopy.targetFolder,oCopy.targetType)
except Exception, err:
print('EXCEPTION: could not clean db\n{0}'.format(err))
"""
*** goes with -m/-M options... removed for now
if args.sourcemodel:
try:
oCopy.sourceModel=args.sourcemodel
oCopy.targetModel=args.sourcemodel
oCopy.createModel()
except Exception, err:
print('EXCEPTION: could not create model\n\
source model: {0}\n\
target model: {1}\n\
{2}'.format(args.sourcemodel,args.targetmodel,err))
"""
if args.sourceFolder:
try:
oCopy.sourceFolder=os.path.abspath(args.sourceFolder)
oCopy.createfolderPath(oCopy.sourceFolder)
except Exception, err:
print('EXCEPTION: could not create folder path\n{0}'.format(err))
else:oCopy.dbStorageFolder=os.path.abspath(os.getcwd())
if args.targetFolder:
try:
oCopy.targetFolder=os.path.abspath(args.targetFolder)
oCopy.createfolderPath(oCopy.targetFolder)
except Exception, err:
print('EXCEPTION: could not create folder path\n{0}'.format(err))
if not args.interactive:
try:
oCopy.copyDB()
except Exception, err:
print('EXCEPTION: could not make a copy of the database\n{0}'.format(err))
else:
s=dalShell()
s.shell(db)
+26
View File
@@ -0,0 +1,26 @@
import sys, glob, os, shutil
name=sys.argv[1]
app=sys.argv[2]
dest=sys.argv[3]
a=glob.glob('applications/%(app)s/*/plugin_%(name)s.*' % dict(app=app,name=name))
b=glob.glob('applications/%(app)s/*/plugin_%(name)s/*' % dict(app=app,name=name))
for f in a:
print 'cp %s ...' % f,
shutil.copyfile(f,os.path.join('applications',dest,*f.split('/')[2:]))
print 'done'
for f in b:
print 'cp %s ...' % f,
path = f.split('/')
for i in range(3,len(path)):
try: os.mkdir(os.path.join('applications',dest,*path[2:i]))
except: pass
path = os.path.join('applications',dest,*f.split('/')[2:])
if os.path.isdir(f):
if not os.path.exists(path):
shutil.copytree(f,path)
else:
shutil.copyfile(f,path)
print 'done'
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from datetime import datetime
from time import mktime
from time import sleep
from time import time
DB_URI = 'sqlite://sessions.sqlite'
EXPIRATION_MINUTES = 60
SLEEP_MINUTES = 5
while 1: # Infinite loop
now = time() # get current Unix timestamp
for row in db().select(db.web2py_session_welcome.ALL):
t = row.modified_datetime
# Convert to a Unix timestamp
t = mktime(t.timetuple())+1e-6*t.microsecond
if now - t > EXPIRATION_MINUTES * 60:
del db.web2py_session_welcome[row.id]
db.commit() # Write changes to database
sleep(SLEEP_MINUTES * 60)
+121
View File
@@ -0,0 +1,121 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
@author: Pierre Thibault (pierre.thibault1 -at- gmail.com)
@license: MIT
@since: 2011-06-17
Usage: dict_diff [OPTION]... dict1 dict2
Show the differences for two dictionaries.
-h, --help Display this help message.
dict1 and dict2 are two web2py dictionary files to compare. These are the files
located in the "languages" directory of a web2py app. The tools show the
differences between the two files.
'''
__docformat__ = "epytext en"
import getopt
import os.path
import sys
def main(argv):
"""Parse the arguments and start the main process."""
try:
opts, args = getopt.getopt(argv, "h", ["help"])
except getopt.GetoptError:
exit_with_parsing_error()
for opt, arg in opts:
arg = arg # To avoid a warning from Pydev
if opt in ("-h", "--help"):
usage()
sys.exit()
if len(args) == 2:
params = list(get_dicts(*args))
params.extend(get_dict_names(*args))
compare_dicts(*params)
else:
exit_with_parsing_error()
def exit_with_parsing_error():
"""Report invalid arguments and usage."""
print("Invalid argument(s).")
usage()
sys.exit(2)
def usage():
"""Display the documentation"""
print(__doc__)
def get_dicts(dict_path1, dict_path2):
"""
Parse the dictionaries.
@param dict_path1: The path to the first dictionary.
@param dict_path2: The path to the second dictionary.
@return: The two dictionaries as a sequence.
"""
return eval(open(dict_path1).read()), eval(open(dict_path2).read())
def get_dict_names(dict1_path, dict2_path):
"""
Get the name of the dictionaries for the end user. Use the base name of the
files. If the two base names are identical, returns "dict1" and "dict2."
@param dict1_path: The path to the first dictionary.
@param dict2_path: The path to the second dictionary.
@return: The two dictionary names as a sequence.
"""
dict1_name = os.path.basename(dict1_path)
dict2_name = os.path.basename(dict2_path)
if dict1_name == dict2_name:
dict1_name = "dict1"
dict2_name = "dict2"
return dict1_name, dict2_name
def compare_dicts(dict1, dict2, dict1_name, dict2_name):
"""
Compare the two dictionaries. Print out the result.
@param dict1: The first dictionary.
@param dict1: The second dictionary.
@param dict1_name: The name of the first dictionary.
@param dict2_name: The name of the second dictionary.
"""
dict1_keyset = set(dict1.keys())
dict2_keyset = set(dict2.keys())
print_key_diff(dict1_keyset - dict2_keyset, dict1_name, dict2_name)
print_key_diff(dict2_keyset - dict1_keyset, dict2_name, dict1_name)
print "Value differences:"
has_value_differences = False
for key in dict1_keyset & dict2_keyset:
if dict1[key] != dict2[key]:
print " %s:" % (key,)
print " %s: %s" % (dict1_name, dict1[key],)
print " %s: %s" % (dict2_name, dict2[key],)
print
has_value_differences = True
if not has_value_differences:
print " None"
def print_key_diff(key_diff, dict1_name, dict2_name):
"""
Prints the keys in the first dictionary and are in the second dictionary.
@param key_diff: Keys in dictionary 1 not in dictionary 2.
@param dict1_name: Name used for the first dictionary.
@param dict2_name: Name used for the second dictionary.
"""
print "Keys in %s not in %s:" % (dict1_name, dict2_name)
if len(key_diff):
for key in key_diff:
print " %s" % (key,)
else:
print " None"
print
if __name__ == "__main__":
main(sys.argv[1:]) # Start the process (without the application name)
+107
View File
@@ -0,0 +1,107 @@
'''
Create the web2py code needed to access your mysql legacy db.
To make this work all the legacy tables you want to access need to have an "id" field.
This plugin needs:
mysql
mysqldump
installed and globally available.
Under Windows you will probably need to add the mysql executable directory to the PATH variable,
you will also need to modify mysql to mysql.exe and mysqldump to mysqldump.exe below.
Just guessing here :)
Access your tables with:
legacy_db(legacy_db.mytable.id>0).select()
If the script crashes this is might be due to that fact that the data_type_map dictionary below is incomplete.
Please complete it, improve it and continue.
Created by Falko Krause, minor modifications by Massimo Di Pierro and Ron McOuat
'''
import subprocess
import re
import sys
data_type_map = dict(
varchar = 'string',
int = 'integer',
integer = 'integer',
tinyint = 'integer',
smallint = 'integer',
mediumint = 'integer',
bigint = 'integer',
float = 'double',
double = 'double',
char = 'string',
decimal = 'integer',
date = 'date',
#year = 'date',
time = 'time',
timestamp = 'datetime',
datetime = 'datetime',
binary = 'blob',
blob = 'blob',
tinyblob = 'blob',
mediumblob = 'blob',
longblob = 'blob',
text = 'text',
tinytext = 'text',
mediumtext = 'text',
longtext = 'text',
)
def mysql(database_name, username, password):
p = subprocess.Popen(['mysql',
'--user=%s' % username,
'--password=%s'% password,
'--execute=show tables;',
database_name],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
sql_showtables, stderr = p.communicate()
tables = [re.sub('\|\s+([^\|*])\s+.*', '\1', x) for x in sql_showtables.split()[1:]]
connection_string = "legacy_db = DAL('mysql://%s:%s@localhost/%s')"%(username, password, database_name)
legacy_db_table_web2py_code = []
for table_name in tables:
#get the sql create statement
p = subprocess.Popen(['mysqldump',
'--user=%s' % username,
'--password=%s' % password,
'--skip-add-drop-table',
'--no-data', database_name,
table_name], stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
sql_create_stmnt,stderr = p.communicate()
if 'CREATE' in sql_create_stmnt:#check if the table exists
#remove garbage lines from sql statement
sql_lines = sql_create_stmnt.split('\n')
sql_lines = [x for x in sql_lines if not(x.startswith('--') or x.startswith('/*') or x =='')]
#generate the web2py code from the create statement
web2py_table_code = ''
table_name = re.search('CREATE TABLE .(\S+). \(', sql_lines[0]).group(1)
fields = []
for line in sql_lines[1:-1]:
if re.search('KEY', line) or re.search('PRIMARY', line) or re.search(' ID', line) or line.startswith(')'):
continue
hit = re.search('(\S+)\s+(\S+)(,| )( .*)?', line)
if hit!=None:
name, d_type = hit.group(1), hit.group(2)
d_type = re.sub(r'(\w+)\(.*',r'\1',d_type)
name = re.sub('`','',name)
web2py_table_code += "\n Field('%s','%s'),"%(name,data_type_map[d_type])
web2py_table_code = "legacy_db.define_table('%s',%s\n migrate=False)"%(table_name,web2py_table_code)
legacy_db_table_web2py_code.append(web2py_table_code)
#----------------------------------------
#write the legacy db to file
legacy_db_web2py_code = connection_string+"\n\n"
legacy_db_web2py_code += "\n\n#--------\n".join(legacy_db_table_web2py_code)
return legacy_db_web2py_code
regex = re.compile('(.*?):(.*?)@(.*)')
if len(sys.argv)<2 or not regex.match(sys.argv[1]):
print 'USAGE:\n\n extract_mysql_models.py username:password@data_basename\n\n'
else:
m = regex.match(sys.argv[1])
print mysql(m.group(3),m.group(1),m.group(2))
+284
View File
@@ -0,0 +1,284 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Create web2py model (python code) to represent PostgreSQL tables.
Features:
* Uses ANSI Standard INFORMATION_SCHEMA (might work with other RDBMS)
* Detects legacy "keyed" tables (not having an "id" PK)
* Connects directly to running databases, no need to do a SQL dump
* Handles notnull, unique and referential constraints
* Detects most common datatypes and default values
* Support PostgreSQL columns comments (ie. for documentation)
Requeriments:
* Needs PostgreSQL pyscopg2 python connector (same as web2py)
* If used against other RDBMS, import and use proper connector (remove pg_ code)
Created by Mariano Reingart, based on a script to "generate schemas from dbs"
(mysql) by Alexandre Andrade
"""
_author__ = "Mariano Reingart <reingart@gmail.com>"
HELP = """
USAGE: extract_pgsql_models db host port user passwd
Call with PostgreSQL database connection parameters,
web2py model will be printed on standard output.
EXAMPLE: python extract_pgsql_models.py mydb localhost 5432 reingart saraza
"""
# Config options
DEBUG = False # print debug messages to STDERR
SCHEMA = 'public' # change if not using default PostgreSQL schema
# Constant for Field keyword parameter order (and filter):
KWARGS = ('type', 'length', 'default', 'required', 'ondelete',
'notnull', 'unique', 'label', 'comment')
import sys
def query(conn, sql,*args):
"Execute a SQL query and return rows as a list of dicts"
cur = conn.cursor()
ret = []
try:
if DEBUG: print >> sys.stderr, "QUERY: ", sql % args
cur.execute(sql, args)
for row in cur:
dic = {}
for i, value in enumerate(row):
field = cur.description[i][0]
dic[field] = value
if DEBUG: print >> sys.stderr, "RET: ", dic
ret.append(dic)
return ret
finally:
cur.close()
def get_tables(conn, schema=SCHEMA):
"List table names in a given schema"
rows = query(conn, """SELECT table_name FROM information_schema.tables
WHERE table_schema = %s
ORDER BY table_name""", schema)
return [row['table_name'] for row in rows]
def get_fields(conn, table):
"Retrieve field list for a given table"
if DEBUG: print >> sys.stderr, "Processing TABLE", table
rows = query(conn, """
SELECT column_name, data_type,
is_nullable,
character_maximum_length,
numeric_precision, numeric_precision_radix, numeric_scale,
column_default
FROM information_schema.columns
WHERE table_name=%s
ORDER BY ordinal_position""", table)
return rows
def define_field(conn, table, field, pks):
"Determine field type, default value, references, etc."
f={}
ref = references(conn, table, field['column_name'])
if ref:
f.update(ref)
elif field['column_default'] and \
field['column_default'].startswith("nextval") and \
field['column_name'] in pks:
# postgresql sequence (SERIAL) and primary key!
f['type'] = "'id'"
elif field['data_type'].startswith('character'):
f['type'] = "'string'"
if field['character_maximum_length']:
f['length'] = field['character_maximum_length']
elif field['data_type'] in ('text', ):
f['type'] = "'text'"
elif field['data_type'] in ('boolean', 'bit'):
f['type'] = "'boolean'"
elif field['data_type'] in ('integer', 'smallint', 'bigint'):
f['type'] = "'integer'"
elif field['data_type'] in ('double precision', 'real' ):
f['type'] = "'double'"
elif field['data_type'] in ('timestamp', 'timestamp without time zone'):
f['type'] = "'datetime'"
elif field['data_type'] in ('date', ):
f['type'] = "'date'"
elif field['data_type'] in ('time', 'time without time zone'):
f['type'] = "'time'"
elif field['data_type'] in ('numeric', 'currency'):
f['type'] = "'decimal'"
f['precision'] = field['numeric_precision']
f['scale'] = field['numeric_scale'] or 0
elif field['data_type'] in ('bytea', ):
f['type'] = "'blob'"
elif field['data_type'] in ('point', 'lseg', 'polygon', 'unknown', 'USER-DEFINED'):
f['type'] = "" # unsupported?
else:
raise RuntimeError("Data Type not supported: %s " % str(field))
try:
if field['column_default']:
if field['column_default']=="now()":
d = "request.now"
elif field['column_default']=="true":
d = "True"
elif field['column_default']=="false":
d = "False"
else:
d = repr(eval(field['column_default']))
f['default'] = str(d)
except (ValueError, SyntaxError):
pass
except Exception, e:
raise RuntimeError("Default unsupported '%s'" % field['column_default'])
if not field['is_nullable']:
f['notnull'] = "True"
comment = get_comment(conn, table, field)
if comment is not None:
f['comment'] = repr(comment)
return f
def is_unique(conn, table, field):
"Find unique columns (incomplete support)"
rows = query(conn, """
SELECT information_schema.constraint_column_usage.column_name
FROM information_schema.table_constraints
NATURAL JOIN information_schema.constraint_column_usage
WHERE information_schema.table_constraints.table_name=%s
AND information_schema.constraint_column_usage.column_name=%s
AND information_schema.table_constraints.constraint_type='UNIQUE'
;""", table, field['column_name'])
return rows and True or False
def get_comment(conn, table, field):
"Find the column comment (postgres specific)"
rows = query(conn, """
SELECT d.description AS comment
FROM pg_class c
JOIN pg_description d ON c.oid=d.objoid
JOIN pg_attribute a ON c.oid = a.attrelid
WHERE c.relname=%s AND a.attname=%s
AND a.attnum = d.objsubid
;""", table, field['column_name'])
return rows and rows[0]['comment'] or None
def primarykeys(conn, table):
"Find primary keys"
rows = query(conn, """
SELECT information_schema.constraint_column_usage.column_name
FROM information_schema.table_constraints
NATURAL JOIN information_schema.constraint_column_usage
WHERE information_schema.table_constraints.table_name=%s
AND information_schema.table_constraints.constraint_type='PRIMARY KEY'
;""", table)
return [row['column_name'] for row in rows]
def references(conn, table, field):
"Find a FK (fails if multiple)"
rows1 = query(conn, """
SELECT table_name, column_name, constraint_name,
update_rule, delete_rule, ordinal_position
FROM information_schema.key_column_usage
NATURAL JOIN information_schema.referential_constraints
NATURAL JOIN information_schema.table_constraints
WHERE information_schema.key_column_usage.table_name=%s
AND information_schema.key_column_usage.column_name=%s
AND information_schema.table_constraints.constraint_type='FOREIGN KEY'
;""", table, field)
if len(rows1)==1:
rows2 = query(conn, """
SELECT table_name, column_name, *
FROM information_schema.constraint_column_usage
WHERE constraint_name=%s
""", rows1[0]['constraint_name'])
row = None
if len(rows2)>1:
row = rows2[int(rows1[0]['ordinal_position'])-1]
keyed = True
if len(rows2)==1:
row = rows2[0]
keyed = False
if row:
if keyed: # THIS IS BAD, DON'T MIX "id" and primarykey!!!
ref = {'type': "'reference %s.%s'" % (row['table_name'],
row['column_name'])}
else:
ref = {'type': "'reference %s'" % (row['table_name'],)}
if rows1[0]['delete_rule']!="NO ACTION":
ref['ondelete'] = repr(rows1[0]['delete_rule'])
return ref
elif rows2:
raise RuntimeError("Unsupported foreign key reference: %s" %
str(rows2))
elif rows1:
raise RuntimeError("Unsupported referential constraint: %s" %
str(rows1))
def define_table(conn, table):
"Output single table definition"
fields = get_fields(conn, table)
pks = primarykeys(conn, table)
print "db.define_table('%s'," % (table, )
for field in fields:
fname = field['column_name']
fdef = define_field(conn, table, field, pks)
if fname not in pks and is_unique(conn, table, field):
fdef['unique'] = "True"
if fdef['type']=="'id'" and fname in pks:
pks.pop(pks.index(fname))
print " Field('%s', %s)," % (fname,
', '.join(["%s=%s" % (k, fdef[k]) for k in KWARGS
if k in fdef and fdef[k]]))
if pks:
print " primarykey=[%s]," % ", ".join(["'%s'" % pk for pk in pks])
print " migrate=migrate)"
print
def define_db(conn, db, host, port, user, passwd):
"Output database definition (model)"
dal = 'db = DAL("postgres://%s:%s@%s:%s/%s", pool_size=10)'
print dal % (user, passwd, host, port, db)
print
print "migrate = False"
print
for table in get_tables(conn):
define_table(conn, table)
if __name__ == "__main__":
if len(sys.argv) < 6:
print HELP
else:
# Parse arguments from command line:
db, host, port, user, passwd = sys.argv[1:6]
# Make the database connection (change driver if required)
import psycopg2
cnn = psycopg2.connect(database=db, host=host, port=port,
user=user, password=passwd,
)
# Start model code generation:
define_db(cnn, db, host, port, user, passwd)
+24
View File
@@ -0,0 +1,24 @@
import sys, glob
def read_fileb(filename, mode='rb'):
f = open(filename, mode)
try:
return f.read()
finally:
f.close()
def write_fileb(filename, value, mode='wb'):
f = open(filename, mode)
try:
f.write(value)
finally:
f.close()
for filename in glob.glob(sys.argv[1]):
data1 = read_fileb(filename)
write_fileb(filename + '.bak2', data1)
data2lines = read_fileb(filename).split('\n')
data2 = '\n'.join([line.rstrip() for line in data2lines])+'\n'
write_fileb(filename, data2)
print filename, len(data1)-len(data2)
+99
View File
@@ -0,0 +1,99 @@
import glob
import os
import zipfile
import sys
import re
from BeautifulSoup import BeautifulSoup as BS
def head(styles):
title = '<title>{{=response.title or request.application}}</title>'
items = '\n'.join(["{{response.files.append(URL(request.application,'static','%s'))}}" % (style) for style in styles])
loc="""<style>
div.flash {
position: absolute;
float: right;
padding: 10px;
top: 0px;
right: 0px;
opacity: 0.75;
margin: 10px 10px 10px 10px;
text-align: center;
clear: both;
color: #fff;
font-size: 11pt;
text-align: center;
vertical-align: middle;
cursor: pointer;
background: black;
border: 2px solid #fff;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
z-index: 2;
}
div.error {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
background-color: red;
color: white;
padding: 3px;
border: 1px solid #666;
}
</style>"""
return "\n%s\n%s\n{{include 'web2py_ajax.html'}}\n%s" % (title,items,loc)
def content():
return """<div class="flash">{{=response.flash or ''}}</div>{{include}}"""
def process(folder):
indexfile = open(os.path.join(folder,'index.html'),'rb')
try:
soup = BS(indexfile.read())
finally:
indexfile.close()
styles = [x['href'] for x in soup.findAll('link')]
soup.find('head').contents=BS(head(styles))
try:
soup.find('h1').contents=BS('{{=response.title or request.application}}')
soup.find('h2').contents=BS("{{=response.subtitle or '=response.subtitle'}}")
except:
pass
for match in (soup.find('div',id='menu'),
soup.find('div',{'class':'menu'}),
soup.find('div',id='nav'),
soup.find('div',{'class':'nav'})):
if match:
match.contents=BS('{{=MENU(response.menu)}}')
break
done=False
for match in (soup.find('div',id='content'),
soup.find('div',{'class':'content'}),
soup.find('div',id='main'),
soup.find('div',{'class':'main'})):
if match:
match.contents=BS(content())
done=True
break
if done:
page = soup.prettify()
page = re.compile("\s*\{\{=response\.flash or ''\}\}\s*",re.MULTILINE)\
.sub("{{=response.flash or ''}}",page)
print page
else:
raise Exception, "Unable to convert"
if __name__=='__main__':
if len(sys.argv)<2:
print """USAGE:
1) start a new web2py application
2) Download a sample free layout from the web into the static/ folder of
your web2py application (make sure a sample index.html is there)
3) run this script with
python layout_make.py /path/to/web2py/applications/app/static/
> /path/to/web2py/applications/app/views/layout.html
"""
elif not os.path.exists(sys.argv[1]):
print 'Folder %s does not exist' % sys.argv[1]
else:
process(sys.argv[1])
+79
View File
@@ -0,0 +1,79 @@
USAGE = """
from web2py main folder
python scripts/make_min_web2py.py /path/to/minweb2py
it will mkdir minweb2py and build a minimal web2py installation
- no admin, no examples, one line welcome
- no scripts
- drops same rarely used contrib modules
- more modules could be dropped but minimal difference
"""
# files to include from top level folder (default.py will be rebuilt)
REQUIRED = """
VERSION
web2py.py
fcgihandler.py
gaehandler.py
wsgihandler.py
anyserver.py
applications/__init__.py
applications/welcome/controllers/default.py
"""
# files and folders to exclude from gluon folder (comment with # if needed)
IGNORED = """
gluon/contrib/comet_messaging.py
gluon/contrib/feedparser.py
gluon/contrib/generics.py
gluon/contrib/gql.py
gluon/contrib/populate.py
gluon/contrib/sms_utils.py
gluon/contrib/spreadsheet.py
gluon/tests/
gluon/contrib/markdown/
gluon/contrib/pyfpdf/
gluon/contrib/pymysql/
gluon/contrib/pyrtf/
gluon/contrib/pysimplesoap/
"""
import sys, os, shutil, glob
def main():
if len(sys.argv)<2:
print USAGE
# make target folder
target = sys.argv[1]
os.mkdir(target)
# make a list of all files to include
files = [x.strip() for x in REQUIRED.split('\n') \
if x and not x[0]=='#']
ignore = [x.strip() for x in IGNORED.split('\n') \
if x and not x[0]=='#']
def accept(filename):
for p in ignore:
if filename.startswith(p):
return False
return True
pattern = 'gluon/*.py'
while True:
newfiles = [x for x in glob.glob(pattern) if accept(x)]
if not newfiles: break
files += newfiles
pattern = pattern[:-3]+'/*.py'
# copy all files, make missing folder, build default.py
files.sort()
for f in files:
dirs = f.split(os.path.sep)
for i in range(1,len(dirs)):
try: os.mkdir(target+'/'+os.path.join(*dirs[:i]))
except OSError: pass
if f=='applications/welcome/controllers/default.py':
open(target+'/'+f,'w').write('def index(): return "hello"\n')
else:
shutil.copyfile(f,target+'/'+f)
if __name__=='__main__': main()
+115
View File
@@ -0,0 +1,115 @@
user nginx nginx;
worker_processes 1;
error_log /var/log/nginx/error_log info;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
client_header_timeout 10m;
client_body_timeout 10m;
send_timeout 10m;
connection_pool_size 256;
client_header_buffer_size 1k;
large_client_header_buffers 4 2k;
request_pool_size 4k;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 75 20;
ignore_invalid_headers on;
ssl_session_cache shared:SSL:10m;
index index.html;
server {
listen 127.0.0.1;
server_name localhost;
access_log /var/log/nginx/localhost.access_log main;
error_log /var/log/nginx/localhost.error_log info;
root /var/www/localhost/htdocs;
}
# SSL example
server {
listen 127.0.0.1:443;
server_name localhost;
ssl on;
ssl_certificate /etc/ssl/nginx/nginx-server.pem;
ssl_client_certificate /etc/ssl/nginx/cacert.pem;
ssl_certificate_key /etc/ssl/nginx/nginx.key;
ssl_verify_client optional;
access_log /var/log/nginx/localhost.ssl_access_log main;
error_log /var/log/nginx/localhost.ssl_error_log info;
root /var/www/localhost/htdocs;
set $web2pyroot /home/Desktop/source/michelecomitini-facebookaccess;
location /pki/ {
root /var/www/localhost/html;
}
location ^/(.*)/static/(.*) {
alias $web2pyroot/applications/$1/static/$2;
}
location / {
include /etc/nginx/scgi_params;
scgi_pass 127.0.0.1:4000;
#Module ngx_http_ssl_module supports the following built-in variables:
#$ssl_cipher returns the cipher suite being used for the currently established SSL/TLS connection
#$ssl_client_serial returns the serial number of the client certificate for the currently established SSL/TLS connection — if applicable, i.e., if client authentication is activated in the connection
#$ssl_client_s_dn returns the subject Distinguished Name (DN) of the client certificate for the currently established SSL/TLS connection — if applicable, i.e., if client authentication is activated in the connection
#$ssl_client_i_dn returns the issuer DN of the client certificate for the currently established SSL/TLS connection — if applicable, i.e., if client authentication is activated in the connection
#$ssl_protocol returns the protocol of the currently established SSL/TLS connection — depending on the configuration and client available options it's one of SSLv2, SSLv3 or TLSv1
#$ssl_session_id the Session ID of the established secure connection — requires Nginx version greater or equal to 0.8.20
#$ssl_client_cert
#$ssl_client_raw_cert
#$ssl_client_verify takes the value "SUCCESS" when the client certificate is successfully verified
scgi_param SSL_PROTOCOL $ssl_protocol;
scgi_param HTTPS on;
scgi_param SSL_CIPHER $ssl_cipher;
scgi_param SSL_CLIENT_SERIAL $ssl_client_serial;
scgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
scgi_param SSL_CLIENT_I_DN $ssl_client_i_dn;
scgi_param SSL_SESSION_ID $ssl_session_id;
scgi_param SSL_CLIENT_CERT $ssl_client_cert;
scgi_param SSL_CLIENT_RAW_CERT $ssl_client_raw_cert;
scgi_param SSL_CLIENT_VERIFY $ssl_client_verify;
}
}
}
+222
View File
@@ -0,0 +1,222 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
sessions2trash.py
Run this script in a web2py environment shell e.g. python web2py.py -S app
If models are loaded (-M option) auth.settings.expiration is assumed
for sessions without an expiration. If models are not loaded, sessions older
than 60 minutes are removed. Use the --expiration option to override these
values.
Typical usage:
# Delete expired sessions every 5 minutes
nohup python web2py.py -S app -M -R scripts/sessions2trash.py &
# Delete sessions older than 60 minutes regardless of expiration,
# with verbose output, then exit.
python web2py.py -S app -M -R scripts/sessions2trash.py -A -o -x 3600 -f -v
# Delete all sessions regardless of expiry and exit.
python web2py.py -S app -M -R scripts/sessions2trash.py -A -o -x 0
"""
from gluon.storage import Storage
from optparse import OptionParser
import cPickle
import datetime
import os
import stat
import time
EXPIRATION_MINUTES = 60
SLEEP_MINUTES = 5
VERSION = 0.3
class SessionSet(object):
"""Class representing a set of sessions"""
def __init__(self, expiration, force, verbose):
self.expiration = expiration
self.force = force
self.verbose = verbose
def get(self):
"""Get session files/records."""
raise NotImplementedError
def trash(self):
"""Trash expired sessions."""
now = datetime.datetime.now()
for item in self.get():
status = 'OK'
last_visit = item.last_visit_default()
try:
session = item.get()
if session.auth:
if session.auth.expiration and not self.force:
self.expiration = session.auth.expiration
if session.auth.last_visit:
last_visit = session.auth.last_visit
except:
pass
age = 0
if last_visit:
age = total_seconds(now - last_visit)
if age > self.expiration or not self.expiration:
item.delete()
status = 'trashed'
if self.verbose > 1:
print 'key: %s' % str(item)
print 'expiration: %s seconds' % self.expiration
print 'last visit: %s' % str(last_visit)
print 'age: %s seconds' % age
print 'status: %s' % status
print ''
elif self.verbose > 0:
print('%s %s' % (str(item), status))
class SessionSetDb(SessionSet):
"""Class representing a set of sessions stored in database"""
def __init__(self, expiration, force, verbose):
SessionSet.__init__(self, expiration, force, verbose)
def get(self):
"""Return list of SessionDb instances for existing sessions."""
sessions = []
tablename = 'web2py_session'
if request.application:
tablename = 'web2py_session_' + request.application
if tablename in db:
for row in db(db[tablename].id > 0).select():
sessions.append(SessionDb(row))
return sessions
class SessionSetFiles(SessionSet):
"""Class representing a set of sessions stored in flat files"""
def __init__(self, expiration, force, verbose):
SessionSet.__init__(self, expiration, force, verbose)
def get(self):
"""Return list of SessionFile instances for existing sessions."""
path = os.path.join(request.folder, 'sessions')
return [SessionFile(os.path.join(path, x)) for x in os.listdir(path)]
class SessionDb(object):
"""Class representing a single session stored in database"""
def __init__(self, row):
self.row = row
def delete(self):
self.row.delete_record()
db.commit()
def get(self):
session = Storage()
session.update(cPickle.loads(self.row.session_data))
return session
def last_visit_default(self):
return self.row.modified_datetime
def __str__(self):
return self.row.unique_key
class SessionFile(object):
"""Class representing a single session stored as a flat file"""
def __init__(self, filename):
self.filename = filename
def delete(self):
os.unlink(self.filename)
def get(self):
session = Storage()
with open(self.filename, 'rb+') as f:
session.update(cPickle.load(f))
return session
def last_visit_default(self):
return datetime.datetime.fromtimestamp(
os.stat(self.filename)[stat.ST_MTIME])
def __str__(self):
return self.filename
def total_seconds(delta):
"""
Adapted from Python 2.7's timedelta.total_seconds() method.
Args:
delta: datetime.timedelta instance.
"""
return (delta.microseconds + (delta.seconds + (delta.days * 24 * 3600)) * \
10 ** 6) / 10 ** 6
def main():
"""Main processing."""
usage = '%prog [options]' + '\nVersion: %s' % VERSION
parser = OptionParser(usage=usage)
parser.add_option('-f', '--force',
action='store_true', dest='force', default=False,
help=('Ignore session expiration. '
'Force expiry based on -x option or auth.settings.expiration.')
)
parser.add_option('-o', '--once',
action='store_true', dest='once', default=False,
help='Delete sessions, then exit.',
)
parser.add_option('-s', '--sleep',
dest='sleep', default=SLEEP_MINUTES * 60, type="int",
help='Number of seconds to sleep between executions. Default 300.',
)
parser.add_option('-v', '--verbose',
default=0, action='count',
help="print verbose output, a second -v increases verbosity")
parser.add_option('-x', '--expiration',
dest='expiration', default=None, type="int",
help='Expiration value for sessions without expiration (in seconds)',
)
(options, unused_args) = parser.parse_args()
expiration = options.expiration
if expiration is None:
try:
expiration = auth.settings.expiration
except:
expiration = EXPIRATION_MINUTES * 60
set_db = SessionSetDb(expiration, options.force, options.verbose)
set_files = SessionSetFiles(expiration, options.force, options.verbose)
while True:
set_db.trash()
set_files.trash()
if options.once:
break
else:
if options.verbose:
print 'Sleeping %s seconds' % (options.sleep)
time.sleep(options.sleep)
main()
+12
View File
@@ -0,0 +1,12 @@
# install virtualenv
easy_install virtualenv
python virtualenv.py w2env
# install missing modules
w2env/bin/easy_install -U pysqlite hashlib
# donwload web2py and unpack
wget http://web2py.com/examples/static/web2py_src.zip
unzip web2py_src.zip
cd web2py
# start web2py using command-line script
w2env/bin/python web2py.py -i 0.0.0.0 -p 8123 -a 'adminpasswd'
+101
View File
@@ -0,0 +1,101 @@
#
# Author: Christopher Steel
# Organization: Voice of Access
# Date: 2010-11-24
# License: Same as Web2py, MIT / GNU
# Email: Christopher DOT Steel AT Voice of Access DOT org
#
# This script will :
# download and install virtualenv
# start a virtual environment
# move into the virtual environment
# download and install latest stable version of web2py
# start web2py in the virtual environment
#
# To disactivate the virtual environment, shut down web2py
# and type 'disactivate' at the command line.
#
# Testing:
# OS X
# should work on POSIX systems
#
# Usage:
# create a directory to hold your virtual environments, for example
# /home/user_name/virtual_environments
# place this script in the directory and make it executable
# chmod +x web2py-install-virtualenv.sh
customize the variables below to meet your needs
# execute from terminal
# ./web2py-install-virtualenv.sh
# relax...
################ VARIABLES
# Change to reflect version changes etc.
#
# name for your virtual environment
ENV=VIRTUAL_ENV
# version to install
APP_NAME=virtualenv
VER=1.5.1
DIR=${APP_NAME}-${VER}
EXT=tar.gz
ARCHIVE=${APP_NAME}-${VER}.${EXT}
# md5 sum, see end of url from pypi
MD5_SUM=3daa1f449d5d2ee03099484cecb1c2b7
################
#
echo 'downloading' ${ARCHIVE}
echo '================================'
echo `wget http://pypi.python.org/packages/source/v/virtualenv/${ARCHIVE}`
md5 ${ARCHIVE}
echo 'MD5 ('${ARCHIVE}') =' ${MD5_SUM}
echo 'unarchive' ${ARCHIVE}
echo '================================='
tar xvfz ${ARCHIVE}
echo ' comparing md5 sums'
echo '================================='
md5 ${ARCHIVE}
echo 'MD5 ('${ARCHIVE}') =' ${MD5_SUM}
#echo 'installing compatibility modules'
#echo '================================'
#virtualenv/bin/easy_install -U pysqlite hashlib
#echo 'Installing distribute'
#echo '====================='
#echo 'Creating Environment'
#echo '====================='
#echo `python ./${DIRAPP_NAME}-${VER}/virtualenv.py --distribute ${ENV}`
echo 'Start virtual environment'
echo '========================='
virtualenv --no-site-packages ${ENV}
RUN_THIS='source ${ENV}/bin/activate'
`echo source ${ENV}/bin/activate`
echo 'Moving into virtual environment directory'
echo '========================================='
cd ${ENV}
echo 'downloading web2py'
echo '=================='
wget http://web2py.com/examples/static/web2py_src.zip
unzip web2py_src.zip
cd web2py
echo 'to deactivate your virtual environment'
echo 'shutdown web2py and then type "deactivate"'
echo '=========================================='
read -p "Press any key to start web2py…"
echo 'starting web2py'
echo '==============='
../bin/python2.5 web2py.py
+409
View File
@@ -0,0 +1,409 @@
echo "This script will:
1) Install modules needed to run web2py on Fedora and CentOS/RHEL
2) Install Python 2.6 to /opt and recompile wsgi if not provided
2) Install web2py in /opt/web-apps/
3) Configure SELinux and iptables
5) Create a self signed ssl certificate
6) Setup web2py with mod_wsgi
7) Create virtualhost entries so that web2py responds for '/'
8) Restart Apache.
You should probably read this script before running it.
Although SELinux permissions changes have been made,
further SELinux changes will be required for your personal
apps. (There may also be additional changes required for the
bundled apps.) As a last resort, SELinux can be disabled.
A simple iptables configuration has been applied. You may
want to review it to verify that it meets your needs.
Finally, if you require a proxy to access the Internet, please
set up your machine to do so before running this script.
(author: berubejd)
Press ENTER to continue...[ctrl+C to abort]"
read CONFIRM
#!/bin/bash
###
### Phase 0 - This may get messy. Lets work from a temporary directory
###
current_dir=`pwd`
if [ -d /tmp/setup-web2py/ ]; then
mv /tmp/setup-web2py/ /tmp/setup-web2py.old/
fi
mkdir -p /tmp/setup-web2py
cd /tmp/setup-web2py
###
### Phase 1 - Requirements installation
###
echo
echo " - Installing packages"
echo
# Verify packages are up to date
yum update
# Install required packages
yum install httpd mod_ssl mod_wsgi wget python
# Verify we have at least Python 2.5
typeset -i version_major
typeset -i version_minor
version=`rpm --qf %{Version} -q python`
version_major=`echo ${version} | awk '{split($0, parts, "."); print parts[1]}'`
version_minor=`echo ${version} | awk '{split($0, parts, "."); print parts[2]}'`
if [ ! ${version_major} -ge 2 -o ! ${version_minor} -ge 5 ]; then
# Setup 2.6 in /opt - based upon
# http://markkoberlein.com/getting-python-26-with-django-11-together-on
# Check for earlier Python 2.6 install
if [ -e /opt/python2.6 ]; then
# Is Python already installed?
RETV=`/opt/python2.6/bin/python -V > /dev/null 2>&1; echo $?`
if [ ${RETV} -eq 0 ]; then
python_installed='True'
else
mv /opt/python2.6 /opt/python2.6-old
fi
fi
# Install Python 2.6 if it doesn't exist already
if [ ! "${python_installed}" == "True" ]; then
# Install requirements for the Python build
yum install sqlite-devel zlib-devel
mkdir -p /opt/python2.6
# Download and install
wget http://www.python.org/ftp/python/2.6.4/Python-2.6.4.tgz
tar -xzf Python-2.6.4.tgz
cd Python-2.6.4
./configure --prefix=/opt/python2.6 --with-threads --enable-shared --with-zlib=/usr/include
make && make install
cd /tmp/setup-web2py
fi
# Create links for Python 2.6
# even if it was previously installed just to be sure
ln -s /opt/python2.6/lib/libpython2.6.so /usr/lib
ln -s /opt/python2.6/lib/libpython2.6.so.1.0 /usr/lib
ln -s /opt/python2.6/bin/python /usr/local/bin/python
ln -s /opt/python2.6/bin/python /usr/bin/python2.6
ln -s /opt/python2.6/lib/python2.6.so /opt/python2.6/lib/python2.6/config/
# Update linker for new libraries
/sbin/ldconfig
# Rebuild wsgi to take advantage of Python 2.6
yum install httpd-devel
cd /tmp/setup-web2py
wget http://modwsgi.googlecode.com/files/mod_wsgi-3.3.tar.gz
tar -xzf mod_wsgi-3.3.tar.gz
cd mod_wsgi-3.3
./configure --with-python=/usr/local/bin/python
make && make install
echo "LoadModule wsgi_module modules/mod_wsgi.so" > /etc/httpd/conf.d/wsgi.conf
cd /tmp/setup-web2py
fi
### MySQL install untested!
# Install mysql packages (optional)
#yum install mysql mysql-server
# Enable mysql to start at boot (optional)
#chkconfig --levels 235 mysqld on
#service mysqld start
# Configure mysql security settings (not really optional if mysql installed)
#/usr/bin/mysql_secure_installation
###
### Phase 2 - Install web2py
###
echo
echo " - Downloading, installing, and starting web2py"
echo
# Create web-apps directory, if required
if [ ! -d "/opt/web-apps" ]; then
mkdir -p /opt/web-apps
chmod 755 /opt
chmod 755 /opt/web-apps
fi
cd /opt/web-apps
# Download web2py
if [ -e web2py_src.zip* ]; then
rm web2py_src.zip*
fi
wget http://web2py.com/examples/static/web2py_src.zip
unzip web2py_src.zip
chown -R apache:apache web2py
###
### Phase 3 - Setup SELinux context
###
# Set context for Python libraries if Python 2.6 installed
if [ -d /opt/python2.6 ]; then
cd /opt/python2.6
chcon -R -t lib_t lib/
fi
# Allow http_tmp_exec required for wsgi
RETV=`setsebool -P httpd_tmp_exec on > /dev/null 2>&1; echo $?`
if [ ! ${RETV} -eq 0 ]; then
# CentOS doesn't support httpd_tmp_exec
cd /tmp/setup-web2py
# Create the SELinux policy
cat > httpd.te <<EOF
EOF
module httpd 1.0;
require {
type httpd_t;
class process execmem;
}
#============= httpd_t ==============
allow httpd_t self:process execmem;
EOF
checkmodule -M -m -o httpd.mod httpd.te
semodule_package -o httpd.pp -m httpd.mod
semodule -i httpd.pp
fi
# Setup the overall web2py SELinux context
cd /opt
chcon -R -t httpd_user_content_t web-apps/
cd /opt/web-apps/web2py/applications
# Setup the proper context on the writable application directories
for app in `ls`
do
for dir in databases cache errors sessions private uploads
do
mkdir ${app}/${dir}
chown apache:apache ${app}/${dir}
chcon -R -t tmp_t ${app}/${dir}
done
done
###
### Phase 4 - Configure iptables
###
cd /tmp/setup-web2py
# Create rules file - based upon
# http://articles.slicehost.com/assets/2007/9/4/iptables.txt
cat > iptables.rules <<EOF
EOF
*filter
# Allows all loopback (lo0) traffic
# drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allows all outbound traffic
-A OUTPUT -j ACCEPT
# Allows SSH, HTTP, and HTTPS
# Consider changing the SSH port and/or using rate limiting
# see http://blog.andrew.net.au/2005/02/16#ipt_recent_and_ssh_attacks
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
# Reject all other inbound - default deny unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT
EOF
/sbin/iptables -F
cat iptables.rules | /sbin/iptables-restore
/sbin/service iptables save
###
### Phase 5 - Setup SSL
###
echo
echo " - Creating a self signed certificate"
echo
# Verify ssl directory exists
if [ ! -d "/etc/httpd/ssl" ]; then
mkdir -p /etc/httpd/ssl
fi
# Generate and protect certificate
openssl genrsa 1024 > /etc/httpd/ssl/self_signed.key
openssl req -new -x509 -nodes -sha1 -days 365 -key /etc/httpd/ssl/self_signed.key > /etc/httpd/ssl/self_signed.cert
openssl x509 -noout -fingerprint -text < /etc/httpd/ssl/self_signed.cert > /etc/httpd/ssl/self_signed.info
chmod 400 /etc/httpd/ssl/self_signed.*
###
### Phase 6 - Configure Apache
###
echo
echo " - Configure Apache to use mod_wsgi"
echo
# Create config
if [ -e /etc/httpd/conf.d/welcome.conf ]; then
mv /etc/httpd/conf.d/welcome.conf /etc/httpd/conf.d/welcome.conf.disabled
fi
cat > /etc/httpd/conf.d/default.conf <<EOF
EOF
NameVirtualHost *:80
NameVirtualHost *:443
<VirtualHost *:80>
WSGIDaemonProcess web2py user=apache group=apache
WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
<Directory /opt/web-apps/web2py>
AllowOverride None
Order Allow,Deny
Deny from all
<Files wsgihandler.py>
Allow from all
</Files>
</Directory>
AliasMatch ^/([^/]+)/static/(.*) /opt/web-apps/web2py/applications/\$1/static/\$2
<Directory /opt/web-apps/web2py/applications/*/static>
Options -Indexes
Order Allow,Deny
Allow from all
</Directory>
<Location /admin>
Deny from all
</Location>
<LocationMatch ^/([^/]+)/appadmin>
Deny from all
</LocationMatch>
CustomLog /var/log/httpd/access_log common
ErrorLog /var/log/httpd/error_log
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/self_signed.cert
SSLCertificateKeyFile /etc/httpd/ssl/self_signed.key
WSGIProcessGroup web2py
WSGIScriptAlias / /opt/web-apps/web2py/wsgihandler.py
<Directory /opt/web-apps/web2py>
AllowOverride None
Order Allow,Deny
Deny from all
<Files wsgihandler.py>
Allow from all
</Files>
</Directory>
AliasMatch ^/([^/]+)/static/(.*) /opt/web-apps/web2py/applications/\$1/static/\$2
<Directory /opt/web-apps/web2py/applications/*/static>
Options -Indexes
ExpiresActive On
ExpiresDefault "access plus 1 hour"
Order Allow,Deny
Allow from all
</Directory>
CustomLog /var/log/httpd/access_log common
ErrorLog /var/log/httpd/error_log
</VirtualHost>
EOF
# Fix wsgi socket locations
echo "WSGISocketPrefix run/wsgi" >> /etc/httpd/conf.d/wsgi.conf
# Restart Apache to pick up changes
service httpd restart
###
### Phase 7 - Setup web2py admin password
###
echo
echo " - Setup web2py admin password"
echo
cd /opt/web-apps/web2py
sudo -u apache python -c "from gluon.main import save_password; save_password(raw_input('admin password: '),443)"
###
### Phase 8 - Verify that required services start at boot
###
/sbin/chkconfig iptables on
/sbin/chkconfig httpd on
###
### Phase 999 - Done!
###
# Change back to original directory
cd ${current_directory}
echo " - Complete!"
echo
EOF
EOF
EOF
@@ -0,0 +1,81 @@
#!/bin/bash
echo 'setup-web2py-nginx-uwsgi-ubuntu.sh'
echo 'Requires Ubuntu 10.04 (LTS) and installs Nginx + uWSGI + Web2py'
# Get Web2py Admin Password
echo -e "Web2py Admin Password: \c "
read PW
# Upgrade and install needed software
apt-get update
apt-get -y upgrade
apt-get install python-software-properties
add-apt-repository ppa:nginx/stable
add-apt-repository ppa:uwsgi/release
apt-get update
apt-get -y install nginx-full
apt-get -y install uwsgi-python
# Create configuration file /etc/nginx/sites-available/web2py
echo 'server {
listen 80;
server_name $hostname;
location ~* /(\w+)/static/ {
root /home/www-data/web2py/applications/;
}
location / {
uwsgi_pass 127.0.0.1:9001;
include uwsgi_params;
uwsgi_param UWSGI_SCHEME $scheme;
uwsgi_param SERVER_SOFTWARE nginx/$nginx_version;
}
}
server {
listen 443;
server_name $hostname;
ssl on;
ssl_certificate /etc/nginx/ssl/web2py.crt;
ssl_certificate_key /etc/nginx/ssl/web2py.key;
location / {
uwsgi_pass 127.0.0.1:9001;
include uwsgi_params;
uwsgi_param UWSGI_SCHEME $scheme;
uwsgi_param SERVER_SOFTWARE nginx/$nginx_version;
}
}' >/etc/nginx/sites-available/web2py
ln -s /etc/nginx/sites-available/web2py /etc/nginx/sites-enabled/web2py
rm /etc/nginx/sites-enabled/default
rm /etc/nginx/sites-available/default
mkdir /etc/nginx/ssl
cd /etc/nginx/ssl
openssl genrsa -out web2py.key 1024
openssl req -batch -new -key web2py.key -out web2py.csr
openssl x509 -req -days 1780 -in web2py.csr -signkey web2py.key -out web2py.crt
# Create configuration file /etc/uwsgi-python/apps-available/web2py.xml
echo '<uwsgi>
<socket>127.0.0.1:9001</socket>
<pythonpath>/home/www-data/web2py/</pythonpath>
<app mountpoint="/">
<script>wsgihandler</script>
</app>
</uwsgi>' >/etc/uwsgi-python/apps-available/web2py.xml
ln -s /etc/uwsgi-python/apps-available/web2py.xml /etc/uwsgi-python/apps-enabled/web2py.xml
# Install Web2py
apt-get -y install unzip
cd /home
mkdir www-data
cd www-data
wget http://web2py.com/examples/static/web2py_src.zip
unzip web2py_src.zip
rm web2py_src.zip
chown -R www-data:www-data web2py
cd /home/www-data/web2py
sudo -u www-data python -c "from gluon.main import save_password; save_password('$PW',443)"
/etc/init.d/uwsgi-python restart
/etc/init.d/nginx restart
+169
View File
@@ -0,0 +1,169 @@
echo "This script will:
1) install all modules need to run web2py on Ubuntu/Debian
2) install web2py in /home/www-data/
3) create a self signed sll certificate
4) setup web2py with mod_wsgi
5) overwrite /etc/apache2/sites-available/default
6) restart apache.
You may want to read this cript before running it.
Press a key to continue...[ctrl+C to abort]"
read CONFIRM
#!/bin/bash
# optional
# dpkg-reconfigure console-setup
# dpkg-reconfigure timezoneconf
# nano /etc/hostname
# nano /etc/network/interfaces
# nano /etc/resolv.conf
# reboot now
# ifconfig eth0
echo "installing useful packages"
echo "=========================="
apt-get update
apt-get -y install ssh
apt-get -y install zip unzip
apt-get -y install tar
apt-get -y install openssh-server
apt-get -y install build-essential
apt-get -y install python2.5
apt-get -y install ipython
apt-get -y install python-dev
apt-get -y install postgresql
apt-get -y install apache2
apt-get -y install libapache2-mod-wsgi
apt-get -y install python2.5-psycopg2
apt-get -y install postfix
apt-get -y install wget
apt-get -y install python-matplotlib
apt-get -y install python-reportlab
apt-get -y install mercurial
/etc/init.d/postgresql restart
# optional, uncomment for emacs
# apt-get -y install emacs
# optional, uncomment for backups using samba
# apt-get -y install samba
# apt-get -y install smbfs
echo "downloading, installing and starting web2py"
echo "==========================================="
cd /home
mkdir www-data
cd www-data
rm web2py_src.zip*
wget http://web2py.com/examples/static/web2py_src.zip
unzip web2py_src.zip
chown -R www-data:www-data web2py
echo "setting up apache modules"
echo "========================="
a2enmod ssl
a2enmod proxy
a2enmod proxy_http
a2enmod headers
a2enmod expires
mkdir /etc/apache2/ssl
echo "creating a self signed certificate"
echo "=================================="
openssl genrsa 1024 > /etc/apache2/ssl/self_signed.key
chmod 400 /etc/apache2/ssl/self_signed.key
openssl req -new -x509 -nodes -sha1 -days 365 -key /etc/apache2/ssl/self_signed.key > /etc/apache2/ssl/self_signed.cert
openssl x509 -noout -fingerprint -text < /etc/apache2/ssl/self_signed.cert > /etc/apache2/ssl/self_signed.info
echo "rewriting your apache config file to use mod_wsgi"
echo "================================================="
echo '
NameVirtualHost *:80
NameVirtualHost *:443
<VirtualHost *:80>
WSGIDaemonProcess web2py user=www-data group=www-data
WSGIProcessGroup web2py
WSGIScriptAlias / /home/www-data/web2py/wsgihandler.py
<Directory /home/www-data/web2py>
AllowOverride None
Order Allow,Deny
Deny from all
<Files wsgihandler.py>
Allow from all
</Files>
</Directory>
AliasMatch ^/([^/]+)/static/(.*) \
/home/www-data/web2py/applications/$1/static/$2
<Directory /home/www-data/web2py/applications/*/static/>
Options -Indexes
Order Allow,Deny
Allow from all
</Directory>
<Location /admin>
Deny from all
</Location>
<LocationMatch ^/([^/]+)/appadmin>
Deny from all
</LocationMatch>
CustomLog /var/log/apache2/access.log common
ErrorLog /var/log/apache2/error.log
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/self_signed.cert
SSLCertificateKeyFile /etc/apache2/ssl/self_signed.key
WSGIProcessGroup web2py
WSGIScriptAlias / /home/www-data/web2py/wsgihandler.py
<Directory /home/www-data/web2py>
AllowOverride None
Order Allow,Deny
Deny from all
<Files wsgihandler.py>
Allow from all
</Files>
</Directory>
AliasMatch ^/([^/]+)/static/(.*) \
/home/www-data/web2py/applications/$1/static/$2
<Directory /home/www-data/web2py/applications/*/static/>
Options -Indexes
ExpiresActive On
ExpiresDefault "access plus 1 hour"
Order Allow,Deny
Allow from all
</Directory>
CustomLog /var/log/apache2/access.log common
ErrorLog /var/log/apache2/error.log
</VirtualHost>
' > /etc/apache2/sites-available/default
# echo "setting up PAM"
# echo "================"
# sudo apt-get install pwauth
# sudo ln -s /etc/apache2/mods-available/authnz_external.load /etc/apache2/mods-enabled
# ln -s /etc/pam.d/apache2 /etc/pam.d/httpd
# usermod -a -G shadow www-data
echo "restarting apage"
echo "================"
/etc/init.d/apache2 restart
cd /home/www-data/web2py
sudo -u www-data python -c "from gluon.widget import console; console();"
sudo -u www-data python -c "from gluon.main import save_password; save_password(raw_input('admin password: '),443)"
echo "done!"
+64
View File
@@ -0,0 +1,64 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Usage:
Install cx_Freeze: http://cx-freeze.sourceforge.net/
Copy script to the web2py directory
c:\Python27\python standalone_exe_cxfreeze.py build_exe
"""
from cx_Freeze import setup, Executable
from gluon.import_all import base_modules, contributed_modules
from gluon.fileutils import readlines_file
from glob import glob
import fnmatch
import os
import shutil
import sys
import re
#read web2py version from VERSION file
web2py_version_line = readlines_file('VERSION')[0]
#use regular expression to get just the version number
v_re = re.compile('[0-9]+\.[0-9]+\.[0-9]+')
web2py_version = v_re.search(web2py_version_line).group(0)
base = None
if sys.platform == 'win32':
base = "Win32GUI"
base_modules.remove('macpath')
buildOptions = dict(
compressed = True,
excludes = ["macpath","PyQt4"],
includes = base_modules,
include_files=[
'applications',
'ABOUT',
'LICENSE',
'VERSION',
'logging.example.conf',
'options_std.py',
'app.example.yaml',
'queue.example.yaml',
],
# append any extra module by extending the list below -
# "contributed_modules+["lxml"]"
packages = contributed_modules,
)
setup(
name = "Web2py",
version=web2py_version,
author="Massimo DiPierro",
description="web2py web framework",
license = "LGPL v3",
options = dict(build_exe = buildOptions),
executables = [Executable("web2py.py",
base=base,
compress = True,
icon = "web2py.ico",
targetName="web2py.exe",
copyDependentFiles = True)],
)
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# TODO: Comment this code
import sys
import shutil
import os
from gluon.languages import findT
sys.path.insert(0, '.')
file = sys.argv[1]
apps = sys.argv[2:]
d = {}
for app in apps:
path = 'applications/%s/' % app
findT(path, file)
langfile = open(os.path.join(path, 'languages', '%s.py' % file))
try:
data = eval(langfile.read())
finally:
langfile.close()
d.update(data)
path = 'applications/%s/' % apps[-1]
file1 = os.path.join(path, 'languages', '%s.py' % file)
f = open(file1, 'w')
try:
f.write('{\n')
keys = d.keys()
keys.sort()
for key in keys:
f.write('%s:%s,\n' % (repr(key), repr(str(d[key]))))
f.write('}\n')
finally:
f.close()
oapps = reversed(apps[:-1])
for app in oapps:
path2 = 'applications/%s/' % app
file2 = os.path.join(path2, 'languages', '%s.py' % file)
shutil.copyfile(file1, file2)
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import time
import stat
import datetime
from gluon.utils import md5_hash
from gluon.restricted import RestrictedError, TicketStorage
from gluon import DAL
SLEEP_MINUTES = 5
errors_path = os.path.join(request.folder, 'errors')
try:
db_string = open(os.path.join(request.folder, 'private', 'ticket_storage.txt')).read().replace('\r','').replace('\n','').strip()
except:
db_string = 'sqlite://storage.db'
db_path = os.path.join(request.folder, 'databases')
tk_db = DAL(db_string, folder=db_path, auto_import=True)
ts = TicketStorage(db=tk_db)
tk_table = ts._get_table(db=tk_db, tablename=ts.tablename, app=request.application)
hashes = {}
while 1:
if request.tickets_db:
print "You're storing tickets yet in database"
sys.exit(1)
for file in os.listdir(errors_path):
filename = os.path.join(errors_path, file)
modified_time = os.stat(filename)[stat.ST_MTIME]
modified_time = datetime.datetime.fromtimestamp(modified_time)
ticket_id = file
ticket_data = open(filename).read()
tk_table.insert(ticket_id=ticket_id,
ticket_data=ticket_data,
created_datetime=modified_time
)
tk_db.commit()
os.unlink(filename)
time.sleep(SLEEP_MINUTES * 60)
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import time
import stat
import datetime
from gluon.utils import md5_hash
from gluon.restricted import RestrictedError
from gluon.tools import Mail
path = os.path.join(request.folder, 'errors')
hashes = {}
mail = Mail()
### CONFIGURE HERE
SLEEP_MINUTES = 5
ALLOW_DUPLICATES = True
mail.settings.server = 'localhost:25'
mail.settings.sender = 'you@localhost'
administrator_email = 'you@localhost'
### END CONFIGURATION
while 1:
for file in os.listdir(path):
filename = os.path.join(path, file)
if not ALLOW_DUPLICATES:
fileobj = open(filename, 'r')
try:
file_data = fileobj.read()
finally:
fileobj.close()
key = md5_hash(file_data)
if key in hashes:
continue
hashes[key] = 1
error = RestrictedError()
error.load(request, request.application, filename)
mail.send(to=administrator_email, subject='new web2py ticket', message=error.traceback)
os.unlink(filename)
time.sleep(SLEEP_MINUTES * 60)
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
#
# update-web2py.sh
# 2009-12-16
#
# install in web2py/.. or web2py/ or web2py/scripts as update-web2py.sh
# make executable: chmod +x web2py.sh
#
# save a snapshot of current web2py/ as web2py/../web2py-version.zip
# download the current stable version of web2py
# unzip downloaded version over web2py/
#
TARGET=web2py
if [ ! -d $TARGET ]; then
# in case we're in web2py/
if [ -f ../$TARGET/VERSION ]; then
cd ..
# in case we're in web2py/scripts
elif [ -f ../../$TARGET/VERSION ]; then
cd ../..
fi
fi
read a VERSION c < $TARGET/VERSION
SAVE=$TARGET-$VERSION
URL=http://www.web2py.com/examples/static/web2py_src.zip
ZIP=`basename $URL`
SAVED=""
# Save a zip archive of the current version,
# but don't overwrite a previous save of the same version.
#
if [ -f $SAVE.zip ]; then
echo "Remove or rename $SAVE.zip first" >&2
exit 1
fi
if [ -d $TARGET ]; then
echo -n ">>Save old version: " >&2
cat $TARGET/VERSION >&2
zip -q -r $SAVE.zip $TARGET
SAVED=$SAVE.zip
fi
#
# Download the new version.
#
echo ">>Download latest web2py release:" >&2
curl -O $URL
#
# Unzip into web2py/
#
unzip -q -o $ZIP
rm $ZIP
echo -n ">>New version: " >&2
cat $TARGET/VERSION >&2
if [ "$SAVED" != "" ]; then
echo ">>Old version saved as $SAVED"
fi
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
crontab -e
* 3 * * * root path/to/this/file
"""
USER = 'www-data'
TMPFILENAME = 'web2py_src_update.zip'
import sys
import os
import urllib
import zipfile
if len(sys.argv)>1 and sys.argv[1] == 'nightly':
version = 'http://web2py.com/examples/static/nightly/web2py_src.zip'
else:
version = 'http://web2py.com/examples/static/web2py_src.zip'
realpath = os.path.realpath(__file__)
path = os.path.dirname(os.path.dirname(os.path.dirname(realpath)))
os.chdir(path)
try:
old_version = open('web2py/VERSION','r').read().strip()
except IOError:
old_version = ''
open(TMPFILENAME,'wb').write(urllib.urlopen(version).read())
new_version = zipfile.ZipFile(TMPFILENAME).read('web2py/VERSION').strip()
if new_version>old_version:
os.system('sudo -u %s unzip -o %s' % (USER,TMPFILENAME))
os.system('apachectl restart | apache2ctl restart')
+11
View File
@@ -0,0 +1,11 @@
chown -R nobody:nobody *.py
chown -R nobody:nobody gluon
chown -R nobody:nobody scripts
chown -R nobody:nobody applications/*/modules/
chown -R nobody:nobody applications/*/models/
chown -R nobody:nobody applications/*/controllers/
chown -R nobody:nobody applications/*/views/
chown -R nobody:nobody applications/*/static/
chown -R nobody:nobody applications/*/cron/
echo "unlock with chown -R www-data:www-data ./"
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
# the script should be run
# from WEB2PY root directory
prog=`basename $0`
cd `pwd`
chmod +x $prog
function web2py_start {
nohup ./$prog -a "<recycle>" 2>/dev/null &
pid=`pgrep $prog | tail -1`
if [ $pid -ne $$ ]
then
echo "WEB2PY has been started."
fi
}
function web2py_stop {
kill -15 `pgrep $prog | grep -v $$` 2>/dev/null
pid=`pgrep $prog | head -1`
if [ $pid -ne $$ ]
then
echo "WEB2PY has been stopped."
fi
}
case "$1" in
start)
web2py_start
;;
stop)
web2py_stop
;;
restart)
web2py_stop
web2py_start
;;
*)
echo "Usage: $prog [start|stop|restart]"
;;
esac
exit 0
+82
View File
@@ -0,0 +1,82 @@
#!/bin/bash
#
# /etc/rc.d/init.d/web2pyd
#
# Starts the Web2py Daemon on Fedora (Red Hat Linux)
#
# To execute automatically at startup
#
# sudo chkconfig --add web2pyd
#
# chkconfig: 2345 90 10
# description: Web2py Daemon
# processname: web2pyd
# pidfile: /var/lock/subsys/web2pyd
source /etc/rc.d/init.d/functions
RETVAL=0
NAME=web2pyd
DESC="Web2py Daemon"
DAEMON_DIR="/usr/lib/web2py"
ADMINPASS="admin"
#ADMINPASS="\<recycle\>"
PIDFILE=/var/run/$NAME.pid
PORT=8001
PYTHON=python
cd $DAEMON_DIR
start() {
echo -n $"Starting $DESC ($NAME): "
daemon --check $NAME $PYTHON $DAEMON_DIR/web2py.py -Q --nogui -a $ADMINPASS -d $PIDFILE -p $PORT &
RETVAL=$?
if [ $RETVAL -eq 0 ]; then
touch /var/lock/subsys/$NAME
fi
echo
return $RETVAL
}
stop() {
echo -n $"Shutting down $DESC ($NAME): "
killproc -p "$PIDFILE" -d 3 "$NAME"
echo
if [ $RETVAL -eq 0 ]; then
rm -f /var/lock/subsys/$NAME
rm -f $PIDFILE
fi
return $RETVAL
}
restart() {
stop
start
}
status() {
if [ -r "$PIDFILE" ]; then
pid=`cat $PIDFILE`
fi
if [ $pid ]; then
echo "$NAME (pid $pid) is running..."
else
echo "$NAME is stopped"
fi
}
case "$1" in
start) start;;
stop) stop;;
status) status;;
restart) restart;;
condrestart) [ -e /var/lock/subsys/$NAME ] && restart
RETVAL=$?
;;
*) echo $"Usage: $0 {start|stop|restart|condrestart|status}"
RETVAL=1
;;
esac
exit $RETVAL
+223
View File
@@ -0,0 +1,223 @@
#! /bin/sh
### BEGIN INIT INFO
# startup script for Ubuntu and Debian Linux servers
#
# To use this file
# cp ubuntu.sh /etc/init.d/web2py
#
# To automatitcally start at reboot
# sudo update-rc.d web2py defaults
#
# Provides: web2py
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: web2py initscript
# Description: This file starts up the web2py server.
### END INIT INFO
# Author: Mark Moore <mark.moore@fonjax.com>
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="Web Framework"
NAME=web2py
PIDDIR=/var/run/$NAME
PIDFILE=$PIDDIR/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
DAEMON=/usr/bin/python
DAEMON_DIR=/usr/lib/$NAME
DAEMON_ARGS="web2py.py --password=<recycle> --pid_filename=$PIDFILE"
DAEMON_USER=web2py
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
# The PIDDIR should normally be created during installation. This
# fixes things just in case.
[ -d $PIDDIR ] || mkdir -p $PIDDIR
[ -n "$DAEMON_USER" ] && chown --recursive $DAEMON_USER $PIDDIR
# Check to see if the daemon is already running.
start-stop-daemon --stop --test --quiet --pidfile $PIDFILE \
&& return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE \
${DAEMON_USER:+--chuid $DAEMON_USER} --chdir $DAEMON_DIR \
--background --exec $DAEMON -- $DAEMON_ARGS \
|| return 2
return 0;
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL=$?
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that restarts the daemon/service
#
do_restart()
{
# Return
# 0 if daemon was (re-)started
# 1 if daemon was not strated or re-started
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) RETVAL=0 ;;
1) RETVAL=1 ;; # Old process is still running
*) RETVAL=1 ;; # Failed to start
esac
;;
*) RETVAL=1 ;; # Failed to stop
esac
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE
return 0
}
#
# Function that queries the status of the daemon/service
#
do_status()
{
# Return
# 0 if daemon is responding and OK
# 1 if daemon is not responding, but PIDFILE exists
# 2 if daemon is not responding, but LOCKFILE exists
# 3 if deamon is not running
# 4 if daemon status is unknown
# Check to see if the daemon is already running.
start-stop-daemon --stop --test --quiet --pidfile $PIDFILE \
&& return 0
[ -f $PIDFILE ] && return 1
return 3
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
RETVAL=$?
[ "$VERBOSE" != no ] &&
case "$RETVAL" in
0|1) log_end_msg 0 ;;
*) log_end_msg 1 ;;
esac
exit "$RETVAL"
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
RETVAL=$?
[ "$VERBOSE" != no ] &&
case "$RETVAL" in
0|1) log_end_msg 0 ;;
*) log_end_msg 1 ;;
esac
exit "$RETVAL"
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#[ "$VERBOSE" != no ] && log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#RETVAL=$?
#[ "$VERBOSE" != no ] && log_end_msg $?
#exit "$RETVAL"
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
[ "$VERBOSE" != no ] && log_daemon_msg "Restarting $DESC" "$NAME"
do_restart
RETVAL=$?
[ "$VERBOSE" != no ] && log_end_msg "$RETVAL"
exit "$RETVAL"
;;
status)
do_status
RETVAL=$?
[ "$VERBOSE" != no ] &&
case "$RETVAL" in
0) log_success_msg "$NAME is running" ;;
*) log_failure_msg "$NAME is not running" ;;
esac
exit "$RETVAL"
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2
exit 3
;;
esac
:
# This was based off /etc/init.d/skeleton from the Ubuntu 8.04 Hardy release.
# (md5sum: da0162012b6a916bdbd4e2580282af78). If we notice that changes, we
# should re-examine things.
# The configuration at the very top seems to be documented as part of the
# Linux Standard Base (LSB) Specification. See section 20.6 Facility Names
# in particular. This is also where I got the spec for the status parm.
# References:
# http://refspecs.linux-foundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic.pdf
# Debian Policy SysV init: http://www.debian.org/doc/debian-policy/ch-opersys.html#s-sysvinit
# Examine files in /usr/share/doc/sysv-rc/