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