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