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.

пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 12 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 12 година
пре 12 година
пре 13 година
пре 12 година
пре 12 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 12 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 12 година
пре 13 година
пре 13 година
пре 12 година
пре 12 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. #!/usr/bin/python
  2. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  3. #
  4. # MIT License (MIT)
  5. #
  6. # Permission is hereby granted, free of charge, to any person obtaining a
  7. # copy of this software and associated documentation files (the "Software"),
  8. # to deal in the Software without restriction, including without limitation
  9. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. # and/or sell copies of the Software, and to permit persons to whom the
  11. # Software is furnished to do so, subject to the following conditions:
  12. #
  13. # The above copyright notice and this permission notice shall be included in
  14. # all copies or substantial portions of the Software.
  15. #
  16. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  17. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  18. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  19. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  20. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  21. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. #
  23. from __future__ import unicode_literals
  24. import os, sys
  25. def replace_code(start, txt1, txt2, extn, search=None, force=False):
  26. """replace all txt1 by txt2 in files with extension (extn)"""
  27. import webnotes.utils
  28. import os, re
  29. esc = webnotes.utils.make_esc('[]')
  30. if not search: search = esc(txt1)
  31. for wt in os.walk(start, followlinks=1):
  32. for fn in wt[2]:
  33. if fn.split('.')[-1]==extn:
  34. fpath = os.path.join(wt[0], fn)
  35. if fpath != '/var/www/erpnext/erpnext/patches/jan_mar_2012/rename_dt.py': # temporary
  36. with open(fpath, 'r') as f:
  37. content = f.read()
  38. if re.search(search, content):
  39. res = search_replace_with_prompt(fpath, txt1, txt2, force)
  40. if res == 'skip':
  41. return 'skip'
  42. def search_replace_with_prompt(fpath, txt1, txt2, force=False):
  43. """ Search and replace all txt1 by txt2 in the file with confirmation"""
  44. from termcolor import colored
  45. with open(fpath, 'r') as f:
  46. content = f.readlines()
  47. tmp = []
  48. for c in content:
  49. if c.find(txt1) != -1:
  50. print fpath
  51. print colored(txt1, 'red').join(c[:-1].split(txt1))
  52. a = ''
  53. if force:
  54. c = c.replace(txt1, txt2)
  55. else:
  56. while a.lower() not in ['y', 'n', 'skip']:
  57. a = raw_input('Do you want to Change [y/n/skip]?')
  58. if a.lower() == 'y':
  59. c = c.replace(txt1, txt2)
  60. elif a.lower() == 'skip':
  61. return 'skip'
  62. tmp.append(c)
  63. with open(fpath, 'w') as f:
  64. f.write(''.join(tmp))
  65. print colored('Updated', 'green')
  66. def pull(remote, branch, build=False):
  67. os.system('cd lib && git pull %s %s' % (remote, branch))
  68. os.system('cd app && git pull %s %s' % (remote, branch))
  69. if build: rebuild()
  70. def rebuild():
  71. # build js / css
  72. from webnotes.utils import bundlejs
  73. bundlejs.bundle(False)
  74. def apply_latest_patches():
  75. import webnotes.modules.patch_handler
  76. webnotes.modules.patch_handler.run_all()
  77. print '\n'.join(webnotes.modules.patch_handler.log_list)
  78. def sync_all(force=0):
  79. import webnotes.model.sync
  80. webnotes.model.sync.sync_all(force)
  81. def update_erpnext(remote='origin', branch='master'):
  82. pull(remote, branch)
  83. patch_sync_build()
  84. def patch_sync_build():
  85. patch_sync()
  86. rebuild()
  87. def patch_sync():
  88. apply_latest_patches()
  89. import webnotes.modules.patch_handler
  90. for l in webnotes.modules.patch_handler.log_list:
  91. if "failed: STOPPED" in l:
  92. return
  93. sync_all()
  94. clear_cache()
  95. def clear_cache():
  96. import webnotes.sessions
  97. webnotes.sessions.clear_cache()
  98. def append_future_import():
  99. """appends from __future__ import unicode_literals to py files if necessary"""
  100. import os
  101. import conf
  102. conf_path = os.path.abspath(conf.__file__)
  103. if conf_path.endswith("pyc"):
  104. conf_path = conf_path[:-1]
  105. base_path = os.path.dirname(conf_path)
  106. for path, folders, files in os.walk(base_path):
  107. for f in files:
  108. if f.endswith('.py'):
  109. file_path = os.path.join(path, f)
  110. with open(file_path, 'r') as pyfile:
  111. content = pyfile.read()
  112. future_import = 'from __future__ import unicode_literals'
  113. if future_import in content: continue
  114. content = content.split('\n')
  115. idx = -1
  116. for c in content:
  117. idx += 1
  118. if c and not c.startswith('#'):
  119. break
  120. content.insert(idx, future_import)
  121. content = "\n".join(content)
  122. with open(file_path, 'w') as pyfile:
  123. pyfile.write(content)
  124. def setup_options():
  125. from optparse import OptionParser
  126. parser = OptionParser()
  127. parser.add_option("-d", "--db",
  128. dest="db_name",
  129. help="Apply the patches on given db")
  130. parser.add_option("--password",
  131. help="Password for given db", nargs=1)
  132. # build
  133. parser.add_option("-b", "--build", default=False, action="store_true",
  134. help="minify + concat js files")
  135. parser.add_option("-w", "--watch", default=False, action="store_true",
  136. help="watch and minify + concat js files, if necessary")
  137. parser.add_option("--no_compress", default=False, action="store_true",
  138. help="do not compress when building js bundle")
  139. parser.add_option("--no_cms", default=False, action="store_true",
  140. help="do not build wn-web.js and wn-css.js")
  141. parser.add_option("--build_web_cache", default=False, action="store_true",
  142. help="build web cache")
  143. parser.add_option("--clear_cache", default=False, action="store_true",
  144. help="clear cache")
  145. parser.add_option("--domain", metavar="DOMAIN",
  146. help="store domain in Website Settings", nargs=1)
  147. # git
  148. parser.add_option("--status", default=False, action="store_true",
  149. help="git status")
  150. parser.add_option("--git", nargs=1, default=False,
  151. metavar = "git options",
  152. help="run git with options in both repos")
  153. parser.add_option("--pull", nargs=2, default=False,
  154. metavar = "remote branch",
  155. help="git pull (both repos)")
  156. parser.add_option("--push", nargs=2, default=False,
  157. metavar = "remote branch",
  158. help="git push (both repos) [remote] [branch]")
  159. parser.add_option("--checkout", nargs=1, default=False,
  160. metavar = "branch",
  161. help="git checkout [branch]")
  162. parser.add_option("-l", "--latest",
  163. action="store_true", dest="run_latest", default=False,
  164. help="Apply the latest patches")
  165. # patch
  166. parser.add_option("-p", "--patch", nargs=1, dest="patch_list", metavar='patch_module',
  167. action="append",
  168. help="Apply patch")
  169. parser.add_option("-f", "--force",
  170. action="store_true", dest="force", default=False,
  171. help="Force Apply all patches specified using option -p or --patch")
  172. parser.add_option('--reload_doc', nargs=3, metavar = "module doctype docname",
  173. help="reload doc")
  174. parser.add_option('--export_doc', nargs=2, metavar = "doctype docname",
  175. help="export doc")
  176. # install
  177. parser.add_option('--install', nargs=2, metavar = "dbname source",
  178. help="install fresh db")
  179. # diff
  180. parser.add_option('--diff_ref_file', nargs=0, \
  181. help="Get missing database records and mismatch properties, with file as reference")
  182. parser.add_option('--diff_ref_db', nargs=0, \
  183. help="Get missing .txt files and mismatch properties, with database as reference")
  184. # scheduler
  185. parser.add_option('--run_scheduler', default=False, action="store_true",
  186. help="Trigger scheduler")
  187. parser.add_option('--run_scheduler_event', nargs=1, metavar="[all|daily|weekly|monthly]",
  188. help="Run scheduler event")
  189. # misc
  190. parser.add_option("--replace", nargs=3, default=False,
  191. metavar = "search replace_by extension",
  192. help="file search-replace")
  193. parser.add_option("--sync_all", help="Synchronize all DocTypes using txt files",
  194. nargs=0)
  195. parser.add_option("--sync", help="Synchronize given DocType using txt file",
  196. nargs=2, metavar="module doctype (use their folder names)")
  197. parser.add_option("--update", help="Pull, run latest patches and sync all",
  198. nargs=2, metavar="ORIGIN BRANCH")
  199. parser.add_option("--patch_sync_build", action="store_true", default=False,
  200. help="run latest patches, sync all and rebuild js css")
  201. parser.add_option("--patch_sync", action="store_true", default=False,
  202. help="run latest patches, sync all")
  203. parser.add_option("--cleanup_data", help="Cleanup test data", default=False,
  204. action="store_true")
  205. parser.add_option("--append_future_import", default=False, action="store_true",
  206. help="append from __future__ import unicode literals to py files")
  207. parser.add_option("--backup", help="Takes backup of database in backup folder",
  208. default=False, action="store_true")
  209. parser.add_option("--test", help="Run test", metavar="MODULE",
  210. nargs=1)
  211. return parser.parse_args()
  212. def run():
  213. sys.path.append('.')
  214. sys.path.append('lib')
  215. sys.path.append('app')
  216. (options, args) = setup_options()
  217. # build
  218. if options.build:
  219. from webnotes.utils import bundlejs
  220. if options.no_cms:
  221. cms_make = False
  222. else:
  223. cms_make = True
  224. bundlejs.bundle(options.no_compress, cms_make)
  225. return
  226. elif options.watch:
  227. from webnotes.utils import bundlejs
  228. bundlejs.watch(True)
  229. return
  230. # code replace
  231. elif options.replace:
  232. print options.replace
  233. replace_code('.', options.replace[0], options.replace[1], options.replace[2], force=options.force)
  234. return
  235. # git
  236. elif options.status:
  237. os.chdir('lib')
  238. os.system('git status')
  239. os.chdir('../app')
  240. os.system('git status')
  241. return
  242. elif options.git:
  243. os.chdir('lib')
  244. os.system('git %s' % options.git)
  245. os.chdir('../app')
  246. os.system('git %s' % options.git)
  247. return
  248. import webnotes
  249. import conf
  250. from webnotes.db import Database
  251. import webnotes.modules.patch_handler
  252. # connect
  253. if options.db_name is not None:
  254. if options.password:
  255. webnotes.connect(options.db_name, options.password)
  256. else:
  257. webnotes.connect(options.db_name)
  258. elif not any([options.install, options.pull]):
  259. webnotes.connect(conf.db_name)
  260. if options.pull:
  261. pull(options.pull[0], options.pull[1], build=True)
  262. elif options.push:
  263. os.chdir('lib')
  264. os.system('git push %s %s' % (options.push[0], options.push[1]))
  265. os.chdir('../app')
  266. os.system('git push %s %s' % (options.push[0], options.push[1]))
  267. elif options.checkout:
  268. os.chdir('lib')
  269. os.system('git checkout %s' % options.checkout)
  270. os.chdir('../app')
  271. os.system('git checkout %s' % options.checkout)
  272. # patch
  273. elif options.patch_list:
  274. # clear log
  275. webnotes.modules.patch_handler.log_list = []
  276. # run individual patches
  277. for patch in options.patch_list:
  278. webnotes.modules.patch_handler.run_single(\
  279. patchmodule = patch, force = options.force)
  280. print '\n'.join(webnotes.modules.patch_handler.log_list)
  281. # reload
  282. elif options.reload_doc:
  283. webnotes.modules.patch_handler.reload_doc(\
  284. {"module":options.reload_doc[0], "dt":options.reload_doc[1], "dn":options.reload_doc[2]})
  285. print '\n'.join(webnotes.modules.patch_handler.log_list)
  286. elif options.export_doc:
  287. from webnotes.modules import export_doc
  288. export_doc(options.export_doc[0], options.export_doc[1])
  289. # run all pending
  290. elif options.run_latest:
  291. apply_latest_patches()
  292. elif options.install:
  293. from webnotes.install_lib.install import Installer
  294. inst = Installer('root')
  295. inst.import_from_db(options.install[0], source_path=options.install[1], \
  296. password='admin', verbose = 1)
  297. elif options.diff_ref_file is not None:
  298. import webnotes.modules.diff
  299. webnotes.modules.diff.diff_ref_file()
  300. elif options.diff_ref_db is not None:
  301. import webnotes.modules.diff
  302. webnotes.modules.diff.diff_ref_db()
  303. elif options.run_scheduler:
  304. import webnotes.utils.scheduler
  305. print webnotes.utils.scheduler.execute()
  306. elif options.run_scheduler_event is not None:
  307. import webnotes.utils.scheduler
  308. print webnotes.utils.scheduler.trigger('execute_' + options.run_scheduler_event)
  309. elif options.sync_all is not None:
  310. sync_all(options.force or 0)
  311. elif options.sync is not None:
  312. import webnotes.model.sync
  313. webnotes.model.sync.sync(options.sync[0], options.sync[1], options.force or 0)
  314. elif options.update:
  315. update_erpnext(options.update[0], options.update[1])
  316. elif options.patch_sync_build:
  317. patch_sync_build()
  318. elif options.patch_sync:
  319. patch_sync()
  320. elif options.cleanup_data:
  321. from utilities import cleanup_data
  322. cleanup_data.run()
  323. elif options.domain:
  324. webnotes.conn.set_value('Website Settings', None, 'subdomain', options.domain)
  325. webnotes.conn.commit()
  326. print "Domain set to", options.domain
  327. elif options.build_web_cache:
  328. # build wn-web.js and wn-web.css
  329. from website.helpers.make_web_include_files import make
  330. make()
  331. import website.utils
  332. website.utils.clear_cache()
  333. elif options.clear_cache:
  334. clear_cache()
  335. elif options.append_future_import:
  336. append_future_import()
  337. elif options.backup:
  338. from webnotes.utils.backups import scheduled_backup
  339. scheduled_backup()
  340. # print messages
  341. if webnotes.message_log:
  342. print '\n'.join(webnotes.message_log)
  343. if options.test is not None:
  344. module_name = options.test
  345. import unittest
  346. del sys.argv[1:]
  347. # is there a better way?
  348. exec ('from %s import *' % module_name) in globals()
  349. unittest.main()
  350. if __name__=='__main__':
  351. run()