Source code for craftr.ext.git

# -*- mode: python -*-
# Copyright (C) 2016  Niklas Rosenstein
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
'''
A very small interface for querying information about a Git repository.

Examples
--------

Display a note in console if build is started with unversioned changes
in the Git repository.

.. code:: python

  git = load_module('git').Git(project_dir)
  info('Current Version:', git.describe())
  if git.status(exclude='??'):
    info('Unversioned changes present.')

Export a ``GIT_VERSION.h`` header file into the build directory (not
to mess with your source tree!)

.. code:: python

  from craftr import *
  from craftr.ext import git

  def write_gitversion():
    filename = path.buildlocal('include/GIT_VERSION.h')
    dirname = path.dirname(filename)
    if session.export:
      path.makedirs(dirname)
      description = git.Git(project_dir).describe()
      with open(filename, 'w') as fp:
        fp.write('#pragma once\\n#define GIT_VERSION "{}"\\n'.format(description))
    return dirname

  gitversion_dir = write_gitversion()  # Add this to your includes

Classes
-------

.. autoclass:: Git
  :members:
  :undoc-members:
'''

__all__ = ['Git']

from craftr import shell


[docs]class Git(object): def __init__(self, git_dir): super().__init__() self.git_dir = git_dir def _popen(self, *args, **kwargs): return shell.pipe(*args, check=True, merge=False, cwd=self.git_dir, **kwargs)
[docs] def status(self, include=None, exclude=None): result = [] output = self._popen(['git', 'status', '--porcelain']).stdout for line in output.split('\n'): status, filename = line[:2].strip(), line[3:] if not status or not filename: continue if include is not None and status not in include: continue if exclude is not None and status in exclude: continue result.append((status, filename)) return result
[docs] def describe(self, mode='tags', all=False, fallback=True): if mode not in ('tags', 'contains'): raise ValueError('invalid describe mode {!r}'.format(mode)) command = ['git', 'describe', '--{}'.format(mode)] if all: command.append('--all') try: return self._popen(command).stdout.strip() except shell.CalledProcessError as exc: if fallback and 'No names found' in exc.stderr: # Let's create an alternative description instead. sha = self._popen(['git', 'rev-parse', 'HEAD']).output[:7] count = int(self._popen(['git', 'rev-list', 'HEAD', '--count']).output.strip()) return '{}-{}'.format(count, sha) raise
[docs] def branches(self): command = ['git', 'branch'] for line in self._popen(command).stdout.split('\n'): parts = line.split() if len(parts) == 2: yield parts else: yield ['', parts[0]]
[docs] def branch(self): command = ['git', 'symbolic-ref', '--short', 'HEAD'] try: return self._popen(command).stdout.strip() except Process.ExitCodeError as exc: raise ValueError(exc.process.stderr.strip())