Skip to content

Instantly share code, notes, and snippets.

@niklasf
Created May 1, 2013 22:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niklasf/5498916 to your computer and use it in GitHub Desktop.
Save niklasf/5498916 to your computer and use it in GitHub Desktop.
Sample Git update hook that deploys the changed files to the web root.
#!/usr/bin/python
import logging
import git
import sys
import os
def main():
"""
Update all files according to a diff.
"""
# Configure logging.
logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(levelname)s: %(message)s')
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Start.
logging.info('Starting update hook.')
repo = git.Repo()
# Check arguments.
logging.debug('Arguments: %s', sys.argv)
assert len(sys.argv) == 4
if sys.argv[2] == '0000000000000000000000000000000000000000':
sys.argv[2] = repo.git.hash_object('-w', '-t', 'tree', os.devnull)
if sys.argv[3] == '0000000000000000000000000000000000000000':
sys.argv[3] = repo.git.hash_object('-w', '-t', 'tree', os.devnull)
# Iterate over the diff.
assert repo.bare == True
diff = repo.git.diff('--name-status', sys.argv[2], sys.argv[3])
tree = repo.commit(sys.argv[3]).tree
for line in diff.split("\n"):
if not line: continue
status, file = line.split("\t", 1)
assert status in ['A', 'D', 'M']
target = get_target(file)
logging.debug('%s %s -> %s', status, file, target)
if target:
if status == 'D':
# Unlink file.
os.unlink(target)
logging.info('Deleted %s', target)
# Remove parent dirs.
try:
os.removedirs(os.path.dirname(target))
logging.info('Cleaned away parent of %s', target)
except OSError:
logging.debug('Did not clean away parent of %s', target)
else:
# Create directories.
node = tree[file]
assert isinstance(node, git.Blob)
if status == 'A':
try:
os.makedirs(os.path.dirname(target))
logging.info('Created directory for %s', target)
except OSError:
logging.debug('Did not create directory for %s', target)
# Write blob.
node.stream_data(open(target, 'w'))
logging.info('Wrote %s', target)
else:
logging.info('Ignored %s', target)
# Done.
logging.info('update hook finished.')
def get_target(file):
"""
Returns the target by a given filename.
"""
splitpath = file.split(os.sep)
if splitpath[0] in ['www', 'local', 'tools', 'data']:
return os.path.join('/var', file)
else:
return False
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment