Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

824 linhas
25 KiB

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