Skip to content

Commit 12d085e

Browse files
committed
Updated synchronization script
Added persistent line endings, commit message on the command line and "quiet" option (run without user interaction).
1 parent 171dda7 commit 12d085e

File tree

1 file changed

+130
-21
lines changed

1 file changed

+130
-21
lines changed

workspace_tools/synch.py

Lines changed: 130 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import sys
2323
from copy import copy
2424
from os import walk, remove, makedirs
25-
from os.path import join, abspath, dirname, relpath, exists, splitext
25+
from os.path import join, abspath, dirname, relpath, exists, isfile
2626
from shutil import copyfile
2727
from optparse import OptionParser
28+
import re
29+
import string
2830

2931
ROOT = abspath(join(dirname(__file__), ".."))
3032
sys.path.append(ROOT)
@@ -33,11 +35,12 @@
3335
from workspace_tools.paths import LIB_DIR
3436
from workspace_tools.utils import cmd, run_cmd
3537

36-
3738
MBED_URL = "mbed.org"
38-
# MBED_URL = "world2.dev.mbed.org"
3939

40-
MBED_REPO_EXT = (".lib", ".bld")
40+
changed = []
41+
push_remote = True
42+
quiet = False
43+
commit_msg = ''
4144

4245
# mbed_official code that does have a mirror in the mbed SDK
4346
OFFICIAL_CODE = (
@@ -88,6 +91,23 @@
8891
"mbed-src-program",
8992
)
9093

94+
# A list of regular expressions that will be checked against each directory
95+
# name and skipped if they match.
96+
IGNORE_DIRS = (
97+
)
98+
99+
IGNORE_FILES = (
100+
'COPYING',
101+
'\.md',
102+
"\.lib",
103+
"\.bld"
104+
)
105+
106+
def ignore_path(name, reg_exps):
107+
for r in reg_exps:
108+
if re.search(r, name):
109+
return True
110+
return False
91111

92112
class MbedOfficialRepository:
93113
URL = "http://" + MBED_URL + "/users/mbed_official/code/%s/"
@@ -114,30 +134,99 @@ def publish(self):
114134
stdout, _, _ = run_cmd(['hg', 'status'], wd=self.path)
115135
if stdout == '':
116136
print "No changes"
117-
return
137+
return False
118138

119139
print stdout
120-
commit = raw_input("Do you want to commit and push? Y/N: ")
140+
if quiet:
141+
commit = 'Y'
142+
else:
143+
commit = raw_input(push_remote and "Do you want to commit and push? Y/N: " or "Do you want to commit? Y/N: ")
121144
if commit == 'Y':
122-
cmd(['hg', 'commit', '-u', MBED_ORG_USER], cwd=self.path)
123-
cmd(['hg', 'push'], cwd=self.path)
145+
args = ['hg', 'commit', '-u', MBED_ORG_USER]
146+
if commit_msg:
147+
args = args + ['-m', commit_msg]
148+
cmd(args, cwd=self.path)
149+
if push_remote:
150+
cmd(['hg', 'push'], cwd=self.path)
151+
return True
124152

153+
# Check if a file is a text file or a binary file
154+
# Taken from http://code.activestate.com/recipes/173220/
155+
text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b"))
156+
_null_trans = string.maketrans("", "")
157+
def is_text_file(filename):
158+
block_size = 1024
159+
def istext(s):
160+
if "\0" in s:
161+
return 0
125162

126-
def visit_files(path, visit, ignore=None, select=None):
163+
if not s: # Empty files are considered text
164+
return 1
165+
166+
# Get the non-text characters (maps a character to itself then
167+
# use the 'remove' option to get rid of the text characters.)
168+
t = s.translate(_null_trans, text_characters)
169+
170+
# If more than 30% non-text characters, then
171+
# this is considered a binary file
172+
if float(len(t))/len(s) > 0.30:
173+
return 0
174+
return 1
175+
with open(filename) as f:
176+
res = istext(f.read(block_size))
177+
return res
178+
179+
# Return the line ending type for the given file ('cr' or 'crlf')
180+
def get_line_endings(f):
181+
examine_size = 1024
182+
try:
183+
tf = open(f, "rb")
184+
lines, ncrlf = tf.readlines(examine_size), 0
185+
tf.close()
186+
for l in lines:
187+
if l.endswith("\r\n"):
188+
ncrlf = ncrlf + 1
189+
return 'crlf' if ncrlf > len(lines) >> 1 else 'cr'
190+
except:
191+
return 'cr'
192+
193+
# Copy file to destination, but preserve destination line endings if possible
194+
# This prevents very annoying issues with huge diffs that appear because of
195+
# differences in line endings
196+
def copy_with_line_endings(sdk_file, repo_file):
197+
if not isfile(repo_file):
198+
copyfile(sdk_file, repo_file)
199+
return
200+
is_text = is_text_file(repo_file)
201+
if is_text:
202+
sdk_le = get_line_endings(sdk_file)
203+
repo_le = get_line_endings(repo_file)
204+
if not is_text or sdk_le == repo_le:
205+
copyfile(sdk_file, repo_file)
206+
else:
207+
print "Converting line endings in '%s' to '%s'" % (abspath(repo_file), repo_le)
208+
f = open(sdk_file, "rb")
209+
data = f.read()
210+
f.close()
211+
f = open(repo_file, "wb")
212+
data = data.replace("\r\n", "\n") if repo_le == 'cr' else data.replace('\n','\r\n')
213+
f.write(data)
214+
f.close()
215+
216+
def visit_files(path, visit):
127217
for root, dirs, files in walk(path):
128218
# Ignore hidden directories
129219
for d in copy(dirs):
220+
full = join(root, d)
130221
if d.startswith('.'):
131222
dirs.remove(d)
223+
if ignore_path(full, IGNORE_DIRS):
224+
print "Skipping '%s'" % full
225+
dirs.remove(d)
132226

133227
for file in files:
134-
ext = splitext(file)[1]
135-
136-
if ignore is not None:
137-
if ext in ignore: continue
138-
139-
if select is not None:
140-
if ext not in select: continue
228+
if ignore_path(file, IGNORE_FILES):
229+
continue
141230

142231
visit(join(root, file))
143232

@@ -152,18 +241,19 @@ def visit_mbed_sdk(sdk_file):
152241
if not exists(repo_dir):
153242
makedirs(repo_dir)
154243

155-
copyfile(sdk_file, repo_file)
156-
visit_files(sdk_path, visit_mbed_sdk, ['.json'])
244+
copy_with_line_endings(sdk_file, repo_file)
245+
visit_files(sdk_path, visit_mbed_sdk)
157246

158247
# remove repository files that do not exist in the mbed SDK
159248
def visit_repo(repo_file):
160249
sdk_file = join(sdk_path, relpath(repo_file, repo.path))
161250
if not exists(sdk_file):
162251
remove(repo_file)
163252
print "remove: %s" % repo_file
164-
visit_files(repo.path, visit_repo, MBED_REPO_EXT)
253+
visit_files(repo.path, visit_repo)
165254

166-
repo.publish()
255+
if repo.publish():
256+
changed.append(repo_name)
167257

168258

169259
def update_code(repositories):
@@ -186,7 +276,8 @@ def visit_repo(repo_file):
186276
f.write(url[:(url.rindex('/')+1)])
187277
visit_files(repo.path, visit_repo, None, MBED_REPO_EXT)
188278

189-
repo.publish()
279+
if repo.publish():
280+
changed.append(repo_name)
190281

191282

192283
def update_mbed():
@@ -208,8 +299,23 @@ def update_mbed():
208299
action="store_true", default=False,
209300
help="Release a build of the mbed library")
210301

302+
parser.add_option("-n", "--nopush",
303+
action="store_true", default=False,
304+
help="Commit the changes locally only, don't push them")
305+
306+
parser.add_option("", "--commit_message",
307+
action="store", type="string", default='', dest='msg',
308+
help="Commit message to use for all the commits")
309+
parser.add_option("-q", "--quiet",
310+
action="store_true", default=False,
311+
help="Don't ask for confirmation before commiting or pushing")
312+
211313
(options, args) = parser.parse_args()
212314

315+
push_remote = not options.nopush
316+
quiet = options.quiet
317+
commit_msg = options.msg
318+
213319
if options.code:
214320
update_code(OFFICIAL_CODE)
215321

@@ -219,3 +325,6 @@ def update_mbed():
219325
if options.mbed:
220326
update_mbed()
221327

328+
if changed:
329+
print "Repositories with changes:", changed
330+

0 commit comments

Comments
 (0)