You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
13 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
11 vuotta sitten
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. #!/usr/bin/env python2.7
  2. # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
  3. # MIT License. See license.txt
  4. from __future__ import unicode_literals
  5. import sys, os
  6. import webnotes
  7. site_arg_optional = ['serve']
  8. def main():
  9. parsed_args = webnotes._dict(vars(setup_parser()))
  10. fn = get_function(parsed_args)
  11. if not parsed_args.get("sites_path"):
  12. parsed_args["sites_path"] = "."
  13. if not parsed_args.get("make_app"):
  14. if not parsed_args.get("site") and not fn in site_arg_optional:
  15. print "Site argument required"
  16. exit(1)
  17. if fn not in site_arg_optional and (fn != 'install' and not os.path.exists(parsed_args.get("site"))):
  18. print "Did not find folder '{}'. Are you in sites folder?".format(parsed_args.get("site"))
  19. exit(1)
  20. if parsed_args.get("site")=="all":
  21. for site in get_sites():
  22. args = parsed_args.copy()
  23. args["site"] = site
  24. webnotes.init(site)
  25. run(fn, args)
  26. else:
  27. if not fn in site_arg_optional:
  28. webnotes.init(parsed_args.get("site"))
  29. run(fn, parsed_args)
  30. else:
  31. run(fn, parsed_args)
  32. def cmd(fn):
  33. def new_fn(*args, **kwargs):
  34. import inspect
  35. fnargs, varargs, varkw, defaults = inspect.getargspec(fn)
  36. new_kwargs = {}
  37. for a in fnargs:
  38. if a in kwargs:
  39. new_kwargs[a] = kwargs.get(a)
  40. return fn(*args, **new_kwargs)
  41. return new_fn
  42. def run(fn, args):
  43. if isinstance(args.get(fn), (list, tuple)):
  44. out = globals().get(fn)(*args.get(fn), **args)
  45. else:
  46. out = globals().get(fn)(**args)
  47. return out
  48. def get_function(args):
  49. for fn, val in args.items():
  50. if (val or isinstance(val, list)) and globals().get(fn):
  51. return fn
  52. def get_sites():
  53. import os
  54. import conf
  55. return [site for site in os.listdir(conf.sites_dir)
  56. if not os.path.islink(os.path.join(conf.sites_dir, site))
  57. and os.path.isdir(os.path.join(conf.sites_dir, site))]
  58. def setup_parser():
  59. import argparse
  60. parser = argparse.ArgumentParser(description="Run webnotes utility functions")
  61. setup_install(parser)
  62. setup_utilities(parser)
  63. setup_translation(parser)
  64. setup_test(parser)
  65. parser.add_argument("site", nargs="?")
  66. # common
  67. parser.add_argument("-f", "--force", default=False, action="store_true",
  68. help="Force execution where applicable (look for [-f] in help)")
  69. parser.add_argument("-v", "--verbose", default=False, action="store_true", dest="verbose",
  70. help="Show verbose output where applicable")
  71. return parser.parse_args()
  72. def setup_install(parser):
  73. parser.add_argument("--make_app", default=False, action="store_true",
  74. help="Make a new application with boilerplate")
  75. parser.add_argument("--install", metavar="DB-NAME", nargs=1,
  76. help="Install a new db")
  77. parser.add_argument("--install_app", metavar="APP-NAME", nargs=1,
  78. help="Install a new app")
  79. parser.add_argument("--root-password", nargs=1,
  80. help="Root password for new app")
  81. parser.add_argument("--reinstall", default=False, action="store_true",
  82. help="Install a fresh app in db_name specified in conf.py")
  83. parser.add_argument("--restore", metavar=("DB-NAME", "SQL-FILE"), nargs=2,
  84. help="Restore from an sql file")
  85. parser.add_argument("--add_system_manager", nargs="+",
  86. metavar=("EMAIL", "[FIRST-NAME] [LAST-NAME]"), help="Add a user with all roles")
  87. def setup_test(parser):
  88. parser.add_argument("--run_tests", default=False, action="store_true",
  89. help="Run tests options [-d doctype], [-m module]")
  90. parser.add_argument("--app", metavar="APP-NAME", nargs=1,
  91. help="Run command for specified app")
  92. parser.add_argument("-d", "--doctype", metavar="DOCTYPE", nargs=1,
  93. help="Run command for specified doctype")
  94. parser.add_argument("-m", "--module", metavar="MODULE", nargs=1,
  95. help="Run command for specified module")
  96. def setup_utilities(parser):
  97. # update
  98. parser.add_argument("-u", "--update", nargs="*", metavar=("REMOTE", "BRANCH"),
  99. help="Perform git pull, run patches, sync schema and rebuild files/translations")
  100. parser.add_argument("--reload_gunicorn", default=False, action="store_true", help="reload gunicorn on update")
  101. parser.add_argument("--patch", nargs=1, metavar="PATCH-MODULE",
  102. help="Run a particular patch [-f]")
  103. parser.add_argument("-l", "--latest", default=False, action="store_true",
  104. help="Run patches, sync schema and rebuild files/translations")
  105. parser.add_argument("--sync_all", default=False, action="store_true",
  106. help="Reload all doctypes, pages, etc. using txt files [-f]")
  107. parser.add_argument("--update_all_sites", nargs="*", metavar=("REMOTE", "BRANCH"),
  108. help="Perform git pull, run patches, sync schema and rebuild files/translations")
  109. parser.add_argument("--reload_doc", nargs=3,
  110. metavar=('"MODULE"', '"DOCTYPE"', '"DOCNAME"'))
  111. # build
  112. parser.add_argument("-b", "--build", default=False, action="store_true",
  113. help="Minify + concatenate JS and CSS files, build translations")
  114. parser.add_argument("-w", "--watch", default=False, action="store_true",
  115. help="Watch and concatenate JS and CSS files as and when they change")
  116. # misc
  117. parser.add_argument("--backup", default=False, action="store_true",
  118. help="Take backup of database in backup folder [--with_files]")
  119. parser.add_argument("--move", default=False, action="store_true",
  120. help="Move site to different directory defined by --dest_dir")
  121. parser.add_argument("--dest_dir", nargs=1, metavar="DEST-DIR",
  122. help="Move site to different directory")
  123. parser.add_argument("--with_files", default=False, action="store_true",
  124. help="Also take backup of files")
  125. parser.add_argument("--domain", nargs="*",
  126. help="Get or set domain in Website Settings")
  127. parser.add_argument("--make_conf", nargs="*", metavar=("DB-NAME", "DB-PASSWORD"),
  128. help="Create new conf.py file")
  129. parser.add_argument("--make_custom_server_script", nargs=1, metavar="DOCTYPE",
  130. help="Create new conf.py file")
  131. parser.add_argument("--set_admin_password", metavar='ADMIN-PASSWORD', nargs=1,
  132. help="Set administrator password")
  133. parser.add_argument("--request", metavar='URL-ARGS', nargs=1, help="Run request as admin")
  134. parser.add_argument("--mysql", action="store_true", help="get mysql shell for a site")
  135. parser.add_argument("--serve", action="store_true", help="Run development server")
  136. parser.add_argument("--profile", action="store_true", help="enable profiling in development server")
  137. parser.add_argument("--smtp", action="store_true", help="Run smtp debug server",
  138. dest="smtp_debug_server")
  139. parser.add_argument("--python", action="store_true", help="get python shell for a site")
  140. parser.add_argument("--ipython", action="store_true", help="get ipython shell for a site")
  141. parser.add_argument("--get_site_status", action="store_true", help="Get site details")
  142. parser.add_argument("--update_site_config", nargs=1,
  143. metavar="site-CONFIG-JSON",
  144. help="Update site_config.json for a given site")
  145. parser.add_argument("--port", default=8000, type=int, help="port for development server")
  146. # clear
  147. parser.add_argument("--clear_web", default=False, action="store_true",
  148. help="Clear website cache")
  149. parser.add_argument("--build_sitemap", default=False, action="store_true",
  150. help="Build Website Sitemap")
  151. parser.add_argument("--clear_cache", default=False, action="store_true",
  152. help="Clear cache, doctype cache and defaults")
  153. parser.add_argument("--reset_perms", default=False, action="store_true",
  154. help="Reset permissions for all doctypes")
  155. # scheduler
  156. parser.add_argument("--run_scheduler", default=False, action="store_true",
  157. help="Trigger scheduler")
  158. parser.add_argument("--run_scheduler_event", nargs=1,
  159. metavar="all | daily | weekly | monthly",
  160. help="Run a scheduler event")
  161. # replace
  162. parser.add_argument("--replace", nargs=3,
  163. metavar=("SEARCH-REGEX", "REPLACE-BY", "FILE-EXTN"),
  164. help="Multi-file search-replace [-f]")
  165. # import/export
  166. parser.add_argument("--export_doc", nargs=2, metavar=('"DOCTYPE"', '"DOCNAME"'))
  167. parser.add_argument("--export_doclist", nargs=3, metavar=("DOCTYPE", "NAME", "PATH"),
  168. help="""Export doclist as json to the given path, use '-' as name for Singles.""")
  169. parser.add_argument("--export_csv", nargs=2, metavar=("DOCTYPE", "PATH"),
  170. help="""Dump DocType as csv""")
  171. parser.add_argument("--import_doclist", nargs=1, metavar="PATH",
  172. help="""Import (insert/update) doclist. If the argument is a directory, all files ending with .json are imported""")
  173. def setup_translation(parser):
  174. parser.add_argument("--build_message_files", default=False, action="store_true",
  175. help="Build message files for translation.")
  176. parser.add_argument("--get_untranslated", nargs=2, metavar=("LANG-CODE", "TARGET-FILE-PATH"),
  177. help="""Get untranslated strings for lang.""")
  178. parser.add_argument("--update_translations", nargs=3,
  179. metavar=("LANG-CODE", "UNTRANSLATED-FILE-PATH", "TRANSLATED-FILE-PATH"),
  180. help="""Update translated strings.""")
  181. # methods
  182. @cmd
  183. def make_app():
  184. from webnotes.utils.boilerplate import make_boilerplate
  185. make_boilerplate()
  186. # install
  187. @cmd
  188. def install(db_name, root_login="root", root_password=None, source_sql=None,
  189. admin_password = 'admin', verbose=True, force=False, site_config=None, reinstall=False):
  190. from webnotes.installer import install_db, install_app
  191. install_db(root_login=root_login, root_password=root_password, db_name=db_name, source_sql=source_sql,
  192. admin_password = admin_password, verbose=verbose, force=force, site_config=site_config, reinstall=reinstall)
  193. install_app("webnotes", verbose=verbose)
  194. webnotes.destroy()
  195. @cmd
  196. def install_app(app_name, verbose=False):
  197. from webnotes.installer import install_app
  198. webnotes.connect()
  199. install_app(app_name, verbose=verbose)
  200. webnotes.destroy()
  201. @cmd
  202. def reinstall(verbose=True):
  203. install(db_name=webnotes.conf.db_name, verbose=verbose, force=True, reinstall=True)
  204. @cmd
  205. def restore(db_name, source_sql, verbose=True, force=False):
  206. install(db_name, source_sql, verbose=verbose, force=force)
  207. @cmd
  208. def install_fixtures():
  209. from webnotes.install_lib.install import install_fixtures
  210. install_fixtures()
  211. webnotes.destroy()
  212. @cmd
  213. def add_system_manager(email, first_name=None, last_name=None):
  214. webnotes.connect()
  215. webnotes.profile.add_system_manager(email, first_name, last_name)
  216. webnotes.conn.commit()
  217. webnotes.destroy()
  218. # utilities
  219. @cmd
  220. def update(remote=None, branch=None, reload_gunicorn=False):
  221. pull(remote=remote, branch=branch)
  222. # maybe there are new framework changes, any consequences?
  223. reload(webnotes)
  224. build()
  225. latest()
  226. if reload_gunicorn:
  227. import subprocess
  228. subprocess.check_output("killall -HUP gunicorn".split())
  229. @cmd
  230. def latest(verbose=True):
  231. import webnotes.modules.patch_handler
  232. import webnotes.model.sync
  233. from webnotes.website import rebuild_config
  234. webnotes.connect()
  235. try:
  236. # run patches
  237. webnotes.local.patch_log_list = []
  238. webnotes.modules.patch_handler.run_all()
  239. if verbose:
  240. print "\n".join(webnotes.local.patch_log_list)
  241. # sync
  242. webnotes.model.sync.sync_all()
  243. # build website config if any changes in templates etc.
  244. rebuild_config()
  245. except webnotes.modules.patch_handler.PatchError, e:
  246. print "\n".join(webnotes.local.patch_log_list)
  247. raise
  248. finally:
  249. webnotes.destroy()
  250. @cmd
  251. def sync_all(force=False):
  252. import webnotes.model.sync
  253. webnotes.connect()
  254. webnotes.model.sync.sync_all(force=force)
  255. webnotes.destroy()
  256. @cmd
  257. def patch(patch_module, force=False):
  258. import webnotes.modules.patch_handler
  259. webnotes.connect()
  260. webnotes.local.patch_log_list = []
  261. webnotes.modules.patch_handler.run_single(patch_module, force=force)
  262. print "\n".join(webnotes.local.patch_log_list)
  263. webnotes.destroy()
  264. @cmd
  265. def update_all_sites(remote=None, branch=None, verbose=True):
  266. pull(remote, branch)
  267. # maybe there are new framework changes, any consequences?
  268. reload(webnotes)
  269. build()
  270. for site in get_sites():
  271. webnotes.init(site)
  272. latest(verbose=verbose)
  273. @cmd
  274. def reload_doc(module, doctype, docname, force=False):
  275. webnotes.connect()
  276. webnotes.reload_doc(module, doctype, docname, force=force)
  277. webnotes.conn.commit()
  278. webnotes.destroy()
  279. @cmd
  280. def build():
  281. import webnotes.build
  282. import webnotes
  283. webnotes.build.bundle(False)
  284. @cmd
  285. def watch():
  286. import webnotes.build
  287. webnotes.build.watch(True)
  288. @cmd
  289. def backup(with_files=False, verbose=True, backup_path_db=None, backup_path_files=None):
  290. from webnotes.utils.backups import scheduled_backup
  291. webnotes.connect()
  292. odb = scheduled_backup(ignore_files=not with_files, backup_path_db=backup_path_db, backup_path_files=backup_path_files)
  293. if verbose:
  294. from webnotes.utils import now
  295. print "database backup taken -", odb.backup_path_db, "- on", now()
  296. if with_files:
  297. print "files backup taken -", odb.backup_path_files, "- on", now()
  298. webnotes.destroy()
  299. return odb
  300. @cmd
  301. def move(dest_dir=None):
  302. import os
  303. if not dest_dir:
  304. raise Exception, "--dest_dir is required for --move"
  305. if not os.path.isdir(dest_dir):
  306. raise Exception, "destination is not a directory or does not exist"
  307. old_path = webnotes.utils.get_site()
  308. new_path = os.path.join(dest_dir, site)
  309. # check if site dump of same name already exists
  310. site_dump_exists = True
  311. count = 0
  312. while site_dump_exists:
  313. final_new_path = new_path + (count and str(count) or "")
  314. site_dump_exists = os.path.exists(final_new_path)
  315. count = int(count or 0) + 1
  316. os.rename(old_path, final_new_path)
  317. webnotes.destroy()
  318. return os.path.basename(final_new_path)
  319. @cmd
  320. def domain(host_url=None):
  321. webnotes.connect()
  322. if host_url:
  323. webnotes.conn.set_value("Website Settings", None, "subdomain", host_url)
  324. webnotes.conn.commit()
  325. else:
  326. print webnotes.conn.get_value("Website Settings", None, "subdomain")
  327. webnotes.destroy()
  328. @cmd
  329. def make_conf(db_name=None, db_password=None, site_config=None):
  330. from webnotes.install_lib.install import make_conf
  331. make_conf(db_name=db_name, db_password=db_password, site_config=site_config)
  332. @cmd
  333. def make_custom_server_script(doctype):
  334. from webnotes.core.doctype.custom_script.custom_script import make_custom_server_script_file
  335. webnotes.connect()
  336. make_custom_server_script_file(doctype)
  337. webnotes.destroy()
  338. # clear
  339. @cmd
  340. def clear_cache():
  341. import webnotes.sessions
  342. webnotes.connect()
  343. webnotes.clear_cache()
  344. webnotes.destroy()
  345. @cmd
  346. def clear_web():
  347. import webnotes.webutils
  348. webnotes.connect()
  349. webnotes.webutils.clear_cache()
  350. webnotes.destroy()
  351. @cmd
  352. def build_sitemap():
  353. from webnotes.website import rebuild_config
  354. webnotes.connect()
  355. rebuild_config()
  356. webnotes.destroy()
  357. @cmd
  358. def reset_perms():
  359. webnotes.connect()
  360. for d in webnotes.conn.sql_list("""select name from `tabDocType`
  361. where ifnull(istable, 0)=0 and ifnull(custom, 0)=0"""):
  362. webnotes.clear_cache(doctype=d)
  363. webnotes.reset_perms(d)
  364. webnotes.destroy()
  365. # scheduler
  366. @cmd
  367. def run_scheduler():
  368. from webnotes.utils.file_lock import create_lock, delete_lock
  369. import webnotes.utils.scheduler
  370. if create_lock('scheduler'):
  371. webnotes.connect()
  372. print webnotes.utils.scheduler.execute()
  373. delete_lock('scheduler')
  374. webnotes.destroy()
  375. @cmd
  376. def run_scheduler_event(event):
  377. import webnotes.utils.scheduler
  378. webnotes.connect()
  379. print webnotes.utils.scheduler.trigger("execute_" + event)
  380. webnotes.destroy()
  381. # replace
  382. @cmd
  383. def replace(search_regex, replacement, extn, force=False):
  384. print search_regex, replacement, extn
  385. replace_code('.', search_regex, replacement, extn, force=force)
  386. # import/export
  387. @cmd
  388. def export_doc(doctype, docname):
  389. import webnotes.modules
  390. webnotes.connect()
  391. webnotes.modules.export_doc(doctype, docname)
  392. webnotes.destroy()
  393. @cmd
  394. def export_doclist(doctype, name, path):
  395. from webnotes.core.page.data_import_tool import data_import_tool
  396. webnotes.connect()
  397. data_import_tool.export_json(doctype, name, path)
  398. webnotes.destroy()
  399. @cmd
  400. def export_csv(doctype, path):
  401. from webnotes.core.page.data_import_tool import data_import_tool
  402. webnotes.connect()
  403. data_import_tool.export_csv(doctype, path)
  404. webnotes.destroy()
  405. @cmd
  406. def import_doclist(path, force=False):
  407. from webnotes.core.page.data_import_tool import data_import_tool
  408. webnotes.connect()
  409. data_import_tool.import_doclist(path, overwrite=force)
  410. webnotes.destroy()
  411. # translation
  412. @cmd
  413. def build_message_files():
  414. import webnotes.translate
  415. webnotes.connect()
  416. webnotes.translate.rebuild_all_translation_files()
  417. webnotes.destroy()
  418. @cmd
  419. def get_untranslated(lang, untranslated_file):
  420. import webnotes.translate
  421. webnotes.connect()
  422. webnotes.translate.get_untranslated(lang, untranslated_file)
  423. webnotes.destroy()
  424. @cmd
  425. def update_translations(lang, untranslated_file, translated_file):
  426. import webnotes.translate
  427. webnotes.connect()
  428. webnotes.translate.update_translations(lang, untranslated_file, translated_file)
  429. webnotes.destroy()
  430. # git
  431. @cmd
  432. def git(param):
  433. if isinstance(param, (list, tuple)):
  434. param = " ".join(param)
  435. import os
  436. os.system("""cd lib && git %s""" % param)
  437. os.system("""cd app && git %s""" % param)
  438. def get_remote_and_branch(remote=None, branch=None):
  439. if not (remote and branch):
  440. if not webnotes.conf.branch:
  441. raise Exception("Please specify remote and branch")
  442. remote = remote or "origin"
  443. branch = branch or webnotes.conf.branch
  444. webnotes.destroy()
  445. return remote, branch
  446. @cmd
  447. def pull(remote=None, branch=None):
  448. remote, branch = get_remote_and_branch(remote, branch)
  449. git(("pull", remote, branch))
  450. @cmd
  451. def push(remote=None, branch=None):
  452. remote, branch = get_remote_and_branch(remote, branch)
  453. git(("push", remote, branch))
  454. @cmd
  455. def status():
  456. git("status")
  457. @cmd
  458. def commit(message):
  459. git("""commit -a -m "%s" """ % message.replace('"', '\"'))
  460. @cmd
  461. def checkout(branch):
  462. git(("checkout", branch))
  463. @cmd
  464. def set_admin_password(admin_password):
  465. import webnotes
  466. webnotes.connect()
  467. webnotes.conn.sql("""update __Auth set `password`=password(%s)
  468. where user='Administrator'""", (admin_password,))
  469. webnotes.conn.commit()
  470. webnotes.destroy()
  471. @cmd
  472. def mysql():
  473. import webnotes
  474. import commands, os
  475. msq = commands.getoutput('which mysql')
  476. os.execv(msq, [msq, '-u', webnotes.conf.db_name, '-p'+webnotes.conf.db_password, webnotes.conf.db_name, '-h', webnotes.conf.db_host or "localhost", "-A"])
  477. webnotes.destroy()
  478. @cmd
  479. def python(site):
  480. import webnotes
  481. import commands, os
  482. python = commands.getoutput('which python')
  483. if site:
  484. os.environ["site"] = site
  485. os.environ["PYTHONSTARTUP"] = os.path.join(os.path.dirname(webnotes.__file__), "pythonrc.py")
  486. os.execv(python, [python])
  487. webnotes.destroy()
  488. @cmd
  489. def ipython():
  490. import webnotes
  491. webnotes.connect()
  492. import IPython
  493. IPython.embed()
  494. @cmd
  495. def smtp_debug_server():
  496. import commands, os
  497. python = commands.getoutput('which python')
  498. os.execv(python, [python, '-m', "smtpd", "-n", "-c", "DebuggingServer", "localhost:25"])
  499. @cmd
  500. def run_tests(app=None, module=None, doctype=None, verbose=False):
  501. import webnotes.test_runner
  502. ret = webnotes.test_runner.main(app and app[0], module and module[0], doctype and doctype[0], verbose)
  503. if len(ret.failures) > 0 or len(ret.errors) > 0:
  504. exit(1)
  505. @cmd
  506. def serve(port=8000, profile=False, site=None):
  507. import webnotes.app
  508. webnotes.app.serve(port=port, profile=profile, site=site)
  509. @cmd
  510. def request(args):
  511. import webnotes.handler
  512. webnotes.connect()
  513. webnotes.form_dict = webnotes._dict([a.split("=") for a in args.split("&")])
  514. webnotes.handler.execute_cmd(webnotes.form_dict.cmd)
  515. print webnotes.response
  516. webnotes.destroy()
  517. def replace_code(start, txt1, txt2, extn, search=None, force=False):
  518. """replace all txt1 by txt2 in files with extension (extn)"""
  519. import webnotes.utils
  520. import os, re
  521. esc = webnotes.utils.make_esc('[]')
  522. if not search: search = esc(txt1)
  523. for wt in os.walk(start, followlinks=1):
  524. for fn in wt[2]:
  525. if fn.split('.')[-1]==extn:
  526. fpath = os.path.join(wt[0], fn)
  527. with open(fpath, 'r') as f:
  528. content = f.read()
  529. if re.search(search, content):
  530. res = search_replace_with_prompt(fpath, txt1, txt2, force)
  531. if res == 'skip':
  532. return 'skip'
  533. def search_replace_with_prompt(fpath, txt1, txt2, force=False):
  534. """ Search and replace all txt1 by txt2 in the file with confirmation"""
  535. from termcolor import colored
  536. with open(fpath, 'r') as f:
  537. content = f.readlines()
  538. tmp = []
  539. for c in content:
  540. if c.find(txt1) != -1:
  541. print fpath
  542. print colored(txt1, 'red').join(c[:-1].split(txt1))
  543. a = ''
  544. if force:
  545. c = c.replace(txt1, txt2)
  546. else:
  547. while a.lower() not in ['y', 'n', 'skip']:
  548. a = raw_input('Do you want to Change [y/n/skip]?')
  549. if a.lower() == 'y':
  550. c = c.replace(txt1, txt2)
  551. elif a.lower() == 'skip':
  552. return 'skip'
  553. tmp.append(c)
  554. with open(fpath, 'w') as f:
  555. f.write(''.join(tmp))
  556. print colored('Updated', 'green')
  557. @cmd
  558. def get_site_status(verbose=False):
  559. import webnotes
  560. import webnotes.utils
  561. from webnotes.profile import get_system_managers
  562. from webnotes.core.doctype.profile.profile import get_total_users, get_active_users, \
  563. get_website_users, get_active_website_users
  564. import json
  565. webnotes.connect()
  566. ret = {
  567. 'last_backup_on': webnotes.local.conf.last_backup_on,
  568. 'active_users': get_active_users(),
  569. 'total_users': get_total_users(),
  570. 'active_website_users': get_active_website_users(),
  571. 'website_users': get_website_users(),
  572. 'system_managers': "\n".join(get_system_managers()),
  573. 'default_company': webnotes.conn.get_default("company"),
  574. 'disk_usage': webnotes.utils.get_disk_usage(),
  575. 'working_directory': webnotes.local.site_path
  576. }
  577. # country, timezone, industry
  578. control_panel_details = webnotes.conn.get_value("Control Panel", "Control Panel",
  579. ["country", "time_zone", "industry"], as_dict=True)
  580. if control_panel_details:
  581. ret.update(control_panel_details)
  582. # basic usage/progress analytics
  583. for doctype in ("Company", "Customer", "Item", "Quotation", "Sales Invoice",
  584. "Journal Voucher", "Stock Ledger Entry"):
  585. key = doctype.lower().replace(" ", "_") + "_exists"
  586. ret[key] = 1 if webnotes.conn.count(doctype) else 0
  587. webnotes.destroy()
  588. if verbose:
  589. print json.dumps(ret, indent=1, sort_keys=True)
  590. return ret
  591. @cmd
  592. def update_site_config(site_config, verbose=False):
  593. import json
  594. if isinstance(site_config, basestring):
  595. site_config = json.loads(site_config)
  596. webnotes.conf.site_config.update(site_config)
  597. site_config_path = webnotes.get_conf_path(webnotes.conf.sites_dir)
  598. with open(site_config_path, "w") as f:
  599. json.dump(webnotes.conf.site_config, f, indent=1, sort_keys=True)
  600. webnotes.destroy()
  601. @cmd
  602. def bump(repo, bump_type):
  603. import json
  604. assert repo in ['lib', 'app']
  605. assert bump_type in ['minor', 'major', 'patch']
  606. def validate(repo_path):
  607. import git
  608. repo = git.Repo(repo_path)
  609. if repo.active_branch != 'master':
  610. raise Exception, "Current branch not master in {}".format(repo_path)
  611. def bump_version(version, version_type):
  612. import semantic_version
  613. v = semantic_version.Version(version)
  614. if version_type == 'minor':
  615. v.minor += 1
  616. elif version_type == 'major':
  617. v.major += 1
  618. elif version_type == 'patch':
  619. v.patch += 1
  620. return unicode(v)
  621. def add_tag(repo_path, version):
  622. import git
  623. repo = git.Repo(repo_path)
  624. repo.index.add(['config.json'])
  625. repo.index.commit('bumped to version {}'.format(version))
  626. repo.create_tag('v' + version, repo.head)
  627. def update_framework_requirement(version):
  628. with open('app/config.json') as f:
  629. config = json.load(f)
  630. config['requires_framework_version'] = '==' + version
  631. with open('app/config.json', 'w') as f:
  632. json.dump(config, f, indent=1, sort_keys=True)
  633. validate('lib/')
  634. validate('app/')
  635. if repo == 'app':
  636. with open('app/config.json') as f:
  637. config = json.load(f)
  638. new_version = bump_version(config['app_version'], bump_type)
  639. config['app_version'] = new_version
  640. with open('app/config.json', 'w') as f:
  641. json.dump(config, f, indent=1, sort_keys=True)
  642. add_tag('app/', new_version)
  643. elif repo == 'lib':
  644. with open('lib/config.json') as f:
  645. config = json.load(f)
  646. new_version = bump_version(config['framework_version'], bump_type)
  647. config['framework_version'] = new_version
  648. with open('lib/config.json', 'w') as f:
  649. json.dump(config, f, indent=1, sort_keys=True)
  650. add_tag('lib/', new_version)
  651. update_framework_requirement(new_version)
  652. bump('app', bump_type)
  653. if __name__=="__main__":
  654. main()