source: rtems-source-builder/source-builder/sb/git.py @ 5601b9c

4.104.114.95
Last change on this file since 5601b9c was 5601b9c, checked in by Chris Johns <chrisj@…>, on 02/04/14 at 07:22:03

sb: Add submodule support to the git support.

  • Property mode set to 100644
File size: 6.5 KB
Line 
1#
2# RTEMS Tools Project (http://www.rtems.org/)
3# Copyright 2010-2013 Chris Johns (chrisj@rtems.org)
4# All rights reserved.
5#
6# This file is part of the RTEMS Tools package in 'rtems-tools'.
7#
8# Permission to use, copy, modify, and/or distribute this software for any
9# purpose with or without fee is hereby granted, provided that the above
10# copyright notice and this permission notice appear in all copies.
11#
12# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#
21# Provide some basic access to the git command.
22#
23
24import os
25
26import error
27import execute
28import log
29import options
30import path
31
32class repo:
33    """An object to manage a git repo."""
34
35    def _git_exit_code(self, ec):
36        if ec:
37            raise error.general('git command failed (%s): %d' % (self.git, ec))
38
39    def _run(self, args, check = False):
40        e = execute.capture_execution()
41        if path.exists(self.path):
42            cwd = self.path
43        else:
44            cwd = None
45        cmd = [self.git] + args
46        log.trace('cmd: (%s) %s' % (str(cwd), ' '.join(cmd)))
47        exit_code, proc, output = e.spawn(cmd, cwd = path.host(cwd))
48        log.trace(output)
49        if check:
50            self._git_exit_code(exit_code)
51        return exit_code, output
52
53    def __init__(self, _path, opts, macros = None):
54        self.path = _path
55        self.opts = opts
56        if macros is None:
57            self.macros = opts.defaults
58        else:
59            self.macros = macros
60        self.git = self.macros.expand('%{__git}')
61
62    def git_version(self):
63        ec, output = self._run(['--version'], True)
64        gvs = output.split()
65        if len(gvs) < 3:
66            raise error.general('invalid version string from git: %s' % (output))
67        vs = gvs[2].split('.')
68        if len(vs) != 4:
69            raise error.general('invalid version number from git: %s' % (gvs[2]))
70        return (int(vs[0]), int(vs[1]), int(vs[2]), int(vs[3]))
71
72    def clone(self, url, _path):
73        ec, output = self._run(['clone', url, path.host(_path)], check = True)
74
75    def fetch(self):
76        ec, output = self._run(['fetch'], check = True)
77
78    def pull(self):
79        ec, output = self._run(['pull'], check = True)
80
81    def reset(self, args):
82        if type(args) == str:
83            args = [args]
84        ec, output = self._run(['reset'] + args, check = True)
85
86    def branch(self):
87        ec, output = self._run(['branch'])
88        if ec == 0:
89            for b in output.split('\n'):
90                if b[0] == '*':
91                    return b[2:]
92        return None
93
94    def checkout(self, branch = 'master'):
95        ec, output = self._run(['checkout', branch], check = True)
96
97    def submodule(self, module):
98        ec, output = self._run(['submodule', 'update', '--init', module], check = True)
99
100    def status(self):
101        _status = {}
102        if path.exists(self.path):
103            ec, output = self._run(['status'])
104            if ec == 0:
105                state = 'none'
106                for l in output.split('\n'):
107                    if l.startswith('# On branch '):
108                        _status['branch'] = l[len('# On branch '):]
109                    elif l.startswith('# Changes to be committed:'):
110                        state = 'staged'
111                    elif l.startswith('# Changes not staged for commit:'):
112                        state = 'unstaged'
113                    elif l.startswith('# Untracked files:'):
114                        state = 'untracked'
115                    elif l.startswith('# HEAD detached'):
116                        state = 'detached'
117                    elif state != 'none' and l[0] == '#':
118                        if l.strip() != '#' and not l.startswith('#   ('):
119                            if state not in _status:
120                                _status[state] = []
121                            l = l[1:]
122                            if ':' in l:
123                                l = l.split(':')[1]
124                            _status[state] += [l.strip()]
125        return _status
126
127    def clean(self):
128        _status = self.status()
129        return len(_status) == 1 and 'branch' in _status
130
131    def valid(self):
132        if path.exists(self.path):
133            ec, output = self._run(['status'])
134            return ec == 0
135        return False
136
137    def remotes(self):
138        _remotes = {}
139        ec, output = self._run(['config', '--list'])
140        if ec == 0:
141            for l in output.split('\n'):
142                if l.startswith('remote'):
143                    ls = l.split('=')
144                    if len(ls) >= 2:
145                        rs = ls[0].split('.')
146                        if len(rs) == 3:
147                            r_name = rs[1]
148                            r_type = rs[2]
149                            if r_name not in _remotes:
150                                _remotes[r_name] = {}
151                            if r_type not in _remotes[r_name]:
152                                _remotes[r_name][r_type] = []
153                            _remotes[r_name][r_type] = '='.join(ls[1:])
154        return _remotes
155
156    def email(self):
157        _email = None
158        _name = None
159        ec, output = self._run(['config', '--list'])
160        if ec == 0:
161            for l in output.split('\n'):
162                if l.startswith('user.email'):
163                    ls = l.split('=')
164                    if len(ls) >= 2:
165                        _email = ls[1]
166                elif l.startswith('user.name'):
167                    ls = l.split('=')
168                    if len(ls) >= 2:
169                        _name = ls[1]
170        if _email is not None:
171            if _name is not None:
172                _email = '%s <%s>' % (_name, _email)
173            return _email
174        return None
175
176    def head(self):
177        hash = ''
178        ec, output = self._run(['log', '-n', '1'])
179        if ec == 0:
180            l1 = output.split('\n')[0]
181            if l1.startswith('commit '):
182                hash = l1[len('commit '):]
183        return hash
184
185if __name__ == '__main__':
186    import sys
187    opts = options.load(sys.argv)
188    g = repo('.', opts)
189    print g.git_version()
190    print g.valid()
191    print g.status()
192    print g.clean()
193    print g.remotes()
194    print g.email()
195    print g.head()
Note: See TracBrowser for help on using the repository browser.