| # ex:ts=4:sw=4:sts=4:et |
| # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- |
| """ |
| BitBake 'Fetch' git submodules implementation |
| |
| Inherits from and extends the Git fetcher to retrieve submodules of a git repository |
| after cloning. |
| |
| SRC_URI = "gitsm://<see Git fetcher for syntax>" |
| |
| See the Git fetcher, git://, for usage documentation. |
| |
| NOTE: Switching a SRC_URI from "git://" to "gitsm://" requires a clean of your recipe. |
| |
| """ |
| |
| # Copyright (C) 2013 Richard Purdie |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License version 2 as |
| # published by the Free Software Foundation. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License along |
| # with this program; if not, write to the Free Software Foundation, Inc., |
| # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| |
| import os |
| import bb |
| from bb import data |
| from bb.fetch2.git import Git |
| from bb.fetch2 import runfetchcmd |
| from bb.fetch2 import logger |
| |
| class GitSM(Git): |
| def supports(self, ud, d): |
| """ |
| Check to see if a given url can be fetched with git. |
| """ |
| return ud.type in ['gitsm'] |
| |
| def uses_submodules(self, ud, d): |
| for name in ud.names: |
| try: |
| runfetchcmd("%s show %s:.gitmodules" % (ud.basecmd, ud.revisions[name]), d, quiet=True) |
| return True |
| except bb.fetch.FetchError: |
| pass |
| return False |
| |
| def _set_relative_paths(self, repopath): |
| """ |
| Fix submodule paths to be relative instead of absolute, |
| so that when we move the repo it doesn't break |
| (In Git 1.7.10+ this is done automatically) |
| """ |
| submodules = [] |
| with open(os.path.join(repopath, '.gitmodules'), 'r') as f: |
| for line in f.readlines(): |
| if line.startswith('[submodule'): |
| submodules.append(line.split('"')[1]) |
| |
| for module in submodules: |
| repo_conf = os.path.join(repopath, module, '.git') |
| if os.path.exists(repo_conf): |
| with open(repo_conf, 'r') as f: |
| lines = f.readlines() |
| newpath = '' |
| for i, line in enumerate(lines): |
| if line.startswith('gitdir:'): |
| oldpath = line.split(': ')[-1].rstrip() |
| if oldpath.startswith('/'): |
| newpath = '../' * (module.count('/') + 1) + '.git/modules/' + module |
| lines[i] = 'gitdir: %s\n' % newpath |
| break |
| if newpath: |
| with open(repo_conf, 'w') as f: |
| for line in lines: |
| f.write(line) |
| |
| repo_conf2 = os.path.join(repopath, '.git', 'modules', module, 'config') |
| if os.path.exists(repo_conf2): |
| with open(repo_conf2, 'r') as f: |
| lines = f.readlines() |
| newpath = '' |
| for i, line in enumerate(lines): |
| if line.lstrip().startswith('worktree = '): |
| oldpath = line.split(' = ')[-1].rstrip() |
| if oldpath.startswith('/'): |
| newpath = '../' * (module.count('/') + 3) + module |
| lines[i] = '\tworktree = %s\n' % newpath |
| break |
| if newpath: |
| with open(repo_conf2, 'w') as f: |
| for line in lines: |
| f.write(line) |
| |
| def update_submodules(self, ud, d): |
| # We have to convert bare -> full repo, do the submodule bit, then convert back |
| tmpclonedir = ud.clonedir + ".tmp" |
| gitdir = tmpclonedir + os.sep + ".git" |
| bb.utils.remove(tmpclonedir, True) |
| os.mkdir(tmpclonedir) |
| os.rename(ud.clonedir, gitdir) |
| runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*true/bare = false/'", d) |
| os.chdir(tmpclonedir) |
| runfetchcmd(ud.basecmd + " reset --hard", d) |
| runfetchcmd(ud.basecmd + " checkout " + ud.revisions[ud.names[0]], d) |
| runfetchcmd(ud.basecmd + " submodule init", d) |
| runfetchcmd(ud.basecmd + " submodule update", d) |
| self._set_relative_paths(tmpclonedir) |
| runfetchcmd("sed " + gitdir + "/config -i -e 's/bare.*=.*false/bare = true/'", d) |
| os.rename(gitdir, ud.clonedir,) |
| bb.utils.remove(tmpclonedir, True) |
| |
| def download(self, ud, d): |
| Git.download(self, ud, d) |
| |
| os.chdir(ud.clonedir) |
| submodules = self.uses_submodules(ud, d) |
| if submodules: |
| self.update_submodules(ud, d) |
| |
| def unpack(self, ud, destdir, d): |
| Git.unpack(self, ud, destdir, d) |
| |
| os.chdir(ud.destdir) |
| submodules = self.uses_submodules(ud, d) |
| if submodules: |
| runfetchcmd("cp -r " + ud.clonedir + "/modules " + ud.destdir + "/.git/", d) |
| runfetchcmd(ud.basecmd + " submodule init", d) |
| runfetchcmd(ud.basecmd + " submodule update", d) |
| |