cmakelib.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import sys, subprocess, json
  2. termwidth = 150
  3. print_communication = True
  4. def ordered(obj):
  5. if isinstance(obj, dict):
  6. return sorted((k, ordered(v)) for k, v in obj.items())
  7. if isinstance(obj, list):
  8. return sorted(ordered(x) for x in obj)
  9. else:
  10. return obj
  11. def col_print(title, array):
  12. print
  13. print
  14. print(title)
  15. indentwidth = 4
  16. indent = " " * indentwidth
  17. if not array:
  18. print(indent + "<None>")
  19. return
  20. padwidth = 2
  21. maxitemwidth = len(max(array, key=len))
  22. numCols = max(1, int((termwidth - indentwidth + padwidth) / (maxitemwidth + padwidth)))
  23. numRows = len(array) // numCols + 1
  24. pad = " " * padwidth
  25. for index in range(numRows):
  26. print(indent + pad.join(item.ljust(maxitemwidth) for item in array[index::numRows]))
  27. def waitForRawMessage(cmakeCommand):
  28. stdoutdata = ""
  29. payload = ""
  30. while not cmakeCommand.poll():
  31. stdoutdataLine = cmakeCommand.stdout.readline()
  32. if stdoutdataLine:
  33. stdoutdata += stdoutdataLine.decode('utf-8')
  34. else:
  35. break
  36. begin = stdoutdata.find("[== CMake Server ==[\n")
  37. end = stdoutdata.find("]== CMake Server ==]")
  38. if (begin != -1 and end != -1):
  39. begin += len("[== CMake Server ==[\n")
  40. payload = stdoutdata[begin:end]
  41. if print_communication:
  42. print("\nSERVER>", json.loads(payload), "\n")
  43. return json.loads(payload)
  44. def writeRawData(cmakeCommand, content):
  45. writeRawData.counter += 1
  46. payload = """
  47. [== CMake Server ==[
  48. %s
  49. ]== CMake Server ==]
  50. """ % content
  51. rn = ( writeRawData.counter % 2 ) == 0
  52. if rn:
  53. payload = payload.replace('\n', '\r\n')
  54. if print_communication:
  55. print("\nCLIENT>", content, "(Use \\r\\n:", rn, ")\n")
  56. cmakeCommand.stdin.write(payload.encode('utf-8'))
  57. cmakeCommand.stdin.flush()
  58. writeRawData.counter = 0
  59. def writePayload(cmakeCommand, obj):
  60. writeRawData(cmakeCommand, json.dumps(obj))
  61. def initProc(cmakeCommand):
  62. cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", "--experimental", "--debug"],
  63. stdin=subprocess.PIPE,
  64. stdout=subprocess.PIPE)
  65. packet = waitForRawMessage(cmakeCommand)
  66. if packet == None:
  67. print("Not in server mode")
  68. sys.exit(1)
  69. if packet['type'] != 'hello':
  70. print("No hello message")
  71. sys.exit(1)
  72. return cmakeCommand
  73. def waitForMessage(cmakeCommand, expected):
  74. data = ordered(expected)
  75. packet = ordered(waitForRawMessage(cmakeCommand))
  76. if packet != data:
  77. sys.exit(-1)
  78. return packet
  79. def waitForReply(cmakeCommand, originalType, cookie, skipProgress):
  80. gotResult = False
  81. while True:
  82. packet = waitForRawMessage(cmakeCommand)
  83. t = packet['type']
  84. if packet['cookie'] != cookie or packet['inReplyTo'] != originalType:
  85. sys.exit(1)
  86. if t == 'message' or t == 'progress':
  87. if skipProgress:
  88. continue
  89. if t == 'reply':
  90. break
  91. sys.exit(1)
  92. return packet
  93. def waitForError(cmakeCommand, originalType, cookie, message):
  94. packet = waitForRawMessage(cmakeCommand)
  95. if packet['cookie'] != cookie or packet['type'] != 'error' or packet['inReplyTo'] != originalType or packet['errorMessage'] != message:
  96. sys.exit(1)
  97. def waitForProgress(cmakeCommand, originalType, cookie, current, message):
  98. packet = waitForRawMessage(cmakeCommand)
  99. if packet['cookie'] != cookie or packet['type'] != 'progress' or packet['inReplyTo'] != originalType or packet['progressCurrent'] != current or packet['progressMessage'] != message:
  100. sys.exit(1)
  101. def handshake(cmakeCommand, major, minor, source, build, generator, extraGenerator):
  102. version = { 'major': major }
  103. if minor >= 0:
  104. version['minor'] = minor
  105. writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version,
  106. 'cookie': 'TEST_HANDSHAKE', 'sourceDirectory': source, 'buildDirectory': build,
  107. 'generator': generator, 'extraGenerator': extraGenerator })
  108. waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE', False)
  109. def validateGlobalSettings(cmakeCommand, cmakeCommandPath, data):
  110. packet = waitForReply(cmakeCommand, 'globalSettings', '', False)
  111. capabilities = packet['capabilities']
  112. # validate version:
  113. cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--version" ], universal_newlines=True)
  114. cmakeVersion = cmakeoutput.splitlines()[0][14:]
  115. version = capabilities['version']
  116. versionString = version['string']
  117. vs = str(version['major']) + '.' + str(version['minor']) + '.' + str(version['patch'])
  118. if (versionString != vs and not versionString.startswith(vs + '-')):
  119. sys.exit(1)
  120. if (versionString != cmakeVersion):
  121. sys.exit(1)
  122. # validate generators:
  123. generatorObjects = capabilities['generators']
  124. cmakeoutput = subprocess.check_output([ cmakeCommandPath, "--help" ], universal_newlines=True)
  125. index = cmakeoutput.index('\nGenerators\n\n')
  126. cmakeGenerators = []
  127. for line in cmakeoutput[index + 12:].splitlines():
  128. if not line.startswith(' '):
  129. continue
  130. if line.startswith(' '):
  131. continue
  132. equalPos = line.find('=')
  133. tmp = ''
  134. if (equalPos > 0):
  135. tmp = line[2:equalPos].strip()
  136. else:
  137. tmp = line.strip()
  138. if tmp.endswith(" [arch]"):
  139. tmp = tmp[0:len(tmp) - 7]
  140. if (len(tmp) > 0) and (" - " not in tmp) and (tmp != 'KDevelop3'):
  141. cmakeGenerators.append(tmp)
  142. generators = []
  143. for genObj in generatorObjects:
  144. generators.append(genObj['name'])
  145. generators.sort()
  146. cmakeGenerators.sort()
  147. for gen in cmakeGenerators:
  148. if (not gen in generators):
  149. sys.exit(1)
  150. gen = packet['generator']
  151. if (gen != '' and not (gen in generators)):
  152. sys.exit(1)
  153. for i in data:
  154. print("Validating", i)
  155. if (packet[i] != data[i]):
  156. sys.exit(1)