Skip to content

Commit f491ea9

Browse files
committed
Add upgrade scripts for docs.
1 parent d36854b commit f491ea9

File tree

4 files changed

+790
-0
lines changed

4 files changed

+790
-0
lines changed
Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
# coding: UTF-8
2+
3+
import sys
4+
import os
5+
import ConfigParser
6+
import glob
7+
8+
HAS_MYSQLDB = True
9+
try:
10+
import MySQLdb
11+
except ImportError:
12+
HAS_MYSQLDB = False
13+
14+
HAS_SQLITE3 = True
15+
try:
16+
import sqlite3
17+
except ImportError:
18+
HAS_SQLITE3 = False
19+
20+
class EnvManager(object):
21+
def __init__(self):
22+
self.upgrade_dir = os.path.dirname(__file__)
23+
self.install_path = os.path.dirname(self.upgrade_dir)
24+
self.top_dir = os.path.dirname(self.install_path)
25+
self.ccnet_dir = os.environ['CCNET_CONF_DIR']
26+
self.seafile_dir = os.environ['SEAFILE_CONF_DIR']
27+
self.central_config_dir = os.environ.get('SEAFILE_CENTRAL_CONF_DIR')
28+
29+
30+
env_mgr = EnvManager()
31+
32+
33+
class Utils(object):
34+
@staticmethod
35+
def highlight(content, is_error=False):
36+
'''Add ANSI color to content to get it highlighted on terminal'''
37+
if is_error:
38+
return '\x1b[1;31m%s\x1b[m' % content
39+
else:
40+
return '\x1b[1;32m%s\x1b[m' % content
41+
42+
@staticmethod
43+
def info(msg):
44+
print Utils.highlight('[INFO] ') + msg
45+
46+
@staticmethod
47+
def warning(msg):
48+
print Utils.highlight('[WARNING] ') + msg
49+
50+
@staticmethod
51+
def error(msg):
52+
print Utils.highlight('[ERROR] ') + msg
53+
sys.exit(1)
54+
55+
@staticmethod
56+
def read_config(config_path, defaults):
57+
if not os.path.exists(config_path):
58+
Utils.error('Config path %s doesn\'t exist, stop db upgrade' %
59+
config_path)
60+
cp = ConfigParser.ConfigParser(defaults)
61+
cp.read(config_path)
62+
return cp
63+
64+
65+
class MySQLDBInfo(object):
66+
def __init__(self, host, port, username, password, db, unix_socket=None):
67+
self.host = host
68+
self.port = port
69+
self.username = username
70+
self.password = password
71+
self.db = db
72+
self.unix_socket = unix_socket
73+
74+
75+
class DBUpdater(object):
76+
def __init__(self, version, name):
77+
self.sql_dir = os.path.join(env_mgr.upgrade_dir, 'sql', version, name)
78+
pro_path = os.path.join(env_mgr.install_path, 'pro')
79+
self.is_pro = os.path.exists(pro_path)
80+
81+
@staticmethod
82+
def get_instance(version):
83+
'''Detect whether we are using mysql or sqlite3'''
84+
ccnet_db_info = DBUpdater.get_ccnet_mysql_info(version)
85+
seafile_db_info = DBUpdater.get_seafile_mysql_info(version)
86+
seahub_db_info = DBUpdater.get_seahub_mysql_info()
87+
88+
if ccnet_db_info and seafile_db_info and seahub_db_info:
89+
Utils.info('You are using MySQL')
90+
if not HAS_MYSQLDB:
91+
Utils.error('Python MySQLdb module is not found')
92+
updater = MySQLDBUpdater(version, ccnet_db_info, seafile_db_info, seahub_db_info)
93+
94+
elif (ccnet_db_info is None) and (seafile_db_info is None) and (seahub_db_info is None):
95+
Utils.info('You are using SQLite3')
96+
if not HAS_SQLITE3:
97+
Utils.error('Python sqlite3 module is not found')
98+
updater = SQLiteDBUpdater(version)
99+
100+
else:
101+
def to_db_string(info):
102+
if info is None:
103+
return 'SQLite3'
104+
else:
105+
return 'MySQL'
106+
Utils.error('Error:\n ccnet is using %s\n seafile is using %s\n seahub is using %s\n'
107+
% (to_db_string(ccnet_db_info),
108+
to_db_string(seafile_db_info),
109+
to_db_string(seahub_db_info)))
110+
111+
return updater
112+
113+
def update_db(self):
114+
ccnet_sql = os.path.join(self.sql_dir, 'ccnet.sql')
115+
seafile_sql = os.path.join(self.sql_dir, 'seafile.sql')
116+
seahub_sql = os.path.join(self.sql_dir, 'seahub.sql')
117+
seafevents_sql = os.path.join(self.sql_dir, 'seafevents.sql')
118+
119+
if os.path.exists(ccnet_sql):
120+
Utils.info('updating ccnet database...')
121+
self.update_ccnet_sql(ccnet_sql)
122+
123+
if os.path.exists(seafile_sql):
124+
Utils.info('updating seafile database...')
125+
self.update_seafile_sql(seafile_sql)
126+
127+
if os.path.exists(seahub_sql):
128+
Utils.info('updating seahub database...')
129+
self.update_seahub_sql(seahub_sql)
130+
131+
if os.path.exists(seafevents_sql):
132+
self.update_seafevents_sql(seafevents_sql)
133+
134+
@staticmethod
135+
def get_ccnet_mysql_info(version):
136+
config_path = env_mgr.central_config_dir
137+
138+
ccnet_conf = os.path.join(config_path, 'ccnet.conf')
139+
defaults = {
140+
'HOST': '127.0.0.1',
141+
'PORT': '3306',
142+
'UNIX_SOCKET': '',
143+
}
144+
145+
config = Utils.read_config(ccnet_conf, defaults)
146+
db_section = 'Database'
147+
148+
if not config.has_section(db_section):
149+
return None
150+
151+
type = config.get(db_section, 'ENGINE')
152+
if type != 'mysql':
153+
return None
154+
155+
try:
156+
host = config.get(db_section, 'HOST')
157+
port = config.getint(db_section, 'PORT')
158+
username = config.get(db_section, 'USER')
159+
password = config.get(db_section, 'PASSWD')
160+
db = config.get(db_section, 'DB')
161+
unix_socket = config.get(db_section, 'UNIX_SOCKET')
162+
except ConfigParser.NoOptionError, e:
163+
Utils.error('Database config in ccnet.conf is invalid: %s' % e)
164+
165+
info = MySQLDBInfo(host, port, username, password, db, unix_socket)
166+
return info
167+
168+
@staticmethod
169+
def get_seafile_mysql_info(version):
170+
config_path = env_mgr.central_config_dir
171+
172+
seafile_conf = os.path.join(config_path, 'seafile.conf')
173+
defaults = {
174+
'HOST': '127.0.0.1',
175+
'PORT': '3306',
176+
'UNIX_SOCKET': '',
177+
}
178+
config = Utils.read_config(seafile_conf, defaults)
179+
db_section = 'database'
180+
181+
if not config.has_section(db_section):
182+
return None
183+
184+
type = config.get(db_section, 'type')
185+
if type != 'mysql':
186+
return None
187+
188+
try:
189+
host = config.get(db_section, 'host')
190+
port = config.getint(db_section, 'port')
191+
username = config.get(db_section, 'user')
192+
password = config.get(db_section, 'password')
193+
db = config.get(db_section, 'db_name')
194+
unix_socket = config.get(db_section, 'unix_socket')
195+
except ConfigParser.NoOptionError, e:
196+
Utils.error('Database config in seafile.conf is invalid: %s' % e)
197+
198+
info = MySQLDBInfo(host, port, username, password, db, unix_socket)
199+
return info
200+
201+
@staticmethod
202+
def get_seahub_mysql_info():
203+
sys.path.insert(0, env_mgr.top_dir)
204+
if env_mgr.central_config_dir:
205+
sys.path.insert(0, env_mgr.central_config_dir)
206+
try:
207+
import seahub_settings # pylint: disable=F0401
208+
except ImportError, e:
209+
Utils.error('Failed to import seahub_settings.py: %s' % e)
210+
211+
if not hasattr(seahub_settings, 'DATABASES'):
212+
return None
213+
214+
try:
215+
d = seahub_settings.DATABASES['default']
216+
if d['ENGINE'] != 'django.db.backends.mysql':
217+
return None
218+
219+
host = d.get('HOST', '127.0.0.1')
220+
port = int(d.get('PORT', 3306))
221+
username = d['USER']
222+
password = d['PASSWORD']
223+
db = d['NAME']
224+
unix_socket = host if host.startswith('/') else None
225+
except KeyError:
226+
Utils.error('Database config in seahub_settings.py is invalid: %s' % e)
227+
228+
info = MySQLDBInfo(host, port, username, password, db, unix_socket)
229+
return info
230+
231+
def update_ccnet_sql(self, ccnet_sql):
232+
raise NotImplementedError
233+
234+
def update_seafile_sql(self, seafile_sql):
235+
raise NotImplementedError
236+
237+
def update_seahub_sql(self, seahub_sql):
238+
raise NotImplementedError
239+
240+
def update_seafevents_sql(self, seafevents_sql):
241+
raise NotImplementedError
242+
243+
class CcnetSQLiteDB(object):
244+
def __init__(self, ccnet_dir):
245+
self.ccnet_dir = ccnet_dir
246+
247+
def get_db(self, dbname):
248+
dbs = (
249+
'ccnet.db',
250+
'GroupMgr/groupmgr.db',
251+
'misc/config.db',
252+
'OrgMgr/orgmgr.db',
253+
'PeerMgr/usermgr.db',
254+
)
255+
for db in dbs:
256+
if os.path.splitext(os.path.basename(db))[0] == dbname:
257+
return os.path.join(self.ccnet_dir, db)
258+
259+
class SQLiteDBUpdater(DBUpdater):
260+
def __init__(self, version):
261+
DBUpdater.__init__(self, version, 'sqlite3')
262+
263+
self.ccnet_db = CcnetSQLiteDB(env_mgr.ccnet_dir)
264+
self.seafile_db = os.path.join(env_mgr.seafile_dir, 'seafile.db')
265+
self.seahub_db = os.path.join(env_mgr.top_dir, 'seahub.db')
266+
self.seafevents_db = os.path.join(env_mgr.top_dir, 'seafevents.db')
267+
268+
def update_db(self):
269+
super(SQLiteDBUpdater, self).update_db()
270+
for sql_path in glob.glob(os.path.join(self.sql_dir, 'ccnet', '*.sql')):
271+
self.update_ccnet_sql(sql_path)
272+
273+
def apply_sqls(self, db_path, sql_path):
274+
with open(sql_path, 'r') as fp:
275+
lines = fp.read().split(';')
276+
277+
with sqlite3.connect(db_path) as conn:
278+
for line in lines:
279+
line = line.strip()
280+
if not line:
281+
continue
282+
else:
283+
conn.execute(line)
284+
285+
def update_ccnet_sql(self, sql_path):
286+
dbname = os.path.splitext(os.path.basename(sql_path))[0]
287+
self.apply_sqls(self.ccnet_db.get_db(dbname), sql_path)
288+
289+
def update_seafile_sql(self, sql_path):
290+
self.apply_sqls(self.seafile_db, sql_path)
291+
292+
def update_seahub_sql(self, sql_path):
293+
self.apply_sqls(self.seahub_db, sql_path)
294+
295+
def update_seafevents_sql(self, sql_path):
296+
if self.is_pro:
297+
Utils.info('seafevents do not support sqlite3 database')
298+
299+
300+
class MySQLDBUpdater(DBUpdater):
301+
def __init__(self, version, ccnet_db_info, seafile_db_info, seahub_db_info):
302+
DBUpdater.__init__(self, version, 'mysql')
303+
self.ccnet_db_info = ccnet_db_info
304+
self.seafile_db_info = seafile_db_info
305+
self.seahub_db_info = seahub_db_info
306+
307+
def update_ccnet_sql(self, ccnet_sql):
308+
self.apply_sqls(self.ccnet_db_info, ccnet_sql)
309+
310+
def update_seafile_sql(self, seafile_sql):
311+
self.apply_sqls(self.seafile_db_info, seafile_sql)
312+
313+
def update_seahub_sql(self, seahub_sql):
314+
self.apply_sqls(self.seahub_db_info, seahub_sql)
315+
316+
def update_seafevents_sql(self, seafevents_sql):
317+
if self.is_pro:
318+
Utils.info('updating seafevents database...')
319+
self.apply_sqls(self.seahub_db_info, seafevents_sql)
320+
321+
def get_conn(self, info):
322+
kw = dict(
323+
user=info.username,
324+
passwd=info.password,
325+
db=info.db,
326+
)
327+
if info.unix_socket:
328+
kw['unix_socket'] = info.unix_socket
329+
else:
330+
kw['host'] = info.host
331+
kw['port'] = info.port
332+
try:
333+
conn = MySQLdb.connect(**kw)
334+
except Exception, e:
335+
if isinstance(e, MySQLdb.OperationalError):
336+
msg = str(e.args[1])
337+
else:
338+
msg = str(e)
339+
Utils.error('Failed to connect to mysql database %s: %s' % (info.db, msg))
340+
341+
return conn
342+
343+
def execute_sql(self, conn, sql):
344+
cursor = conn.cursor()
345+
try:
346+
cursor.execute(sql)
347+
conn.commit()
348+
except Exception, e:
349+
msg = str(e)
350+
Utils.warning('Failed to execute sql: %s' % msg)
351+
352+
def apply_sqls(self, info, sql_path):
353+
with open(sql_path, 'r') as fp:
354+
lines = fp.read().split(';')
355+
356+
conn = self.get_conn(info)
357+
358+
for line in lines:
359+
line = line.strip()
360+
if not line:
361+
continue
362+
else:
363+
self.execute_sql(conn, line)
364+
365+
366+
def main():
367+
skipdb = os.environ.get('SEAFILE_SKIP_DB_UPGRADE', '').lower()
368+
if skipdb in ('1', 'true', 'on'):
369+
print 'Database upgrade skipped because SEAFILE_SKIP_DB_UPGRADE=%s' % skipdb
370+
sys.exit()
371+
version = sys.argv[1]
372+
db_updater = DBUpdater.get_instance(version)
373+
db_updater.update_db()
374+
375+
return 0
376+
377+
if __name__ == '__main__':
378+
main()

0 commit comments

Comments
 (0)