25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

420 lines
13 KiB

  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 run(fn, args):
  20. out = globals().get(fn)(args.get(fn), args)
  21. webnotes.destroy()
  22. return out
  23. def get_function(args):
  24. for fn, val in args.items():
  25. if (val or isinstance(val, list)) and globals().get(fn):
  26. return fn
  27. def get_sites():
  28. pass
  29. def setup_parser():
  30. import argparse
  31. parser = argparse.ArgumentParser(description="Run webnotes utility functions")
  32. setup_install(parser)
  33. setup_utilities(parser)
  34. setup_translation(parser)
  35. setup_git(parser)
  36. # common
  37. parser.add_argument("-f", "--force", default=False, action="store_true",
  38. help="Force execution where applicable (look for [-f] in help)")
  39. parser.add_argument("--site", nargs="?", metavar="SITE-NAME or all",
  40. help="Run for a particular site")
  41. return parser.parse_args()
  42. def setup_install(parser):
  43. parser.add_argument("--install", metavar="DB-NAME", nargs=1,
  44. help="Install a new app")
  45. parser.add_argument("--reinstall", default=False, action="store_true",
  46. help="Install a fresh app in db_name specified in conf.py")
  47. parser.add_argument("--restore", metavar=("DB-NAME", "SQL-FILE"), nargs=2,
  48. help="Restore from an sql file")
  49. parser.add_argument("--install_fixtures", default=False, action="store_true",
  50. help="(Re)Install install-fixtures from app/startup/install_fixtures")
  51. parser.add_argument("--make_demo", default=False, action="store_true",
  52. help="Install demo in demo_db_name specified in conf.py")
  53. parser.add_argument("--make_demo_fresh", default=False, action="store_true",
  54. help="(Re)Install demo in demo_db_name specified in conf.py")
  55. def setup_utilities(parser):
  56. # update
  57. parser.add_argument("-u", "--update", nargs="*", metavar=("REMOTE", "BRANCH"),
  58. help="Perform git pull, run patches, sync schema and rebuild files/translations")
  59. parser.add_argument("--patch", nargs=1, metavar="PATCH-MODULE",
  60. help="Run a particular patch [-f]")
  61. parser.add_argument("-l", "--latest", default=False, action="store_true",
  62. help="Run patches, sync schema and rebuild files/translations")
  63. parser.add_argument("--sync_all", default=False, action="store_true",
  64. help="Reload all doctypes, pages, etc. using txt files [-f]")
  65. parser.add_argument("--reload_doc", nargs=3,
  66. metavar=('"MODULE"', '"DOCTYPE"', '"DOCNAME"'))
  67. # build
  68. parser.add_argument("-b", "--build", default=False, action="store_true",
  69. help="Minify + concatenate JS and CSS files, build translations")
  70. parser.add_argument("-w", "--watch", default=False, action="store_true",
  71. help="Watch and concatenate JS and CSS files as and when they change")
  72. # misc
  73. parser.add_argument("--backup", default=False, action="store_true",
  74. help="Take backup of database in backup folder [--with_files]")
  75. parser.add_argument("--with_files", default=False, action="store_true",
  76. help="Also take backup of files")
  77. parser.add_argument("--docs", default=False, action="store_true",
  78. help="Build docs")
  79. parser.add_argument("--domain", nargs="*",
  80. help="Get or set domain in Website Settings")
  81. parser.add_argument("--make_conf", nargs="*", metavar=("DB-NAME", "DB-PASSWORD"),
  82. help="Create new conf.py file")
  83. # clear
  84. parser.add_argument("--clear_web", default=False, action="store_true",
  85. help="Clear website cache")
  86. parser.add_argument("--clear_cache", default=False, action="store_true",
  87. help="Clear cache, doctype cache and defaults")
  88. parser.add_argument("--reset_perms", default=False, action="store_true",
  89. help="Reset permissions for all doctypes")
  90. # scheduler
  91. parser.add_argument("--run_scheduler", default=False, action="store_true",
  92. help="Trigger scheduler")
  93. parser.add_argument("--run_scheduler_event", nargs=1,
  94. metavar="all | daily | weekly | monthly",
  95. help="Run a scheduler event")
  96. # replace
  97. parser.add_argument("--replace", nargs=3,
  98. metavar=("SEARCH-REGEX", "REPLACE-BY", "FILE-EXTN"),
  99. help="Multi-file search-replace [-f]")
  100. # import/export
  101. parser.add_argument("--export_doc", nargs=2, metavar=('"DOCTYPE"', '"DOCNAME"'))
  102. parser.add_argument("--export_doclist", nargs=3, metavar=("DOCTYPE", "NAME", "PATH"),
  103. help="""Export doclist as json to the given path, use '-' as name for Singles.""")
  104. parser.add_argument("--export_csv", nargs=2, metavar=("DOCTYPE", "PATH"),
  105. help="""Dump DocType as csv""")
  106. parser.add_argument("--import_doclist", nargs=1, metavar="PATH",
  107. help="""Import (insert/update) doclist. If the argument is a directory, all files ending with .json are imported""")
  108. def setup_git(parser):
  109. parser.add_argument("--pull", nargs="*", metavar=("REMOTE", "BRANCH"),
  110. help="Run git pull for both repositories")
  111. parser.add_argument("-p", "--push", nargs="*", metavar=("REMOTE", "BRANCH"),
  112. help="Run git push for both repositories")
  113. parser.add_argument("--status", default=False, action="store_true",
  114. help="Run git status for both repositories")
  115. parser.add_argument("--commit", nargs=1, metavar="COMMIT-MSG",
  116. help="Run git commit COMMIT-MSG for both repositories")
  117. parser.add_argument("--checkout", nargs=1, metavar="BRANCH",
  118. help="Run git checkout BRANCH for both repositories")
  119. parser.add_argument("--git", nargs="*", metavar="OPTIONS",
  120. help="Run git command for both repositories")
  121. def setup_translation(parser):
  122. parser.add_argument("--build_message_files", default=False, action="store_true",
  123. help="Build message files for translation")
  124. parser.add_argument("--export_messages", nargs=2, metavar=("LANG-CODE", "FILENAME"),
  125. help="""Export all messages for a language to translation in a csv file.
  126. Example, lib/wnf.py --export_messages hi hindi.csv""")
  127. parser.add_argument("--import_messages", nargs=2, metavar=("LANG-CODE", "FILENAME"),
  128. help="""Import messages for a language and make language files.
  129. Example, lib/wnf.py --import_messages hi hindi.csv""")
  130. parser.add_argument("--google_translate", nargs=3,
  131. metavar=("LANG-CODE", "INFILE", "OUTFILE"),
  132. help="Auto translate using Google Translate API")
  133. parser.add_argument("--translate", nargs=1, metavar="LANG-CODE",
  134. help="""Rebuild translation for the given langauge and
  135. use Google Translate to tranlate untranslated messages. use "all" """)
  136. # methods
  137. # install
  138. def _install(val, args):
  139. from webnotes.install_lib.install import Installer
  140. inst = Installer('root', db_name=val[0], site=args.site)
  141. inst.install(*val, verbose=1, force=args.force)
  142. def install(val, args):
  143. _install(val, args)
  144. # install
  145. def reinstall(val, args):
  146. webnotes.init(site=args.site)
  147. _install([webnotes.conf.db_name], args)
  148. def restore(val, args):
  149. _install(val, args)
  150. def install_fixtures(val, args):
  151. webnotes.init(site=args.site)
  152. from webnotes.install_lib.install import install_fixtures
  153. install_fixtures()
  154. def make_demo(val, args):
  155. import utilities.demo.make_demo
  156. webnotes.init(site=args.site)
  157. utilities.demo.make_demo.make()
  158. def make_demo_fresh(val, args):
  159. import utilities.demo.make_demo
  160. webnotes.init(site=args.site)
  161. utilities.demo.make_demo.make(reset=True)
  162. # utilities
  163. def update(val, args):
  164. pull(val, args)
  165. reload(webnotes)
  166. latest(val, args)
  167. def latest(val, args):
  168. import webnotes.modules.patch_handler
  169. import webnotes.model.sync
  170. webnotes.connect(site=args.site)
  171. # run patches
  172. webnotes.modules.patch_handler.log_list = []
  173. webnotes.modules.patch_handler.run_all()
  174. print "\n".join(webnotes.modules.patch_handler.log_list)
  175. # sync
  176. webnotes.model.sync.sync_all()
  177. # build
  178. build(val, args)
  179. def sync_all(val, args):
  180. import webnotes.model.sync
  181. webnotes.connect(site=args.site)
  182. webnotes.model.sync.sync_all(force=args.force)
  183. def patch(val, args):
  184. import webnotes.modules.patch_handler
  185. webnotes.connect(site=args.site)
  186. webnotes.modules.patch_handler.log_list = []
  187. webnotes.modules.patch_handler.run_single(val[0], force=args.force)
  188. print "\n".join(webnotes.modules.patch_handler.log_list)
  189. def reload_doc(val, args):
  190. webnotes.connect(site=args.site)
  191. webnotes.reload_doc(val[0], val[1], val[2], force=args.force)
  192. def build(val, args):
  193. import webnotes.build
  194. webnotes.build.bundle(False)
  195. def watch(val, args):
  196. import webnotes.build
  197. webnotes.build.watch(True)
  198. def backup(val, args):
  199. from webnotes.utils.backups import scheduled_backup
  200. webnotes.connect(site=args.site)
  201. scheduled_backup(ignore_files=not args.with_files)
  202. def docs(val, args):
  203. from core.doctype.documentation_tool.documentation_tool import write_static
  204. write_static()
  205. def domain(val, args):
  206. webnotes.connect(site=args.site)
  207. if val:
  208. webnotes.conn.set_value("Website Settings", None, "subdomain", val[0])
  209. webnotes.conn.commit()
  210. else:
  211. print webnotes.conn.get_value("Website Settings", None, "subdomain")
  212. def make_conf(val, args):
  213. from webnotes.install_lib.install import make_conf
  214. make_conf(*val, site=args.site)
  215. # clear
  216. def clear_cache(val, args):
  217. import webnotes.sessions
  218. webnotes.connect(site=args.site)
  219. webnotes.sessions.clear_cache()
  220. def clear_web(val, args):
  221. import webnotes.webutils
  222. webnotes.connect(site=args.site)
  223. webnotes.webutils.clear_cache()
  224. def reset_perms(val, args):
  225. webnotes.connect(site=args.site)
  226. for d in webnotes.conn.sql_list("""select name from `tabDocType`
  227. where ifnull(istable, 0)=0 and ifnull(custom, 0)=0"""):
  228. webnotes.clear_cache(doctype=d)
  229. webnotes.reset_perms(d)
  230. # scheduler
  231. def run_scheduler(val, args):
  232. import webnotes.utils.scheduler
  233. webnotes.connect(site=args.site)
  234. print webnotes.utils.scheduler.execute()
  235. def run_scheduler_event(val, args):
  236. import webnotes.utils.scheduler
  237. webnotes.connect(site=args.site)
  238. print webnotes.utils.scheduler.trigger("execute_" + val[0])
  239. # replace
  240. def replace(val, args):
  241. print val
  242. replace_code('.', *val, force=args.force)
  243. # import/export
  244. def export_doc(val, args):
  245. import webnotes.modules
  246. webnotes.connect(site=args.site)
  247. webnotes.modules.export_doc(*val)
  248. def export_doclist(val, args):
  249. from core.page.data_import_tool import data_import_tool
  250. webnotes.connect(site=args.site)
  251. data_import_tool.export_json(*val)
  252. def export_csv(val, args):
  253. from core.page.data_import_tool import data_import_tool
  254. webnotes.connect(site=args.site)
  255. data_import_tool.export_csv(*val)
  256. def import_doclist(val, args):
  257. from core.page.data_import_tool import data_import_tool
  258. webnotes.connect(site=args.site)
  259. data_import_tool.import_doclist(*val)
  260. # translation
  261. def build_message_files(val, args):
  262. import webnotes.translate
  263. webnotes.connect(site=args.site)
  264. webnotes.translate.build_message_files()
  265. def export_messages(val, args):
  266. import webnotes.translate
  267. webnotes.connect(site=args.site)
  268. webnotes.translate.export_messages(*val)
  269. def import_messages(val, args):
  270. import webnotes.translate
  271. webnotes.connect(site=args.site)
  272. webnotes.translate.import_messages(*val)
  273. def google_translate(val, args):
  274. import webnotes.translate
  275. webnotes.connect(site=args.site)
  276. webnotes.translate.google_translate(*val)
  277. def translate(val, args):
  278. import webnotes.translate
  279. webnotes.connect(site=args.site)
  280. webnotes.translate.translate(*val)
  281. # git
  282. def git(val, args=None):
  283. cmd = val
  284. if isinstance(val, (list, tuple)):
  285. cmd = " ".join(val)
  286. import os
  287. os.system("""cd lib && git %s""" % cmd)
  288. os.system("""cd app && git %s""" % cmd)
  289. def pull(val, args=None):
  290. if not val:
  291. webnotes.init(site=args.site)
  292. val = ("origin", webnotes.conf.branch or "master")
  293. git(("pull", val[0], val[1]))
  294. def push(val, args=None):
  295. if not val:
  296. webnotes.init(site=args.site)
  297. val = ("origin", webnotes.conf.branch or "master")
  298. git(("push", val[0], val[1]))
  299. def status(val, args=None):
  300. git("status")
  301. def commit(val, args=None):
  302. git("""commit -a -m "%s" """ % val[0].replace('"', '\"'))
  303. def checkout(val, args=None):
  304. git(("checkout", val[0]))
  305. def replace_code(start, txt1, txt2, extn, search=None, force=False):
  306. """replace all txt1 by txt2 in files with extension (extn)"""
  307. import webnotes.utils
  308. import os, re
  309. esc = webnotes.utils.make_esc('[]')
  310. if not search: search = esc(txt1)
  311. for wt in os.walk(start, followlinks=1):
  312. for fn in wt[2]:
  313. if fn.split('.')[-1]==extn:
  314. fpath = os.path.join(wt[0], fn)
  315. with open(fpath, 'r') as f:
  316. content = f.read()
  317. if re.search(search, content):
  318. res = search_replace_with_prompt(fpath, txt1, txt2, force)
  319. if res == 'skip':
  320. return 'skip'
  321. def search_replace_with_prompt(fpath, txt1, txt2, force=False):
  322. """ Search and replace all txt1 by txt2 in the file with confirmation"""
  323. from termcolor import colored
  324. with open(fpath, 'r') as f:
  325. content = f.readlines()
  326. tmp = []
  327. for c in content:
  328. if c.find(txt1) != -1:
  329. print fpath
  330. print colored(txt1, 'red').join(c[:-1].split(txt1))
  331. a = ''
  332. if force:
  333. c = c.replace(txt1, txt2)
  334. else:
  335. while a.lower() not in ['y', 'n', 'skip']:
  336. a = raw_input('Do you want to Change [y/n/skip]?')
  337. if a.lower() == 'y':
  338. c = c.replace(txt1, txt2)
  339. elif a.lower() == 'skip':
  340. return 'skip'
  341. tmp.append(c)
  342. with open(fpath, 'w') as f:
  343. f.write(''.join(tmp))
  344. print colored('Updated', 'green')
  345. if __name__=="__main__":
  346. main()