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 години
преди 13 години
преди 11 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #!/usr/bin/env python
  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. webnotes.destroy()
  35. return out
  36. def get_function(args):
  37. for fn, val in args.items():
  38. if (val or isinstance(val, list)) and globals().get(fn):
  39. return fn
  40. def get_sites():
  41. import os
  42. import conf
  43. return [site for site in os.listdir(conf.sites_dir)
  44. if not os.path.islink(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. def setup_utilities(parser):
  76. # update
  77. parser.add_argument("-u", "--update", nargs="*", metavar=("REMOTE", "BRANCH"),
  78. help="Perform git pull, run patches, sync schema and rebuild files/translations")
  79. parser.add_argument("--patch", nargs=1, metavar="PATCH-MODULE",
  80. help="Run a particular patch [-f]")
  81. parser.add_argument("-l", "--latest", default=False, action="store_true",
  82. help="Run patches, sync schema and rebuild files/translations")
  83. parser.add_argument("--sync_all", default=False, action="store_true",
  84. help="Reload all doctypes, pages, etc. using txt files [-f]")
  85. parser.add_argument("--update_all_sites", nargs="*", metavar=("REMOTE", "BRANCH"),
  86. help="Perform git pull, run patches, sync schema and rebuild files/translations")
  87. parser.add_argument("--reload_doc", nargs=3,
  88. metavar=('"MODULE"', '"DOCTYPE"', '"DOCNAME"'))
  89. # build
  90. parser.add_argument("-b", "--build", default=False, action="store_true",
  91. help="Minify + concatenate JS and CSS files, build translations")
  92. parser.add_argument("-w", "--watch", default=False, action="store_true",
  93. help="Watch and concatenate JS and CSS files as and when they change")
  94. # misc
  95. parser.add_argument("--backup", default=False, action="store_true",
  96. help="Take backup of database in backup folder [--with_files]")
  97. parser.add_argument("--with_files", default=False, action="store_true",
  98. help="Also take backup of files")
  99. parser.add_argument("--docs", default=False, action="store_true",
  100. help="Build docs")
  101. parser.add_argument("--domain", nargs="*",
  102. help="Get or set domain in Website Settings")
  103. parser.add_argument("--make_conf", nargs="*", metavar=("DB-NAME", "DB-PASSWORD"),
  104. help="Create new conf.py file")
  105. # clear
  106. parser.add_argument("--clear_web", default=False, action="store_true",
  107. help="Clear website cache")
  108. parser.add_argument("--clear_cache", default=False, action="store_true",
  109. help="Clear cache, doctype cache and defaults")
  110. parser.add_argument("--reset_perms", default=False, action="store_true",
  111. help="Reset permissions for all doctypes")
  112. # scheduler
  113. parser.add_argument("--run_scheduler", default=False, action="store_true",
  114. help="Trigger scheduler")
  115. parser.add_argument("--run_scheduler_event", nargs=1,
  116. metavar="all | daily | weekly | monthly",
  117. help="Run a scheduler event")
  118. # replace
  119. parser.add_argument("--replace", nargs=3,
  120. metavar=("SEARCH-REGEX", "REPLACE-BY", "FILE-EXTN"),
  121. help="Multi-file search-replace [-f]")
  122. # import/export
  123. parser.add_argument("--export_doc", nargs=2, metavar=('"DOCTYPE"', '"DOCNAME"'))
  124. parser.add_argument("--export_doclist", nargs=3, metavar=("DOCTYPE", "NAME", "PATH"),
  125. help="""Export doclist as json to the given path, use '-' as name for Singles.""")
  126. parser.add_argument("--export_csv", nargs=2, metavar=("DOCTYPE", "PATH"),
  127. help="""Dump DocType as csv""")
  128. parser.add_argument("--import_doclist", nargs=1, metavar="PATH",
  129. help="""Import (insert/update) doclist. If the argument is a directory, all files ending with .json are imported""")
  130. def setup_git(parser):
  131. parser.add_argument("--pull", nargs="*", metavar=("REMOTE", "BRANCH"),
  132. help="Run git pull for both repositories")
  133. parser.add_argument("-p", "--push", nargs="*", metavar=("REMOTE", "BRANCH"),
  134. help="Run git push for both repositories")
  135. parser.add_argument("--status", default=False, action="store_true",
  136. help="Run git status for both repositories")
  137. parser.add_argument("--commit", nargs=1, metavar="COMMIT-MSG",
  138. help="Run git commit COMMIT-MSG for both repositories")
  139. parser.add_argument("--checkout", nargs=1, metavar="BRANCH",
  140. help="Run git checkout BRANCH for both repositories")
  141. parser.add_argument("--git", nargs="*", metavar="OPTIONS",
  142. help="Run git command for both repositories")
  143. def setup_translation(parser):
  144. parser.add_argument("--build_message_files", default=False, action="store_true",
  145. help="Build message files for translation")
  146. parser.add_argument("--export_messages", nargs=2, metavar=("LANG-CODE", "FILENAME"),
  147. help="""Export all messages for a language to translation in a csv file.
  148. Example, lib/wnf.py --export_messages hi hindi.csv""")
  149. parser.add_argument("--import_messages", nargs=2, metavar=("LANG-CODE", "FILENAME"),
  150. help="""Import messages for a language and make language files.
  151. Example, lib/wnf.py --import_messages hi hindi.csv""")
  152. parser.add_argument("--google_translate", nargs=3,
  153. metavar=("LANG-CODE", "INFILE", "OUTFILE"),
  154. help="Auto translate using Google Translate API")
  155. parser.add_argument("--translate", nargs=1, metavar="LANG-CODE",
  156. help="""Rebuild translation for the given langauge and
  157. use Google Translate to tranlate untranslated messages. use "all" """)
  158. # methods
  159. # install
  160. @cmd
  161. def install(db_name, source_sql=None, site=None, verbose=True, force=False, root_password=None):
  162. from webnotes.install_lib.install import Installer
  163. inst = Installer('root', db_name=db_name, site=site, root_password=root_password)
  164. inst.install(db_name, source_sql=source_sql, verbose=verbose, force=force)
  165. @cmd
  166. def reinstall(site=None, verbose=True):
  167. webnotes.init(site=site)
  168. install(webnotes.conf.db_name, site=site, verbose=verbose, force=True)
  169. @cmd
  170. def restore(db_name, source_sql, site=None, verbose=True, force=False):
  171. install(db_name, source_sql, site=site, verbose=verbose, force=force)
  172. @cmd
  173. def install_fixtures(site=None):
  174. webnotes.init(site=site)
  175. from webnotes.install_lib.install import install_fixtures
  176. install_fixtures()
  177. @cmd
  178. def make_demo(site=None):
  179. import utilities.demo.make_demo
  180. webnotes.init(site=site)
  181. utilities.demo.make_demo.make()
  182. @cmd
  183. def make_demo_fresh(site=None):
  184. import utilities.demo.make_demo
  185. webnotes.init(site=site)
  186. utilities.demo.make_demo.make(reset=True)
  187. # utilities
  188. @cmd
  189. def update(remote=None, branch=None, site=None):
  190. pull(remote=remote, branch=branch, site=site)
  191. # maybe there are new framework changes, any consequences?
  192. reload(webnotes)
  193. latest(site=site)
  194. @cmd
  195. def latest(site=None, verbose=True):
  196. import webnotes.modules.patch_handler
  197. import webnotes.model.sync
  198. webnotes.connect(site=site)
  199. try:
  200. # run patches
  201. webnotes.modules.patch_handler.log_list = []
  202. webnotes.modules.patch_handler.run_all()
  203. if verbose:
  204. print "\n".join(webnotes.modules.patch_handler.log_list)
  205. # sync
  206. webnotes.model.sync.sync_all()
  207. except webnotes.modules.patch_handler.PatchError, e:
  208. print "\n".join(webnotes.modules.patch_handler.log_list)
  209. raise e
  210. @cmd
  211. def sync_all(site=None, force=False):
  212. import webnotes.model.sync
  213. webnotes.connect(site=site)
  214. webnotes.model.sync.sync_all(force=force)
  215. @cmd
  216. def patch(patch_module, site=None, force=False):
  217. import webnotes.modules.patch_handler
  218. webnotes.connect(site=site)
  219. webnotes.modules.patch_handler.log_list = []
  220. webnotes.modules.patch_handler.run_single(patch_module, force=force)
  221. print "\n".join(webnotes.modules.patch_handler.log_list)
  222. @cmd
  223. def update_all_sites(remote=None, branch=None, verbose=True):
  224. pull(remote, branch)
  225. build()
  226. for site in get_sites():
  227. latest(site=site, verbose=verbose)
  228. @cmd
  229. def reload_doc(module, doctype, docname, site=None, force=False):
  230. webnotes.connect(site=site)
  231. webnotes.reload_doc(module, doctype, docname, force=force)
  232. @cmd
  233. def build():
  234. import webnotes.build
  235. webnotes.build.bundle(False)
  236. @cmd
  237. def watch():
  238. import webnotes.build
  239. webnotes.build.watch(True)
  240. @cmd
  241. def backup(site=None, with_files=False):
  242. from webnotes.utils.backups import scheduled_backup
  243. webnotes.connect(site=site)
  244. scheduled_backup(ignore_files=not with_files)
  245. @cmd
  246. def docs():
  247. from core.doctype.documentation_tool.documentation_tool import write_static
  248. write_static()
  249. @cmd
  250. def domain(host_url=None, site=None):
  251. webnotes.connect(site=site)
  252. if host_url:
  253. webnotes.conn.set_value("Website Settings", None, "subdomain", host_url)
  254. webnotes.conn.commit()
  255. else:
  256. print webnotes.conn.get_value("Website Settings", None, "subdomain")
  257. @cmd
  258. def make_conf(db_name=None, db_password=None, site=None, site_config=None):
  259. from webnotes.install_lib.install import make_conf
  260. make_conf(db_name=db_name, db_password=db_password, site=site, site_config=site_config)
  261. # clear
  262. @cmd
  263. def clear_cache(site=None):
  264. import webnotes.sessions
  265. webnotes.connect(site=site)
  266. webnotes.sessions.clear_cache()
  267. @cmd
  268. def clear_web(site=None):
  269. import webnotes.webutils
  270. webnotes.connect(site=site)
  271. webnotes.webutils.clear_cache()
  272. @cmd
  273. def reset_perms(site=None):
  274. webnotes.connect(site=site)
  275. for d in webnotes.conn.sql_list("""select name from `tabDocType`
  276. where ifnull(istable, 0)=0 and ifnull(custom, 0)=0"""):
  277. webnotes.clear_cache(doctype=d)
  278. webnotes.reset_perms(d)
  279. # scheduler
  280. @cmd
  281. def run_scheduler(site=None):
  282. import webnotes.utils.scheduler
  283. webnotes.connect(site=site)
  284. print webnotes.utils.scheduler.execute()
  285. @cmd
  286. def run_scheduler_event(event, site=None):
  287. import webnotes.utils.scheduler
  288. webnotes.connect(site=site)
  289. print webnotes.utils.scheduler.trigger("execute_" + event)
  290. # replace
  291. @cmd
  292. def replace(search_regex, replacement, extn, force=False):
  293. print search_regex, replacement, extn
  294. replace_code('.', search_regex, replacement, extn, force=force)
  295. # import/export
  296. @cmd
  297. def export_doc(doctype, docname, site=None):
  298. import webnotes.modules
  299. webnotes.connect(site=site)
  300. webnotes.modules.export_doc(doctype, docname)
  301. @cmd
  302. def export_doclist(doctype, name, path, site=None):
  303. from core.page.data_import_tool import data_import_tool
  304. webnotes.connect(site=site)
  305. data_import_tool.export_json(doctype, name, path)
  306. @cmd
  307. def export_csv(doctype, path, site=None):
  308. from core.page.data_import_tool import data_import_tool
  309. webnotes.connect(site=site)
  310. data_import_tool.export_csv(doctype, path)
  311. @cmd
  312. def import_doclist(path, site=None):
  313. from core.page.data_import_tool import data_import_tool
  314. webnotes.connect(site=site)
  315. data_import_tool.import_doclist(path)
  316. # translation
  317. @cmd
  318. def build_message_files(site=None):
  319. import webnotes.translate
  320. webnotes.connect(site=site)
  321. webnotes.translate.build_message_files()
  322. @cmd
  323. def export_messages(lang, outfile, site=None):
  324. import webnotes.translate
  325. webnotes.connect(site=site)
  326. webnotes.translate.export_messages(lang, outfile)
  327. @cmd
  328. def import_messages(lang, infile, site=None):
  329. import webnotes.translate
  330. webnotes.connect(site=site)
  331. webnotes.translate.import_messages(lang, infile)
  332. @cmd
  333. def google_translate(lang, infile, outfile, site=None):
  334. import webnotes.translate
  335. webnotes.connect(site=site)
  336. webnotes.translate.google_translate(lang, infile, outfile)
  337. @cmd
  338. def translate(lang, site=None):
  339. import webnotes.translate
  340. webnotes.connect(site=site)
  341. webnotes.translate.translate(lang)
  342. # git
  343. @cmd
  344. def git(param):
  345. if isinstance(param, (list, tuple)):
  346. param = " ".join(param)
  347. import os
  348. os.system("""cd lib && git %s""" % param)
  349. os.system("""cd app && git %s""" % param)
  350. def get_remote_and_branch(remote=None, branch=None):
  351. if not (remote and branch):
  352. webnotes.init()
  353. if not webnotes.conf.branch:
  354. raise Exception("Please specify remote and branch")
  355. remote = remote or "origin"
  356. branch = branch or webnotes.conf.branch
  357. return remote, branch
  358. @cmd
  359. def pull(remote=None, branch=None):
  360. remote, branch = get_remote_and_branch(remote, branch)
  361. git(("pull", remote, branch))
  362. @cmd
  363. def push(remote=None, branch=None):
  364. remote, branch = get_remote_and_branch(remote, branch)
  365. git(("push", remote, branch))
  366. @cmd
  367. def status():
  368. git("status")
  369. @cmd
  370. def commit(message):
  371. git("""commit -a -m "%s" """ % message.replace('"', '\"'))
  372. @cmd
  373. def checkout(branch):
  374. git(("checkout", branch))
  375. def replace_code(start, txt1, txt2, extn, search=None, force=False):
  376. """replace all txt1 by txt2 in files with extension (extn)"""
  377. import webnotes.utils
  378. import os, re
  379. esc = webnotes.utils.make_esc('[]')
  380. if not search: search = esc(txt1)
  381. for wt in os.walk(start, followlinks=1):
  382. for fn in wt[2]:
  383. if fn.split('.')[-1]==extn:
  384. fpath = os.path.join(wt[0], fn)
  385. with open(fpath, 'r') as f:
  386. content = f.read()
  387. if re.search(search, content):
  388. res = search_replace_with_prompt(fpath, txt1, txt2, force)
  389. if res == 'skip':
  390. return 'skip'
  391. def search_replace_with_prompt(fpath, txt1, txt2, force=False):
  392. """ Search and replace all txt1 by txt2 in the file with confirmation"""
  393. from termcolor import colored
  394. with open(fpath, 'r') as f:
  395. content = f.readlines()
  396. tmp = []
  397. for c in content:
  398. if c.find(txt1) != -1:
  399. print fpath
  400. print colored(txt1, 'red').join(c[:-1].split(txt1))
  401. a = ''
  402. if force:
  403. c = c.replace(txt1, txt2)
  404. else:
  405. while a.lower() not in ['y', 'n', 'skip']:
  406. a = raw_input('Do you want to Change [y/n/skip]?')
  407. if a.lower() == 'y':
  408. c = c.replace(txt1, txt2)
  409. elif a.lower() == 'skip':
  410. return 'skip'
  411. tmp.append(c)
  412. with open(fpath, 'w') as f:
  413. f.write(''.join(tmp))
  414. print colored('Updated', 'green')
  415. if __name__=="__main__":
  416. main()