Created
April 6, 2016 18:27
-
-
Save pan-/9be5af8bcff3479bd2773137677fe66f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
git clone https://github.com/ARMmbed/ble.git upstream | |
hg clone https://<username>@developer.mbed.org/teams/Bluetooth-Low-Energy/code/BLE_API/ | |
python -u git-hg-repoSynch/synch.py -n upstream BLE_API |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
""" | |
mbed SDK | |
Copyright (c) 2011-2013 ARM Limited | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
One repository to update them all | |
On mbed.org the mbed SDK is split up in multiple repositories, this script takes | |
care of updating them all. | |
""" | |
import git | |
import os | |
from os import walk, remove, makedirs | |
from os.path import join, abspath, dirname, relpath, exists, isfile | |
from optparse import OptionParser | |
import re | |
import string | |
from utils import run_cmd, error | |
import codecs | |
MBED_URL = "mbed.org" | |
MBED_USER = "mbed_official" | |
MBED_ORG_USER = "vcoubard" | |
class MbedRepository: | |
@staticmethod | |
def run_and_print(command, cwd): | |
stdout, _, _ = run_cmd(command, wd=cwd, redirect=True) | |
print(stdout) | |
def __init__(self, name, team = None, MBED_ORG_PATH = "http:"): | |
self.name = name | |
self.path = join(MBED_ORG_PATH, name) | |
if team is None: | |
self.url = "http://" + MBED_URL + "/users/" + MBED_USER + "/code/%s/" | |
else: | |
self.url = "http://" + MBED_URL + "/teams/" + team + "/code/%s/" | |
if not exists(self.path): | |
# Checkout code | |
if not exists(MBED_ORG_PATH): | |
makedirs(MBED_ORG_PATH) | |
self.run_and_print(['hg', 'clone', self.url % name], cwd=MBED_ORG_PATH) | |
else: | |
# Update | |
self.run_and_print(['hg', 'pull'], cwd=self.path) | |
self.run_and_print(['hg', 'update'], cwd=self.path) | |
def publish(self, commit_msg): | |
# The maintainer has to evaluate the changes first and explicitly accept them | |
self.run_and_print(['hg', 'addremove'], cwd=self.path) | |
stdout, _, _ = run_cmd(['hg', 'status'], wd=self.path) | |
if stdout == '': | |
print "No changes" | |
return False | |
print stdout | |
global quiet | |
if quiet: | |
commit = 'Y' | |
else: | |
commit = raw_input(push_remote and "Do you want to commit and push? Y/N: " or "Do you want to commit? Y/N: ") | |
if commit == 'Y': | |
args = ['hg', 'commit', '-u', MBED_ORG_USER] | |
args = args + ['-m', commit_msg] | |
self.run_and_print(args, cwd=self.path) | |
return True | |
# if push_remote: | |
# self.run_and_print(['hg', 'push'], cwd=self.path) | |
def processAddition(added): | |
global gitRepo | |
filename = re.sub(r'\n.*$', '', added.__str__(), flags = re.M) | |
print "added '{}'".format(filename) | |
targetFile = join(mercurial_repo_name, filename) | |
if not os.path.exists(os.path.dirname(targetFile)): | |
os.makedirs(os.path.dirname(targetFile)) | |
fh = codecs.open(targetFile, "w") | |
content = gitRepo.git.show(added.b_blob, stdout_as_string=False) | |
fh.write(content) | |
fh.close() | |
def processDeletion(deleted): | |
global gitRepo | |
filename = re.sub(r'\n.*$', '', deleted.__str__(), flags = re.M) | |
print "deleted '{}'".format(filename) | |
targetFile = join(mercurial_repo_name, filename) | |
remove(targetFile) | |
def processRenamed(renamed): | |
source = re.search(r"renamed from u'(.*)'", renamed.__str__()).group(1) | |
dest = re.search(r"renamed to u'(.*)'", renamed.__str__()).group(1) | |
print "rename {} to {}".format(source, dest) | |
source = join(mercurial_repo_name, source) | |
dest = join(mercurial_repo_name, dest) | |
if os.path.isfile(dest): | |
remove(dest) | |
os.rename(source, dest) | |
def processModification(modified): | |
global gitRepo | |
filename = re.sub(r'\n.*$', '', modified.__str__(), flags = re.M) | |
print "modified '{}'".format(filename) | |
targetFile = join(mercurial_repo_name, filename) | |
if not os.path.exists(os.path.dirname(targetFile)): | |
os.makedirs(os.path.dirname(targetFile)) | |
fh = codecs.open(targetFile, "w") | |
content = gitRepo.git.show(modified.b_blob, stdout_as_string=False) | |
fh.write(content) | |
fh.close() | |
def resolveRepoToTeam(repo_name): | |
REPOS_AND_TEAMS = ( | |
('BLE_API', 'Bluetooth-Low-Energy'), | |
('nRF51822', 'Nordic-Semiconductor') | |
) | |
for (r,t) in REPOS_AND_TEAMS: | |
if repo_name == r: | |
return t; | |
else: | |
assert False, "don't know how to handle repo '{}'".format(repo_name) | |
def determineGitSyncPoint(hg_repo_dir, repo_name): | |
stdout, _, _ = run_cmd(['hg', 'log', '-v', '-l2'], wd=join(hg_repo_dir, repo_name), redirect=True) | |
for line in stdout.splitlines(): | |
m = re.search('Synchronized with git rev (\w+)', line) | |
if m: | |
break | |
else: | |
assert False, "Failed to find git revision; check mercurial logs" | |
return m.group(1) | |
def doSync(options, repo_name, mercurial_repo_name): | |
print "\n=== fetching mercurial repository {} ===".format(repo_name) | |
team_name = resolveRepoToTeam(mercurial_repo_name) | |
hgRepo = MbedRepository(mercurial_repo_name, team_name, "") | |
global gitRepo | |
gitRepo = git.Repo(repo_name) | |
# get the list of commitRefs to sync | |
gitSyncCommitRef = determineGitSyncPoint('', mercurial_repo_name) | |
print "commit sync ref: {}".format(gitSyncCommitRef) | |
# commitRefs = list(gitRepo.iter_commits('master', max_count=4)) | |
commitRefs = list(gitRepo.iter_commits("{}..HEAD".format(gitSyncCommitRef))) | |
commitRefs.reverse() | |
# Iterate over each commit and unpack the objects into the target. | |
previousCommit = gitRepo.commit(gitSyncCommitRef) | |
for commitRef in commitRefs: | |
print "patching commit {}".format(commitRef) | |
commit = gitRepo.commit(commitRef) | |
diffIndex = previousCommit.diff(commit) | |
for added in diffIndex.iter_change_type('A'): | |
processAddition(added) | |
for deleted in diffIndex.iter_change_type('D'): | |
processDeletion(deleted) | |
for renamed in diffIndex.iter_change_type('R'): | |
processRenamed(renamed) | |
for modified in diffIndex.iter_change_type('M'): | |
processModification(modified) | |
try: | |
hgRepo.publish('Synchronized with git rev {}\nAuthor: {}\n{}'.format(commitRef.__str__()[:8], commit.author, commit.message)) | |
except UnicodeEncodeError: | |
hgRepo.publish('Synchronized with git rev {}\n'.format(commitRef.__str__()[:8])) | |
previousCommit = commit | |
if __name__ == '__main__': | |
parser = OptionParser() | |
parser.add_option("-n", "--nopush", | |
action="store_true", default=True, | |
help="Commit the changes locally only, don't push them") | |
parser.add_option("-q", "--quiet", | |
action="store_true", default=False, | |
help="Don't ask for confirmation before commiting or pushing") | |
(options, args) = parser.parse_args() | |
global push_remote, quiet, repo_name, mercurial_repo_name | |
push_remote = not options.nopush | |
quiet = options.quiet | |
assert len(args) == 2 | |
repo_name = args[0] | |
mercurial_repo_name = args[1] | |
assert exists(repo_name) | |
assert exists(mercurial_repo_name) | |
doSync(options, repo_name, mercurial_repo_name) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment