Skip to content

Instantly share code, notes, and snippets.

@pan-
Created April 6, 2016 18:27
Show Gist options
  • Save pan-/9be5af8bcff3479bd2773137677fe66f to your computer and use it in GitHub Desktop.
Save pan-/9be5af8bcff3479bd2773137677fe66f to your computer and use it in GitHub Desktop.
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
#!/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