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