forked from sinacloud/sae-python-dev-guide
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloudsql.py
More file actions
executable file
·182 lines (143 loc) · 6.32 KB
/
cloudsql.py
File metadata and controls
executable file
·182 lines (143 loc) · 6.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python
# Copyright (C) 2012-2013 SINA, All rights reserved.
"""Command line client for SAE MySQL Service. """
import sys
import os
import logging
import optparse
import sae._restful_mysql
import sae._restful_mysql._mysql_exceptions
sys.modules['_mysql_exceptions'] = sae._restful_mysql._mysql_exceptions
from grizzled import db
from grizzled.db import mysql
import prettytable
import sqlcmd
from sqlcmd import config
logging.basicConfig(level=logging.WARNING)
sqlcmd.log = logging.getLogger('cloudsql')
sqlcmd.DEFAULT_CONFIG_DIR = os.path.expanduser('~/.saecloud')
sqlcmd.RC_FILE = os.path.join(sqlcmd.DEFAULT_CONFIG_DIR, 'cloudsql.config')
sqlcmd.HISTORY_FILE_FORMAT = os.path.join(sqlcmd.DEFAULT_CONFIG_DIR, '%s.hist')
sqlcmd.INTRO = 'SAE MySQL Client\n\nType "help" or "?" for help.\n'
DEFAULT_ENCODING = 'utf-8'
USAGE = '%prog [options] database_name'
DEFAULT_SAE_MYSQL_HOST = 'w.rdc.sae.sina.com.cn'
DEFAULT_SAE_MYSQL_PORT = 3307
DEFAULT_SAE_MYSQL_DB_PREFIX = 'app_'
class CloudSqlDriver(mysql.MySQLDriver):
"""Grizzled DB Driver for Cloud SAE MySQL Service."""
NAME = 'cloudsql'
def get_import(self):
return sae._restful_mysql
def get_display_name(self):
return 'Cloud SQL'
def do_connect(self, host, port, user, password, database):
# Fix grizzled's mysql driver which omit the port argument when connecting.
dbi = self.get_import()
port = port and int(port) or 3306
return dbi.connect(host=host, user=user, passwd=password, db=database, port=port)
class CloudSqlCmd(sqlcmd.SQLCmd):
"""The SQLCmd command interpreter for Cloud SQL."""
sqlcmd.SQLCmd.MAIN_PROMPT = 'mysql> '
sqlcmd.SQLCmd.CONTINUATION_PROMPT = ' -> '
sqlcmd.SQLCmd.NO_SEMI_NEEDED.update(
['about', 'desc', 'describe', 'echo', 'exit', 'h', 'hist',
'history', 'load', 'run', 'r', 'redo', 'set', 'show', 'var', 'vars'])
for method in ['do_dot_connect', 'do_dot_desc', 'do_begin']:
delattr(sqlcmd.SQLCmd, method)
for cmd in ['show', 'describe', 'echo', 'load', 'run', 'exit', 'h',
'hist', 'history', 'var', 'vars', 'about']:
method = 'do_dot_' + cmd
setattr(sqlcmd.SQLCmd, method.replace('dot_', ''), getattr(
sqlcmd.SQLCmd, method))
delattr(sqlcmd.SQLCmd, method)
method = 'complete_dot_' + cmd
if hasattr(sqlcmd.SQLCmd, method):
setattr(sqlcmd.SQLCmd, method.replace('dot_', ''), getattr(
sqlcmd.SQLCmd, method))
delattr(sqlcmd.SQLCmd, method)
def do_redo(self, args):
# XXX: Fix global name 'do_r' is not defined problem in sqlcmd
self.do_r(args)
def _SQLCmd__set_setting(self, varname, value):
# XXX: Fix bool object has no lower attribute in sqlcmd
return sqlcmd.SQLCmd._SQLCmd__set_setting(self, varname, str(value))
def do_desc(self, args):
self.do_describe(args, cmd='.desc')
complete_desc = sqlcmd.SQLCmd.complete_dot_desc
def do_load(self, args):
self.do_run(args)
def preloop(self, *args, **kwargs):
sqlcmd.SQLCmd.preloop(self, *args, **kwargs)
# Just exit if the connect failed
if self._SQLCmd__db is None: sys.exit(1)
def __init__(self, *args, **kwargs):
sqlcmd.SQLCmd.__init__(self, *args, **kwargs)
self.prompt = sqlcmd.SQLCmd.MAIN_PROMPT
self.output_encoding = DEFAULT_ENCODING
def set_output_encoding(self, encoding):
self.output_encoding = encoding
def _build_table(self, cursor):
"""Builds an output PrettyTable from the results in the given cursor."""
if not cursor.description:
return None
column_names = [column[0] for column in cursor.description]
table = prettytable.PrettyTable(column_names)
rows = cursor.fetchall()
if not rows:
return table
for i, col in enumerate(rows[0]):
table.align[column_names[i]] = isinstance(col, basestring) and 'l' or 'r'
for row in rows: table.add_row(row)
return table
def _SQLCmd__handle_select(self, args, cursor, command='select'):
"""Overrides SQLCmd.__handle_select to display output with prettytable."""
self._SQLCmd__exec_SQL(cursor, command, args)
table = self._build_table(cursor)
if table:
output = table.get_string()
if isinstance(output, unicode):
print output.encode(self.output_encoding)
else:
print output
def _create_config_dir():
"""Creates the sqlcmd config directory if necessary."""
directory = sqlcmd.DEFAULT_CONFIG_DIR
if not os.access(directory, os.R_OK | os.W_OK | os.X_OK):
old_umask = os.umask(077)
os.makedirs(sqlcmd.DEFAULT_CONFIG_DIR)
os.umask(old_umask)
def main(argv):
parser = optparse.OptionParser(usage=USAGE)
parser.add_option('-u', '--username', dest='username',
help='MySQL username to use when connecting to the server.')
parser.add_option('-p', '--password', dest='password',
help='MySQL password to use when connecting to the server.')
parser.add_option('-e', '--output_encoding', dest='output_encoding',
default=DEFAULT_ENCODING,
help='Output encoding. Defaults to %s.' % DEFAULT_ENCODING)
(options, args) = parser.parse_args(argv[1:])
if len(args) != 1:
parser.print_help(sys.stderr)
return 1
if not options.username or not options.password:
print >>sys.stderr, 'Error: username or password is missing.\n'
return 1
if args[0].startswith(DEFAULT_SAE_MYSQL_DB_PREFIX):
database_name = args[0]
else:
database_name = DEFAULT_SAE_MYSQL_DB_PREFIX + args[0]
instance_alias = database_name
_create_config_dir()
db.add_driver(CloudSqlDriver.NAME, CloudSqlDriver)
sql_cmd_config = config.SQLCmdConfig(None)
sql_cmd_config.add('__cloudsql__', instance_alias,
DEFAULT_SAE_MYSQL_HOST , DEFAULT_SAE_MYSQL_PORT, database_name,
CloudSqlDriver.NAME, options.username, options.password)
sql_cmd = CloudSqlCmd(sql_cmd_config)
sql_cmd.set_output_encoding(options.output_encoding)
sql_cmd.set_database(instance_alias)
sql_cmd.cmdloop()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))