Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
13 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
11 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  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("--clear_cache", default=False, action="store_true",
  162. help="Clear cache, doctype cache and defaults")
  163. parser.add_argument("--reset_perms", default=False, action="store_true",
  164. help="Reset permissions for all doctypes")
  165. # scheduler
  166. parser.add_argument("--run_scheduler", default=False, action="store_true",
  167. help="Trigger scheduler")
  168. parser.add_argument("--run_scheduler_event", nargs=1,
  169. metavar="all | daily | weekly | monthly",
  170. help="Run a scheduler event")
  171. # replace
  172. parser.add_argument("--replace", nargs=3,
  173. metavar=("SEARCH-REGEX", "REPLACE-BY", "FILE-EXTN"),
  174. help="Multi-file search-replace [-f]")
  175. # import/export
  176. parser.add_argument("--export_doc", nargs=2, metavar=('"DOCTYPE"', '"DOCNAME"'))
  177. parser.add_argument("--export_doclist", nargs=3, metavar=("DOCTYPE", "NAME", "PATH"),
  178. help="""Export doclist as json to the given path, use '-' as name for Singles.""")
  179. parser.add_argument("--export_csv", nargs=2, metavar=("DOCTYPE", "PATH"),
  180. help="""Dump DocType as csv""")
  181. parser.add_argument("--import_doclist", nargs=1, metavar="PATH",
  182. help="""Import (insert/update) doclist. If the argument is a directory, all files ending with .json are imported""")
  183. def setup_translation(parser):
  184. parser.add_argument("--build_message_files", default=False, action="store_true",
  185. help="Build message files for translation.")
  186. parser.add_argument("--get_untranslated", nargs=2, metavar=("LANG-CODE", "TARGET-FILE-PATH"),
  187. help="""Get untranslated strings for lang.""")
  188. parser.add_argument("--update_translations", nargs=3,
  189. metavar=("LANG-CODE", "UNTRANSLATED-FILE-PATH", "TRANSLATED-FILE-PATH"),
  190. help="""Update translated strings.""")
  191. # methods
  192. @cmd
  193. def make_app():
  194. from webnotes.utils.boilerplate import make_boilerplate
  195. make_boilerplate()
  196. @cmd
  197. def use():
  198. with open("currentsite.txt", "w") as sitefile:
  199. sitefile.write(webnotes.local.site)
  200. # install
  201. @cmd
  202. def install(db_name, root_login="root", root_password=None, source_sql=None,
  203. admin_password = 'admin', verbose=True, force=False, site_config=None, reinstall=False):
  204. print db_name, source_sql
  205. from webnotes.installer import install_db, install_app, make_site_dirs
  206. install_db(root_login=root_login, root_password=root_password, db_name=db_name, source_sql=source_sql,
  207. admin_password = admin_password, verbose=verbose, force=force, site_config=site_config, reinstall=reinstall)
  208. make_site_dirs()
  209. install_app("webnotes", verbose=verbose)
  210. webnotes.destroy()
  211. @cmd
  212. def install_app(app_name, verbose=False):
  213. from webnotes.installer import install_app
  214. webnotes.connect()
  215. install_app(app_name, verbose=verbose)
  216. webnotes.destroy()
  217. @cmd
  218. def reinstall(verbose=True):
  219. install(db_name=webnotes.conf.db_name, verbose=verbose, force=True, reinstall=True)
  220. @cmd
  221. def restore(db_name, source_sql, verbose=True, force=False):
  222. install(db_name, source_sql=source_sql, verbose=verbose, force=force)
  223. @cmd
  224. def install_fixtures():
  225. from webnotes.install_lib.install import install_fixtures
  226. install_fixtures()
  227. webnotes.destroy()
  228. @cmd
  229. def add_system_manager(email, first_name=None, last_name=None):
  230. webnotes.connect()
  231. webnotes.profile.add_system_manager(email, first_name, last_name)
  232. webnotes.conn.commit()
  233. webnotes.destroy()
  234. # utilities
  235. @cmd
  236. def update(remote=None, branch=None, reload_gunicorn=False):
  237. pull(remote=remote, branch=branch)
  238. # maybe there are new framework changes, any consequences?
  239. reload(webnotes)
  240. build()
  241. latest()
  242. if reload_gunicorn:
  243. import subprocess
  244. subprocess.check_output("killall -HUP gunicorn".split())
  245. @cmd
  246. def latest(verbose=True):
  247. import webnotes.modules.patch_handler
  248. import webnotes.model.sync
  249. from webnotes.website import rebuild_config
  250. webnotes.connect()
  251. try:
  252. # run patches
  253. webnotes.local.patch_log_list = []
  254. webnotes.modules.patch_handler.run_all()
  255. if verbose:
  256. print "\n".join(webnotes.local.patch_log_list)
  257. # sync
  258. webnotes.model.sync.sync_all()
  259. # build website config if any changes in templates etc.
  260. rebuild_config()
  261. except webnotes.modules.patch_handler.PatchError, e:
  262. print "\n".join(webnotes.local.patch_log_list)
  263. raise
  264. finally:
  265. webnotes.destroy()
  266. @cmd
  267. def sync_all(force=False):
  268. import webnotes.model.sync
  269. webnotes.connect()
  270. webnotes.model.sync.sync_all(force=force)
  271. webnotes.destroy()
  272. @cmd
  273. def patch(patch_module, force=False):
  274. import webnotes.modules.patch_handler
  275. webnotes.connect()
  276. webnotes.local.patch_log_list = []
  277. webnotes.modules.patch_handler.run_single(patch_module, force=force)
  278. print "\n".join(webnotes.local.patch_log_list)
  279. webnotes.destroy()
  280. @cmd
  281. def update_all_sites(remote=None, branch=None, verbose=True):
  282. pull(remote, branch)
  283. # maybe there are new framework changes, any consequences?
  284. reload(webnotes)
  285. build()
  286. for site in get_sites():
  287. webnotes.init(site)
  288. latest(verbose=verbose)
  289. @cmd
  290. def reload_doc(module, doctype, docname, force=False):
  291. webnotes.connect()
  292. webnotes.reload_doc(module, doctype, docname, force=force)
  293. webnotes.conn.commit()
  294. webnotes.destroy()
  295. @cmd
  296. def build():
  297. import webnotes.build
  298. import webnotes
  299. webnotes.build.bundle(False)
  300. @cmd
  301. def watch():
  302. import webnotes.build
  303. webnotes.build.watch(True)
  304. @cmd
  305. def backup(with_files=False, verbose=True, backup_path_db=None, backup_path_files=None):
  306. from webnotes.utils.backups import scheduled_backup
  307. webnotes.connect()
  308. odb = scheduled_backup(ignore_files=not with_files, backup_path_db=backup_path_db, backup_path_files=backup_path_files)
  309. if verbose:
  310. from webnotes.utils import now
  311. print "database backup taken -", odb.backup_path_db, "- on", now()
  312. if with_files:
  313. print "files backup taken -", odb.backup_path_files, "- on", now()
  314. webnotes.destroy()
  315. return odb
  316. @cmd
  317. def move(dest_dir=None):
  318. import os
  319. if not dest_dir:
  320. raise Exception, "--dest_dir is required for --move"
  321. if not os.path.isdir(dest_dir):
  322. raise Exception, "destination is not a directory or does not exist"
  323. old_path = webnotes.utils.get_site()
  324. new_path = os.path.join(dest_dir, site)
  325. # check if site dump of same name already exists
  326. site_dump_exists = True
  327. count = 0
  328. while site_dump_exists:
  329. final_new_path = new_path + (count and str(count) or "")
  330. site_dump_exists = os.path.exists(final_new_path)
  331. count = int(count or 0) + 1
  332. os.rename(old_path, final_new_path)
  333. webnotes.destroy()
  334. return os.path.basename(final_new_path)
  335. @cmd
  336. def domain(host_url=None):
  337. webnotes.connect()
  338. if host_url:
  339. webnotes.conn.set_value("Website Settings", None, "subdomain", host_url)
  340. webnotes.conn.commit()
  341. else:
  342. print webnotes.conn.get_value("Website Settings", None, "subdomain")
  343. webnotes.destroy()
  344. @cmd
  345. def make_conf(db_name=None, db_password=None, site_config=None):
  346. from webnotes.install_lib.install import make_conf
  347. make_conf(db_name=db_name, db_password=db_password, site_config=site_config)
  348. @cmd
  349. def make_custom_server_script(doctype):
  350. from webnotes.core.doctype.custom_script.custom_script import make_custom_server_script_file
  351. webnotes.connect()
  352. make_custom_server_script_file(doctype)
  353. webnotes.destroy()
  354. # clear
  355. @cmd
  356. def clear_cache():
  357. import webnotes.sessions
  358. webnotes.connect()
  359. webnotes.clear_cache()
  360. webnotes.destroy()
  361. @cmd
  362. def clear_web():
  363. import webnotes.webutils
  364. webnotes.connect()
  365. webnotes.webutils.clear_cache()
  366. webnotes.destroy()
  367. @cmd
  368. def build_sitemap():
  369. from webnotes.website import rebuild_config
  370. webnotes.connect()
  371. rebuild_config()
  372. webnotes.destroy()
  373. @cmd
  374. def reset_perms():
  375. webnotes.connect()
  376. for d in webnotes.conn.sql_list("""select name from `tabDocType`
  377. where ifnull(istable, 0)=0 and ifnull(custom, 0)=0"""):
  378. webnotes.clear_cache(doctype=d)
  379. webnotes.reset_perms(d)
  380. webnotes.destroy()
  381. # scheduler
  382. @cmd
  383. def run_scheduler():
  384. from webnotes.utils.file_lock import create_lock, delete_lock
  385. import webnotes.utils.scheduler
  386. if create_lock('scheduler'):
  387. webnotes.connect()
  388. print webnotes.utils.scheduler.execute()
  389. delete_lock('scheduler')
  390. webnotes.destroy()
  391. @cmd
  392. def run_scheduler_event(event):
  393. import webnotes.utils.scheduler
  394. webnotes.connect()
  395. print webnotes.utils.scheduler.trigger(event)
  396. webnotes.destroy()
  397. # replace
  398. @cmd
  399. def replace(search_regex, replacement, extn, force=False):
  400. print search_regex, replacement, extn
  401. replace_code('.', search_regex, replacement, extn, force=force)
  402. # import/export
  403. @cmd
  404. def export_doc(doctype, docname):
  405. import webnotes.modules
  406. webnotes.connect()
  407. webnotes.modules.export_doc(doctype, docname)
  408. webnotes.destroy()
  409. @cmd
  410. def export_doclist(doctype, name, path):
  411. from webnotes.core.page.data_import_tool import data_import_tool
  412. webnotes.connect()
  413. data_import_tool.export_json(doctype, name, path)
  414. webnotes.destroy()
  415. @cmd
  416. def export_csv(doctype, path):
  417. from webnotes.core.page.data_import_tool import data_import_tool
  418. webnotes.connect()
  419. data_import_tool.export_csv(doctype, path)
  420. webnotes.destroy()
  421. @cmd
  422. def import_doclist(path, force=False):
  423. from webnotes.core.page.data_import_tool import data_import_tool
  424. webnotes.connect()
  425. data_import_tool.import_doclist(path, overwrite=force)
  426. webnotes.destroy()
  427. # translation
  428. @cmd
  429. def build_message_files():
  430. import webnotes.translate
  431. webnotes.connect()
  432. webnotes.translate.rebuild_all_translation_files()
  433. webnotes.destroy()
  434. @cmd
  435. def get_untranslated(lang, untranslated_file):
  436. import webnotes.translate
  437. webnotes.connect()
  438. webnotes.translate.get_untranslated(lang, untranslated_file)
  439. webnotes.destroy()
  440. @cmd
  441. def update_translations(lang, untranslated_file, translated_file):
  442. import webnotes.translate
  443. webnotes.connect()
  444. webnotes.translate.update_translations(lang, untranslated_file, translated_file)
  445. webnotes.destroy()
  446. # git
  447. @cmd
  448. def git(param):
  449. if isinstance(param, (list, tuple)):
  450. param = " ".join(param)
  451. import os
  452. os.system("""cd lib && git %s""" % param)
  453. os.system("""cd app && git %s""" % param)
  454. def get_remote_and_branch(remote=None, branch=None):
  455. if not (remote and branch):
  456. if not webnotes.conf.branch:
  457. raise Exception("Please specify remote and branch")
  458. remote = remote or "origin"
  459. branch = branch or webnotes.conf.branch
  460. webnotes.destroy()
  461. return remote, branch
  462. @cmd
  463. def pull(remote=None, branch=None):
  464. remote, branch = get_remote_and_branch(remote, branch)
  465. git(("pull", remote, branch))
  466. @cmd
  467. def push(remote=None, branch=None):
  468. remote, branch = get_remote_and_branch(remote, branch)
  469. git(("push", remote, branch))
  470. @cmd
  471. def status():
  472. git("status")
  473. @cmd
  474. def commit(message):
  475. git("""commit -a -m "%s" """ % message.replace('"', '\"'))
  476. @cmd
  477. def checkout(branch):
  478. git(("checkout", branch))
  479. @cmd
  480. def set_admin_password(admin_password):
  481. import webnotes
  482. webnotes.connect()
  483. webnotes.conn.sql("""update __Auth set `password`=password(%s)
  484. where user='Administrator'""", (admin_password,))
  485. webnotes.conn.commit()
  486. webnotes.destroy()
  487. @cmd
  488. def mysql():
  489. import webnotes
  490. import commands, os
  491. msq = commands.getoutput('which mysql')
  492. 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"])
  493. webnotes.destroy()
  494. @cmd
  495. def python(site):
  496. import webnotes
  497. import commands, os
  498. python = commands.getoutput('which python')
  499. if site:
  500. os.environ["site"] = site
  501. os.environ["PYTHONSTARTUP"] = os.path.join(os.path.dirname(webnotes.__file__), "pythonrc.py")
  502. os.execv(python, [python])
  503. webnotes.destroy()
  504. @cmd
  505. def ipython():
  506. import webnotes
  507. webnotes.connect()
  508. import IPython
  509. IPython.embed()
  510. @cmd
  511. def smtp_debug_server():
  512. import commands, os
  513. python = commands.getoutput('which python')
  514. os.execv(python, [python, '-m', "smtpd", "-n", "-c", "DebuggingServer", "localhost:25"])
  515. @cmd
  516. def run_tests(app=None, module=None, doctype=None, verbose=False):
  517. import webnotes.test_runner
  518. ret = webnotes.test_runner.main(app and app[0], module and module[0], doctype and doctype[0], verbose)
  519. if len(ret.failures) > 0 or len(ret.errors) > 0:
  520. exit(1)
  521. @cmd
  522. def serve(port=8000, profile=False):
  523. import webnotes.app
  524. webnotes.app.serve(port=port, profile=profile, site=webnotes.local.site)
  525. @cmd
  526. def request(args):
  527. import webnotes.handler
  528. webnotes.connect()
  529. webnotes.form_dict = webnotes._dict([a.split("=") for a in args.split("&")])
  530. webnotes.handler.execute_cmd(webnotes.form_dict.cmd)
  531. print webnotes.response
  532. webnotes.destroy()
  533. @cmd
  534. def flush_memcache():
  535. webnotes.cache().flush_all()
  536. def replace_code(start, txt1, txt2, extn, search=None, force=False):
  537. """replace all txt1 by txt2 in files with extension (extn)"""
  538. import webnotes.utils
  539. import os, re
  540. esc = webnotes.utils.make_esc('[]')
  541. if not search: search = esc(txt1)
  542. for wt in os.walk(start, followlinks=1):
  543. for fn in wt[2]:
  544. if fn.split('.')[-1]==extn:
  545. fpath = os.path.join(wt[0], fn)
  546. with open(fpath, 'r') as f:
  547. content = f.read()
  548. if re.search(search, content):
  549. res = search_replace_with_prompt(fpath, txt1, txt2, force)
  550. if res == 'skip':
  551. return 'skip'
  552. def search_replace_with_prompt(fpath, txt1, txt2, force=False):
  553. """ Search and replace all txt1 by txt2 in the file with confirmation"""
  554. from termcolor import colored
  555. with open(fpath, 'r') as f:
  556. content = f.readlines()
  557. tmp = []
  558. for c in content:
  559. if c.find(txt1) != -1:
  560. print fpath
  561. print colored(txt1, 'red').join(c[:-1].split(txt1))
  562. a = ''
  563. if force:
  564. c = c.replace(txt1, txt2)
  565. else:
  566. while a.lower() not in ['y', 'n', 'skip']:
  567. a = raw_input('Do you want to Change [y/n/skip]?')
  568. if a.lower() == 'y':
  569. c = c.replace(txt1, txt2)
  570. elif a.lower() == 'skip':
  571. return 'skip'
  572. tmp.append(c)
  573. with open(fpath, 'w') as f:
  574. f.write(''.join(tmp))
  575. print colored('Updated', 'green')
  576. @cmd
  577. def get_site_status(verbose=False):
  578. import webnotes
  579. import webnotes.utils
  580. from webnotes.profile import get_system_managers
  581. from webnotes.core.doctype.profile.profile import get_total_users, get_active_users, \
  582. get_website_users, get_active_website_users
  583. import json
  584. webnotes.connect()
  585. ret = {
  586. 'last_backup_on': webnotes.local.conf.last_backup_on,
  587. 'active_users': get_active_users(),
  588. 'total_users': get_total_users(),
  589. 'active_website_users': get_active_website_users(),
  590. 'website_users': get_website_users(),
  591. 'system_managers': "\n".join(get_system_managers()),
  592. 'default_company': webnotes.conn.get_default("company"),
  593. 'disk_usage': webnotes.utils.get_disk_usage(),
  594. 'working_directory': webnotes.local.site_path
  595. }
  596. # country, timezone, industry
  597. control_panel_details = webnotes.conn.get_value("Control Panel", "Control Panel",
  598. ["country", "time_zone", "industry"], as_dict=True)
  599. if control_panel_details:
  600. ret.update(control_panel_details)
  601. # basic usage/progress analytics
  602. for doctype in ("Company", "Customer", "Item", "Quotation", "Sales Invoice",
  603. "Journal Voucher", "Stock Ledger Entry"):
  604. key = doctype.lower().replace(" ", "_") + "_exists"
  605. ret[key] = 1 if webnotes.conn.count(doctype) else 0
  606. webnotes.destroy()
  607. if verbose:
  608. print json.dumps(ret, indent=1, sort_keys=True)
  609. return ret
  610. @cmd
  611. def update_site_config(site_config, verbose=False):
  612. import json
  613. if isinstance(site_config, basestring):
  614. site_config = json.loads(site_config)
  615. config = webnotes.get_site_config()
  616. config.update(site_config)
  617. site_config_path = os.path.join(webnotes.local.site_path, "site_config.json")
  618. with open(site_config_path, "w") as f:
  619. json.dump(config, f, indent=1, sort_keys=True)
  620. webnotes.destroy()
  621. @cmd
  622. def bump(repo, bump_type):
  623. import json
  624. assert repo in ['lib', 'app']
  625. assert bump_type in ['minor', 'major', 'patch']
  626. def validate(repo_path):
  627. import git
  628. repo = git.Repo(repo_path)
  629. if repo.active_branch != 'master':
  630. raise Exception, "Current branch not master in {}".format(repo_path)
  631. def bump_version(version, version_type):
  632. import semantic_version
  633. v = semantic_version.Version(version)
  634. if version_type == 'minor':
  635. v.minor += 1
  636. elif version_type == 'major':
  637. v.major += 1
  638. elif version_type == 'patch':
  639. v.patch += 1
  640. return unicode(v)
  641. def add_tag(repo_path, version):
  642. import git
  643. repo = git.Repo(repo_path)
  644. repo.index.add(['config.json'])
  645. repo.index.commit('bumped to version {}'.format(version))
  646. repo.create_tag('v' + version, repo.head)
  647. def update_framework_requirement(version):
  648. with open('app/config.json') as f:
  649. config = json.load(f)
  650. config['requires_framework_version'] = '==' + version
  651. with open('app/config.json', 'w') as f:
  652. json.dump(config, f, indent=1, sort_keys=True)
  653. validate('lib/')
  654. validate('app/')
  655. if repo == 'app':
  656. with open('app/config.json') as f:
  657. config = json.load(f)
  658. new_version = bump_version(config['app_version'], bump_type)
  659. config['app_version'] = new_version
  660. with open('app/config.json', 'w') as f:
  661. json.dump(config, f, indent=1, sort_keys=True)
  662. add_tag('app/', new_version)
  663. elif repo == 'lib':
  664. with open('lib/config.json') as f:
  665. config = json.load(f)
  666. new_version = bump_version(config['framework_version'], bump_type)
  667. config['framework_version'] = new_version
  668. with open('lib/config.json', 'w') as f:
  669. json.dump(config, f, indent=1, sort_keys=True)
  670. add_tag('lib/', new_version)
  671. update_framework_requirement(new_version)
  672. bump('app', bump_type)
  673. if __name__=="__main__":
  674. main()