From d3cbf9429118b292c917885d6ae41af19b9dfaec Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:06:27 -0500 Subject: [PATCH 1/8] custom qualifier, thanks david karapetyan --- VERSION | 2 +- gluon/dal.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e75c1d37..4d23a498 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 21:32:06) dev +Version 2.00.0 (2012-07-05 22:06:22) dev diff --git a/gluon/dal.py b/gluon/dal.py index dda43717..22c60196 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -724,6 +724,8 @@ class BaseAdapter(ConnectionPool): ftype += self.ALLOW_NULL() if field.unique: ftype += ' UNIQUE' + if field.custom_qualifier: + ftype += ' %s' % field.custom_qualifier # add to list of fields sql_fields[field.name] = dict(sortable=sortable, @@ -7962,6 +7964,7 @@ class Field(Expression): custom_delete=None, filter_in = None, filter_out = None, + custom_qualifier = None, ): self.db = None self.op = None @@ -8011,6 +8014,7 @@ class Field(Expression): self.custom_delete = custom_delete self.filter_in = filter_in self.filter_out = filter_out + self.custom_qualifier = custom_qualifier if self.label is None: self.label = fieldname.replace('_',' ').title() if requires is None: From 6303f2c455b327e3f63eff4817c1db7abc111787 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:09:13 -0500 Subject: [PATCH 2/8] no double import contenttype, thanks Salomon Derossi --- VERSION | 2 +- gluon/globals.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 4d23a498..5faa260f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:06:22) dev +Version 2.00.0 (2012-07-05 22:09:10) dev diff --git a/gluon/globals.py b/gluon/globals.py index 63e22e0d..c1bb716a 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -329,7 +329,6 @@ class Response(Storage): downloads from http://..../download/filename """ - import contenttype as c if not request.args: raise HTTP(404) name = request.args[-1] @@ -343,7 +342,7 @@ class Response(Storage): (filename, stream) = field.retrieve(name) except IOError: raise HTTP(404) - self.headers['Content-Type'] = c.contenttype(name) + self.headers['Content-Type'] = contenttype(name) if attachment: self.headers['Content-Disposition'] = \ "attachment; filename=%s" % filename From b77bd65140cb30c90e2ec9be25c6837e108fc1f8 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:21:18 -0500 Subject: [PATCH 3/8] openshift integration, thanks prelegalwonder --- VERSION | 2 +- applications/admin/controllers/openshift.py | 53 ++++++++++ applications/admin/views/default/site.html | 96 +++++++++---------- .../admin/views/openshift/deploy.html | 32 +++++++ 4 files changed, 132 insertions(+), 51 deletions(-) create mode 100644 applications/admin/controllers/openshift.py create mode 100644 applications/admin/views/openshift/deploy.html diff --git a/VERSION b/VERSION index 5faa260f..0cd08554 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:09:10) dev +Version 2.00.0 (2012-07-05 22:21:15) dev diff --git a/applications/admin/controllers/openshift.py b/applications/admin/controllers/openshift.py new file mode 100644 index 00000000..a04934d0 --- /dev/null +++ b/applications/admin/controllers/openshift.py @@ -0,0 +1,53 @@ +import os +from distutils import dir_util +from git import * + +def deploy(): + apps = sorted(file for file in os.listdir(apath(r=request)))#if regex.match(file)) + form = SQLFORM.factory( + Field('osrepo',default='/tmp',label='Path to local openshift repo root.', + requires=EXISTS(error_message=T('directory not found'))), + Field('osname',default='web2py',label='WSGI reference name'), + Field('applications','list:string', + requires=IS_IN_SET(apps,multiple=True), + label=T('web2py apps to deploy'))) + + cmd = output = errors= "" + if form.accepts(request,session): + try: + kill() + except: + pass + + ignore_apps = [item for item in apps \ + if not item in form.vars.applications] + regex = re.compile('\(applications/\(.*') + w2p_origin = os.getcwd() + osrepo = form.vars.osrepo + osname = form.vars.osname + #Git code starts here + repo = Repo(form.vars.osrepo) + index = repo.index + assert repo.bare == False + + for i in form.vars.applications: + appsrc = os.path.join(os.getcwd(),'applications',i) + appdest = os.path.join(osrepo,'wsgi',osname,'applications',i) + dir_util.copy_tree(appsrc,appdest) + #shutil.copytree(appsrc,appdest) + index.add(['wsgi/'+osname+'/applications/'+i]) + new_commit = index.commit("Deploy from Web2py IDE") #<--- COMMIT WORKED.. Next.. on to actual push. + + origin = repo.remotes.origin + origin.push + origin.push() + #Git code ends here + return dict(form=form,command=cmd) + +class EXISTS(object): + def __init__(self, error_message='file not found'): + self.error_message = error_message + def __call__(self, value): + if os.path.exists(value): + return (value,None) + return (value,self.error_message) diff --git a/applications/admin/views/default/site.html b/applications/admin/views/default/site.html index de4d418e..184b3a93 100644 --- a/applications/admin/views/default/site.html +++ b/applications/admin/views/default/site.html @@ -14,10 +14,7 @@

{{else:}}

{{=A(a,_href=URL(a,'default','index'))}}

- {{if MULTI_USER_MODE and db.app(name=a):}}{{owner = db.auth_user[db.app(name=a).owner]}} - (created by {{="%(first_name)s %(last_name)s" % owner}} - <{{=A(owner.email, _href='mailto:%s' % owner.email)}}>) - {{pass}} + {{if MULTI_USER_MODE and db.app(name=a):}}(created by {{="%(first_name)s %(last_name)s" % db.auth_user[db.app(name=a).owner]}}){{pass}}

{{if not os.path.exists('applications/%s/compiled' % a):}} {{=sp_button(URL('design',args=a), T("Edit"))}} @@ -39,12 +36,8 @@ {{pass}} {{if a!=request.application:}} {{=button(URL('uninstall',args=a), T("Uninstall"))}} - {{=button_enable(URL('enable',args=a), a)}} + {{=button_enable(URL('enable',args=a), a)}} {{pass}} - {{if a=='admin' and MULTI_USER_MODE and is_manager():}} - {{=button(URL('default','manage_students'), T('Manage Students'))}} - {{=button(URL('default','bulk_register'), T('Bulk Register'))}} - {{pass}}

{{pass}} @@ -65,19 +58,18 @@ {{if is_manager():}}
-

{{=T("Version %s.%s.%s (%s) %s") % myversion}}

+

{{="Version %s.%s.%s (%s) %s" % myversion}}

{{if session.check_version:}}

{{=T('Checking for upgrades...')}} {{session.check_version=False}} -

{{else:}}

{{=button("javascript:ajax('"+URL('check_version')+"',[],'check_version')", T('Check for upgrades'))}} -

{{pass}} +

- Running on {{=request.env.server_software}} + Running on {{=request.env.server_software}}

{{=button(URL('default','reload_routes'), T('Reload routes'))}}

@@ -105,46 +97,46 @@

{{=T("Upload and install packed application")}}

- +
- - - - - - + + + + + + - + - - - - + {{=LABEL(T("Get from URL:"), _for='upload_url')}} + + + + + - - - - - -
- {{=LABEL(T("Application name:"), _form='upload_filename')}} - - -
- {{=LABEL(T("Upload a package:"), _for='upload_file')}} - - - OR - + {{=LABEL(T("Application name:"), _form='upload_filename')}} + + +
+ {{=LABEL(T("Upload a package:"), _for='upload_file')}} + + + OR +
- {{=LABEL(T("Get from URL:"), _for='upload_url')}} - - -
+ +
- - {{=LABEL(T("Overwrite installed app"), _for='upload_overwrite')}} -
- -
+ + {{=LABEL(T("Overwrite installed app"), _for='upload_overwrite')}} + + + + + + + + +
@@ -153,6 +145,11 @@

{{=T("Deploy on Google App Engine")}}

{{=button(URL('gae','deploy'), T('Deploy'))}}


+ +
+

{{=T("Deploy to OpenShift")}}

+

{{=button(URL('openshift','deploy'),T('Deploy'))}}

+

{{if TWITTER_HASH:}}

{{=T("%s Recent Tweets"%TWITTER_HASH)}}

@@ -164,4 +161,3 @@ {{pass}}
- diff --git a/applications/admin/views/openshift/deploy.html b/applications/admin/views/openshift/deploy.html new file mode 100644 index 00000000..44cd21fe --- /dev/null +++ b/applications/admin/views/openshift/deploy.html @@ -0,0 +1,32 @@ +{{extend 'layout.html'}} + + + + + +

OpenShift Deployment Interface

+ +

{{=T("This page can commit your changes to an openshift app repo and push them to your cloud instance. This assumes that you've already created the application instance using the web2py skeleton and have that repo somewhere on a filesystem that this web2py instance can access. This functionality requires GitPython installed and on the python path of the runtime that web2py is operating in.")}}

+ +

{{=T("Note: If you receive an error with github status code of 128, ensure the system and account you are deploying from has a cooresponding ssh key configured in the openshift account.")}}

+ +{{if command:}} +

Command

+ +{{=CODE(command)}} +

OpenShift Output

+

+{{else:}}
+

Deployment form

+
+{{=form}} +
+{{pass}} From 58a4fb4b2bbe098e47e03bffb744840ab1ca0d69 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:24:34 -0500 Subject: [PATCH 4/8] fixed language in comments, thanks Clifford --- VERSION | 2 +- gluon/dal.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 0cd08554..f5633051 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:21:15) dev +Version 2.00.0 (2012-07-05 22:24:31) dev diff --git a/gluon/dal.py b/gluon/dal.py index 22c60196..4a44856c 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -173,7 +173,7 @@ CALLABLETYPES = (types.LambdaType, types.FunctionType, types.BuiltinFunctionType ################################################################################### -# following checks allows running of dal without web2py as a standalone module +# following checks allow the use of dal without web2py, as a standalone module ################################################################################### try: from utils import web2py_uuid @@ -559,7 +559,7 @@ class BaseAdapter(ConnectionPool): 'list:integer': 'TEXT', 'list:string': 'TEXT', 'list:reference': 'TEXT', - # the two below only used when DAL(...bigint_id=True) and replace 'id','reference' + # the two below are only used when DAL(...bigint_id=True) and replace 'id','reference' 'big-id': 'BIGINT PRIMARY KEY AUTOINCREMENT', 'big-reference': 'BIGINT REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s', } @@ -1919,7 +1919,7 @@ class SpatiaLiteAdapter(SQLiteAdapter): def after_connection(self): self.connection.enable_load_extension(True) - # for Windows, rename libspatialite-2.dll as libspatialite.dll + # for Windows, rename libspatialite-2.dll to libspatialite.dll # Linux uses libspatialite.so # Mac OS X uses libspatialite.dylib libspatialite = SPATIALLIBS[platform.system()] @@ -4282,7 +4282,7 @@ class GoogleDatastoreAdapter(NoSQLAdapter): """ This function was changed on 2010-05-04 because according to http://code.google.com/p/googleappengine/issues/detail?id=3119 - GAE no longer support deleting more than 1000 records. + GAE no longer supports deleting more than 1000 records. """ # self.db['_lastsql'] = self._delete(tablename,query) (items, tablename, fields) = self.select_raw(query) @@ -4666,7 +4666,7 @@ class MongoDBAdapter(NoSQLAdapter): if expression.second != 0 and not isinstance(expression.second,pymongo.objectid.ObjectId): if isinstance(expression.second,int): try: - #Cause the reference field is by default an integer and therefor this must be an integer to be able to work with other databases + #Because the reference field is by default an integer and therefore this must be an integer to be able to work with other databases expression.second = pymongo.objectid.ObjectId(("%X" % expression.second)) except: raise SyntaxError, 'The second argument must by an integer that can represent an objectid.' @@ -6220,8 +6220,8 @@ copy_reg.pickle(Row, Row_pickler, Row_unpickler) ################################################################################ -# Everything below should be independent on the specifics of the -# database and should for RDBMs and some NoSQL databases +# Everything below should be independent of the specifics of the database +# and should work for RDBMs and some NoSQL databases ################################################################################ class SQLCallableList(list): From 0668739c6e000d237bc5bdc8c6bbed7d2cbbf2dc Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:28:54 -0500 Subject: [PATCH 5/8] check if git installed for openshift --- VERSION | 2 +- applications/admin/controllers/openshift.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index f5633051..7678f6f3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:24:31) dev +Version 2.00.0 (2012-07-05 22:28:51) dev diff --git a/applications/admin/controllers/openshift.py b/applications/admin/controllers/openshift.py index a04934d0..25a0a7e0 100644 --- a/applications/admin/controllers/openshift.py +++ b/applications/admin/controllers/openshift.py @@ -1,9 +1,13 @@ import os from distutils import dir_util -from git import * +try: + from git import * +except ImportError: + session.flash = 'requires python-git, but not installed' + redirect(URL('deafult','site')) def deploy(): - apps = sorted(file for file in os.listdir(apath(r=request)))#if regex.match(file)) + apps = sorted(file for file in os.listdir(apath(r=request))) form = SQLFORM.factory( Field('osrepo',default='/tmp',label='Path to local openshift repo root.', requires=EXISTS(error_message=T('directory not found'))), @@ -19,8 +23,7 @@ def deploy(): except: pass - ignore_apps = [item for item in apps \ - if not item in form.vars.applications] + ignore_apps = [item for item in apps if not item in form.vars.applications] regex = re.compile('\(applications/\(.*') w2p_origin = os.getcwd() osrepo = form.vars.osrepo @@ -36,7 +39,7 @@ def deploy(): dir_util.copy_tree(appsrc,appdest) #shutil.copytree(appsrc,appdest) index.add(['wsgi/'+osname+'/applications/'+i]) - new_commit = index.commit("Deploy from Web2py IDE") #<--- COMMIT WORKED.. Next.. on to actual push. + new_commit = index.commit("Deploy from Web2py IDE") origin = repo.remotes.origin origin.push From f227fb673c28d2ab93f4e8afb8aab15af1016cfa Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:29:51 -0500 Subject: [PATCH 6/8] fixed typo --- VERSION | 2 +- applications/admin/controllers/openshift.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 7678f6f3..0c1f5f05 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:28:51) dev +Version 2.00.0 (2012-07-05 22:29:48) dev diff --git a/applications/admin/controllers/openshift.py b/applications/admin/controllers/openshift.py index 25a0a7e0..6f3620d2 100644 --- a/applications/admin/controllers/openshift.py +++ b/applications/admin/controllers/openshift.py @@ -4,7 +4,7 @@ try: from git import * except ImportError: session.flash = 'requires python-git, but not installed' - redirect(URL('deafult','site')) + redirect(URL('default','site')) def deploy(): apps = sorted(file for file in os.listdir(apath(r=request))) From 7891045b182e112b5f64973453c1c294dfaa3206 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 5 Jul 2012 22:33:43 -0500 Subject: [PATCH 7/8] fixed error in recent commit __idx, thanks Joel Carrier --- VERSION | 2 +- gluon/dal.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 0c1f5f05..ddee1e57 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:29:48) dev +Version 2.00.0 (2012-07-05 22:33:40) dev diff --git a/gluon/dal.py b/gluon/dal.py index 4a44856c..ff977083 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -678,7 +678,7 @@ class BaseAdapter(ConnectionPool): id_fieldname = referenced in table._db \ and table._db[referenced]._id.name or 'id' ftype = self.types[field.type[:9]] % dict( - index_name = self.varquote(tablename+'__idx'), + index_name = self.varquote(field.name+'__idx'), field_name = self.varquote(field.name), constraint_name = self.varquote(constraint_name), foreign_key = '%s (%s)' % (self.varquote(referenced), @@ -2043,7 +2043,7 @@ class MySQLAdapter(BaseAdapter): 'list:string': 'LONGTEXT', 'list:reference': 'LONGTEXT', 'big-id': 'BIGINT AUTO_INCREMENT NOT NULL', - 'big-reference': 'BIGINT, INDEX %(index_name)s (%(field_name)s), FOREIGN KEY (%(field_name)s) REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s', + 'big-reference': 'BIGINT, INDEX %(index_name`)s (%(field_name)s), FOREIGN KEY (%(field_name)s) REFERENCES %(foreign_key)s ON DELETE %(on_delete_action)s', } def varquote(self,name): From 7aa90c37230511e3cea77e4f78c2d4fed84f8afc Mon Sep 17 00:00:00 2001 From: mdipierro Date: Fri, 6 Jul 2012 08:54:45 -0500 Subject: [PATCH 8/8] db._debug=True --- VERSION | 2 +- gluon/dal.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index ddee1e57..c945597e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.00.0 (2012-07-05 22:33:40) dev +Version 2.00.0 (2012-07-06 08:54:40) dev diff --git a/gluon/dal.py b/gluon/dal.py index ff977083..926d3b4a 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -1486,6 +1486,8 @@ class BaseAdapter(ConnectionPool): def log_execute(self, *a, **b): command = a[0] + if self.db._debug: + logger.debug('SQL: %s' % command) self.db._lastsql = command t0 = time.time() ret = self.cursor.execute(*a, **b) @@ -6405,7 +6407,7 @@ class DAL(dict): migrate_enabled=True, fake_migrate_all=False, decode_credentials=False, driver_args=None, adapter_args=None, attempts=5, auto_import=False, - bigint_id=False): + bigint_id=False,debug=False): """ Creates a new Database Abstraction Layer instance. @@ -6448,6 +6450,7 @@ class DAL(dict): self._common_fields = [] self._referee_name = '%(table)s' self._bigint_id = bigint_id + self._debug = debug if not str(attempts).isdigit() or attempts < 0: attempts = 5 if uri: