Keyboard firmwares for Atmel AVR and Cortex-M
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.

synch.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. """
  2. mbed SDK
  3. Copyright (c) 2011-2013 ARM Limited
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. One repository to update them all
  14. On mbed.org the mbed SDK is split up in multiple repositories, this script takes
  15. care of updating them all.
  16. """
  17. import sys
  18. from copy import copy
  19. from os import walk, remove, makedirs
  20. from os.path import join, abspath, dirname, relpath, exists, isfile
  21. from shutil import copyfile
  22. from optparse import OptionParser
  23. import re
  24. import string
  25. ROOT = abspath(join(dirname(__file__), ".."))
  26. sys.path.insert(0, ROOT)
  27. from workspace_tools.settings import MBED_ORG_PATH, MBED_ORG_USER, BUILD_DIR
  28. from workspace_tools.paths import LIB_DIR
  29. from workspace_tools.utils import run_cmd
  30. MBED_URL = "mbed.org"
  31. MBED_USER = "mbed_official"
  32. changed = []
  33. push_remote = True
  34. quiet = False
  35. commit_msg = ''
  36. # Code that does have a mirror in the mbed SDK
  37. # Tuple data: (repo_name, list_of_code_dirs, [team])
  38. # team is optional - if not specified, the code is published under mbed_official
  39. OFFICIAL_CODE = (
  40. ("mbed-src" , "mbed"),
  41. ("mbed-rtos", "rtos"),
  42. ("mbed-dsp" , "dsp"),
  43. ("mbed-rpc" , "rpc"),
  44. ("lwip" , "net/lwip/lwip"),
  45. ("lwip-sys", "net/lwip/lwip-sys"),
  46. ("Socket" , "net/lwip/Socket"),
  47. ("lwip-eth" , "net/eth/lwip-eth"),
  48. ("EthernetInterface", "net/eth/EthernetInterface"),
  49. ("USBDevice", "USBDevice"),
  50. ("USBHost" , "USBHost"),
  51. ("CellularModem", "net/cellular/CellularModem"),
  52. ("CellularUSBModem", "net/cellular/CellularUSBModem"),
  53. ("UbloxUSBModem", "net/cellular/UbloxUSBModem"),
  54. ("UbloxModemHTTPClientTest", ["tests/net/cellular/http/common", "tests/net/cellular/http/ubloxusb"]),
  55. ("UbloxModemSMSTest", ["tests/net/cellular/sms/common", "tests/net/cellular/sms/ubloxusb"]),
  56. ("FATFileSystem", "fs/fat", "mbed-official"),
  57. )
  58. # Code that does have dependencies to libraries should point to
  59. # the latest revision. By default, they point to a specific revision.
  60. CODE_WITH_DEPENDENCIES = (
  61. # Libraries
  62. "EthernetInterface",
  63. # RTOS Examples
  64. "rtos_basic",
  65. "rtos_isr",
  66. "rtos_mail",
  67. "rtos_mutex",
  68. "rtos_queue",
  69. "rtos_semaphore",
  70. "rtos_signals",
  71. "rtos_timer",
  72. # Net Examples
  73. "TCPEchoClient",
  74. "TCPEchoServer",
  75. "TCPSocket_HelloWorld",
  76. "UDPSocket_HelloWorld",
  77. "UDPEchoClient",
  78. "UDPEchoServer",
  79. "BroadcastReceive",
  80. "BroadcastSend",
  81. # mbed sources
  82. "mbed-src-program",
  83. )
  84. # A list of regular expressions that will be checked against each directory
  85. # name and skipped if they match.
  86. IGNORE_DIRS = (
  87. )
  88. IGNORE_FILES = (
  89. 'COPYING',
  90. '\.md',
  91. "\.lib",
  92. "\.bld"
  93. )
  94. def ignore_path(name, reg_exps):
  95. for r in reg_exps:
  96. if re.search(r, name):
  97. return True
  98. return False
  99. class MbedRepository:
  100. @staticmethod
  101. def run_and_print(command, cwd):
  102. stdout, _, _ = run_cmd(command, wd=cwd, redirect=True)
  103. print(stdout)
  104. def __init__(self, name, team = None):
  105. self.name = name
  106. self.path = join(MBED_ORG_PATH, name)
  107. if team is None:
  108. self.url = "http://" + MBED_URL + "/users/" + MBED_USER + "/code/%s/"
  109. else:
  110. self.url = "http://" + MBED_URL + "/teams/" + team + "/code/%s/"
  111. if not exists(self.path):
  112. # Checkout code
  113. if not exists(MBED_ORG_PATH):
  114. makedirs(MBED_ORG_PATH)
  115. self.run_and_print(['hg', 'clone', self.url % name], cwd=MBED_ORG_PATH)
  116. else:
  117. # Update
  118. self.run_and_print(['hg', 'pull'], cwd=self.path)
  119. self.run_and_print(['hg', 'update'], cwd=self.path)
  120. def publish(self):
  121. # The maintainer has to evaluate the changes first and explicitly accept them
  122. self.run_and_print(['hg', 'addremove'], cwd=self.path)
  123. stdout, _, _ = run_cmd(['hg', 'status'], wd=self.path)
  124. if stdout == '':
  125. print "No changes"
  126. return False
  127. print stdout
  128. if quiet:
  129. commit = 'Y'
  130. else:
  131. commit = raw_input(push_remote and "Do you want to commit and push? Y/N: " or "Do you want to commit? Y/N: ")
  132. if commit == 'Y':
  133. args = ['hg', 'commit', '-u', MBED_ORG_USER]
  134. if commit_msg:
  135. args = args + ['-m', commit_msg]
  136. self.run_and_print(args, cwd=self.path)
  137. if push_remote:
  138. self.run_and_print(['hg', 'push'], cwd=self.path)
  139. return True
  140. # Check if a file is a text file or a binary file
  141. # Taken from http://code.activestate.com/recipes/173220/
  142. text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b"))
  143. _null_trans = string.maketrans("", "")
  144. def is_text_file(filename):
  145. block_size = 1024
  146. def istext(s):
  147. if "\0" in s:
  148. return 0
  149. if not s: # Empty files are considered text
  150. return 1
  151. # Get the non-text characters (maps a character to itself then
  152. # use the 'remove' option to get rid of the text characters.)
  153. t = s.translate(_null_trans, text_characters)
  154. # If more than 30% non-text characters, then
  155. # this is considered a binary file
  156. if float(len(t))/len(s) > 0.30:
  157. return 0
  158. return 1
  159. with open(filename) as f:
  160. res = istext(f.read(block_size))
  161. return res
  162. # Return the line ending type for the given file ('cr' or 'crlf')
  163. def get_line_endings(f):
  164. examine_size = 1024
  165. try:
  166. tf = open(f, "rb")
  167. lines, ncrlf = tf.readlines(examine_size), 0
  168. tf.close()
  169. for l in lines:
  170. if l.endswith("\r\n"):
  171. ncrlf = ncrlf + 1
  172. return 'crlf' if ncrlf > len(lines) >> 1 else 'cr'
  173. except:
  174. return 'cr'
  175. # Copy file to destination, but preserve destination line endings if possible
  176. # This prevents very annoying issues with huge diffs that appear because of
  177. # differences in line endings
  178. def copy_with_line_endings(sdk_file, repo_file):
  179. if not isfile(repo_file):
  180. copyfile(sdk_file, repo_file)
  181. return
  182. is_text = is_text_file(repo_file)
  183. if is_text:
  184. sdk_le = get_line_endings(sdk_file)
  185. repo_le = get_line_endings(repo_file)
  186. if not is_text or sdk_le == repo_le:
  187. copyfile(sdk_file, repo_file)
  188. else:
  189. print "Converting line endings in '%s' to '%s'" % (abspath(repo_file), repo_le)
  190. f = open(sdk_file, "rb")
  191. data = f.read()
  192. f.close()
  193. f = open(repo_file, "wb")
  194. data = data.replace("\r\n", "\n") if repo_le == 'cr' else data.replace('\n','\r\n')
  195. f.write(data)
  196. f.close()
  197. def visit_files(path, visit):
  198. for root, dirs, files in walk(path):
  199. # Ignore hidden directories
  200. for d in copy(dirs):
  201. full = join(root, d)
  202. if d.startswith('.'):
  203. dirs.remove(d)
  204. if ignore_path(full, IGNORE_DIRS):
  205. print "Skipping '%s'" % full
  206. dirs.remove(d)
  207. for file in files:
  208. if ignore_path(file, IGNORE_FILES):
  209. continue
  210. visit(join(root, file))
  211. def update_repo(repo_name, sdk_paths, team_name):
  212. repo = MbedRepository(repo_name, team_name)
  213. # copy files from mbed SDK to mbed_official repository
  214. def visit_mbed_sdk(sdk_file):
  215. repo_file = join(repo.path, relpath(sdk_file, sdk_path))
  216. repo_dir = dirname(repo_file)
  217. if not exists(repo_dir):
  218. makedirs(repo_dir)
  219. copy_with_line_endings(sdk_file, repo_file)
  220. for sdk_path in sdk_paths:
  221. visit_files(sdk_path, visit_mbed_sdk)
  222. # remove repository files that do not exist in the mbed SDK
  223. def visit_repo(repo_file):
  224. for sdk_path in sdk_paths:
  225. sdk_file = join(sdk_path, relpath(repo_file, repo.path))
  226. if exists(sdk_file):
  227. break
  228. else:
  229. remove(repo_file)
  230. print "remove: %s" % repo_file
  231. visit_files(repo.path, visit_repo)
  232. if repo.publish():
  233. changed.append(repo_name)
  234. def update_code(repositories):
  235. for r in repositories:
  236. repo_name, sdk_dir = r[0], r[1]
  237. team_name = r[2] if len(r) == 3 else None
  238. print '\n=== Updating "%s" ===' % repo_name
  239. sdk_dirs = [sdk_dir] if type(sdk_dir) != type([]) else sdk_dir
  240. sdk_path = [join(LIB_DIR, d) for d in sdk_dirs]
  241. update_repo(repo_name, sdk_path, team_name)
  242. def update_single_repo(repo):
  243. repos = [r for r in OFFICIAL_CODE if r[0] == repo]
  244. if not repos:
  245. print "Repository '%s' not found" % repo
  246. else:
  247. update_code(repos)
  248. def update_dependencies(repositories):
  249. for repo_name in repositories:
  250. print '\n=== Updating "%s" ===' % repo_name
  251. repo = MbedRepository(repo_name)
  252. # point to the latest libraries
  253. def visit_repo(repo_file):
  254. with open(repo_file, "r") as f:
  255. url = f.read()
  256. with open(repo_file, "w") as f:
  257. f.write(url[:(url.rindex('/')+1)])
  258. visit_files(repo.path, visit_repo, None, MBED_REPO_EXT)
  259. if repo.publish():
  260. changed.append(repo_name)
  261. def update_mbed():
  262. update_repo("mbed", [join(BUILD_DIR, "mbed")], None)
  263. def do_sync(options):
  264. global push_remote, quiet, commit_msg, changed
  265. push_remote = not options.nopush
  266. quiet = options.quiet
  267. commit_msg = options.msg
  268. chnaged = []
  269. if options.code:
  270. update_code(OFFICIAL_CODE)
  271. if options.dependencies:
  272. update_dependencies(CODE_WITH_DEPENDENCIES)
  273. if options.mbed:
  274. update_mbed()
  275. if options.repo:
  276. update_single_repo(options.repo)
  277. if changed:
  278. print "Repositories with changes:", changed
  279. return changed
  280. if __name__ == '__main__':
  281. parser = OptionParser()
  282. parser.add_option("-c", "--code",
  283. action="store_true", default=False,
  284. help="Update the mbed_official code")
  285. parser.add_option("-d", "--dependencies",
  286. action="store_true", default=False,
  287. help="Update the mbed_official code dependencies")
  288. parser.add_option("-m", "--mbed",
  289. action="store_true", default=False,
  290. help="Release a build of the mbed library")
  291. parser.add_option("-n", "--nopush",
  292. action="store_true", default=False,
  293. help="Commit the changes locally only, don't push them")
  294. parser.add_option("", "--commit_message",
  295. action="store", type="string", default='', dest='msg',
  296. help="Commit message to use for all the commits")
  297. parser.add_option("-r", "--repository",
  298. action="store", type="string", default='', dest='repo',
  299. help="Synchronize only the given repository")
  300. parser.add_option("-q", "--quiet",
  301. action="store_true", default=False,
  302. help="Don't ask for confirmation before commiting or pushing")
  303. (options, args) = parser.parse_args()
  304. do_sync(options)