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.
 
 
 
 
 
 

196 lines
5.9 KiB

  1. # Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. #
  3. # MIT License (MIT)
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a
  6. # copy of this software and associated documentation files (the "Software"),
  7. # to deal in the Software without restriction, including without limitation
  8. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. # and/or sell copies of the Software, and to permit persons to whom the
  10. # Software is furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. #
  22. """get diff bettween txt files and database records"""
  23. import webnotes
  24. import os, conf
  25. from webnotes.model.utils import peval_doclist
  26. dt_map = {
  27. 'DocType': {
  28. 'DocField': ['fieldname', 'label']
  29. },
  30. 'Search Criteria': {},
  31. 'Page': {}
  32. }
  33. ignore_fields = ('modified', 'creation', 'owner', 'modified_by',
  34. '_last_update', 'version', 'idx', 'name')
  35. missing = property_diff = 0
  36. property_count = {}
  37. def diff_ref_file():
  38. """get diff using .txt files as reference"""
  39. global missing, property_diff, property_count
  40. missing = property_diff = 0
  41. property_count = {}
  42. get_diff(conf.modules_path)
  43. get_diff(os.path.join(os.getcwd(), 'lib', 'py', 'core'))
  44. print_stats()
  45. def get_diff(path):
  46. for wt in os.walk(path):
  47. for fname in wt[2]:
  48. if fname.endswith('.txt'):
  49. path = os.path.join(wt[0], fname)
  50. with open(path, 'r') as txtfile:
  51. doclist_diff(peval_doclist(txtfile.read()))
  52. def diff_ref_db():
  53. """get diff using database as reference"""
  54. from webnotes.modules import scrub
  55. for dt in dt_map:
  56. # get all main docs
  57. for doc in webnotes.conn.sql("""select * from `tab%s`""" % dt, as_dict=1):
  58. # get file for this doc
  59. doc['doctype'] = dt
  60. #print doc['name'], doc['doctype'], doc['module']
  61. path = os.path.join(conf.modules_path, scrub(doc['module']), \
  62. scrub(dt), scrub(doc['name']), scrub(doc['name']) + '.txt')
  63. path_core = os.path.join(os.getcwd(), 'lib', 'py', 'core', \
  64. scrub(dt), scrub(doc['name']), scrub(doc['name']) + '.txt')
  65. if os.path.exists(path):
  66. with open(path, 'r') as txtfile:
  67. target = peval_doclist(txtfile.read())
  68. elif os.path.exists(path_core):
  69. with open(path_core, 'r') as txtfile:
  70. target = peval_doclist(txtfile.read())
  71. else:
  72. target = [None,]
  73. doc_diff(doc, target[0])
  74. # do diff for child records
  75. if target[0] and dt_map[dt].keys():
  76. for child_dt in dt_map[dt]:
  77. # for each child type, we need to create
  78. # a key (e.g. fieldname, label) based mapping of child records in
  79. # txt files
  80. child_key_map = {}
  81. keys = dt_map[dt][child_dt]
  82. for target_d in target:
  83. if target_d['doctype'] == child_dt:
  84. for key in keys:
  85. if target_d.get(key):
  86. child_key_map[target_d.get(key)] = target_d
  87. break
  88. for d in webnotes.conn.sql("""select * from `tab%s` where
  89. parent=%s and docstatus<2""" % (child_dt, '%s'), doc['name'], as_dict=1):
  90. source_key = None
  91. d['doctype'] = child_dt
  92. for key in keys:
  93. if d.get(key):
  94. source_key = d.get(key)
  95. break
  96. # only if a key is found
  97. if source_key:
  98. doc_diff(d, child_key_map.get(source_key), source_key)
  99. print_stats()
  100. def doclist_diff(doclist):
  101. # main doc
  102. doc = doclist[0]
  103. if doc['doctype'] in dt_map.keys():
  104. # do for main
  105. target = webnotes.conn.sql("""select * from `tab%s`
  106. where name=%s""" % (doc['doctype'], '%s'), doc['name'], as_dict=1)
  107. doc_diff(doc, target and target[0] or None)
  108. if not target:
  109. # no parent, no children!
  110. return
  111. for d in doclist[1:]:
  112. # if child
  113. if d['doctype'] in dt_map[doc['doctype']].keys():
  114. child_keys = dt_map[doc['doctype']][d['doctype']]
  115. # find the key on which a child is unique
  116. child_key = child_key_value = None
  117. for key in child_keys:
  118. if d.get(key):
  119. child_key = key
  120. child_key_value = d[key]
  121. break
  122. # incoming child record has a uniquely
  123. # identifiable key
  124. if child_key:
  125. target = webnotes.conn.sql("""select * from `tab%s`
  126. where `%s`=%s and parent=%s""" % (d['doctype'], child_key, '%s', '%s'),
  127. (child_key_value, d['parent']), as_dict=1)
  128. doc_diff(d, target and target[0] or None, child_key_value)
  129. def doc_diff(source, target, child_key_value=None):
  130. from termcolor import colored
  131. global property_diff, property_count, missing
  132. docname = source.get('parent') and (source.get('parent') + '.' + child_key_value) \
  133. or source['name']
  134. if not target:
  135. missing += 1
  136. print(colored((source['doctype'] + ' -> ' + docname), 'red') + ' missing')
  137. else:
  138. target['doctype'] = source['doctype']
  139. for key in source:
  140. if (key not in ignore_fields) \
  141. and (target.get(key) != source[key]) \
  142. and (not (target.get(key)==None and source[key]==0)):
  143. prefix = source['doctype']+' -> ' + docname + ' -> '+key+' = '
  144. in_db = colored(str(target.get(key)), 'red')
  145. in_file = colored(str(source[key]), 'green')
  146. print(prefix + in_db + ' | ' + in_file)
  147. property_diff += 1
  148. if not key in property_count:
  149. property_count[key] = 0
  150. property_count[key] += 1
  151. def print_stats():
  152. print
  153. print "Missing records: " + str(missing)
  154. print "Property mismatch: " + str(property_diff)
  155. for key in property_count:
  156. print "- " + key + ": " + str(property_count[key] or 0)
  157. print