diff --git a/pre_commit/make_archives.py b/pre_commit/make_archives.py new file mode 100644 index 00000000..e989750b --- /dev/null +++ b/pre_commit/make_archives.py @@ -0,0 +1,65 @@ +from __future__ import absolute_import +from __future__ import print_function +from __future__ import unicode_literals + +import os.path +import shutil +from plumbum import local + +from pre_commit.util import tarfile_open +from pre_commit.util import tmpdir + + +# This is a script for generating the tarred resources for git repo +# dependencies. Currently it's just for "vendoring" ruby support packages. + + +REPOS = ( + ('rbenv', 'git://github.com/sstephenson/rbenv', '13a474c'), + ('ruby-build', 'git://github.com/sstephenson/ruby-build', 'd3d5fe0'), + ( + 'ruby-download', + 'git://github.com/garnieretienne/rvm-download', + 'f2e9f1e', + ), +) + + +RESOURCES_DIR = os.path.abspath( + os.path.join(os.path.dirname(__file__), 'resources') +) + + +def make_archive(name, repo, ref, destdir): + """Makes an archive of a repository in the given destdir. + + :param text name: Name to give the archive. For instance foo. The file + that is created will be called foo.tar.gz. + :param text repo: Repository to clone. + :param text ref: Tag/SHA/branch to check out. + :param text destdir: Directory to place archives in. + """ + output_path = os.path.join(destdir, name + '.tar.gz') + with tmpdir() as tempdir: + # Clone the repository to the temporary directory + local['git']('clone', repo, tempdir) + with local.cwd(tempdir): + local['git']('checkout', ref) + + # We don't want the '.git' directory + shutil.rmtree(os.path.join(tempdir, '.git')) + + with tarfile_open(output_path, 'w|gz') as tf: + tf.add(tempdir, name) + + return output_path + + +def main(): + for archive_name, repo, ref in REPOS: + print('Making {0}.tar.gz for {1}@{2}'.format(archive_name, repo, ref)) + make_archive(archive_name, repo, ref, RESOURCES_DIR) + + +if __name__ == '__main__': + exit(main()) diff --git a/pre_commit/util.py b/pre_commit/util.py index 4b625c27..03bd4a28 100644 --- a/pre_commit/util.py +++ b/pre_commit/util.py @@ -7,6 +7,8 @@ import os import os.path import shutil import sys +import tarfile +import tempfile def memoize_by_cwd(func): @@ -65,3 +67,25 @@ def hex_md5(s): :param text s: """ return hashlib.md5(s.encode('utf-8')).hexdigest() + + +@contextlib.contextmanager +def tarfile_open(*args, **kwargs): + """Compatibility layer because python2.6""" + tf = tarfile.open(*args, **kwargs) + try: + yield tf + finally: + tf.close() + + +@contextlib.contextmanager +def tmpdir(): + """Contextmanager to create a temporary directory. It will be cleaned up + afterwards. + """ + tempdir = tempfile.mkdtemp() + try: + yield tempdir + finally: + shutil.rmtree(tempdir) diff --git a/tests/make_archives_test.py b/tests/make_archives_test.py new file mode 100644 index 00000000..290a0caf --- /dev/null +++ b/tests/make_archives_test.py @@ -0,0 +1,62 @@ +from __future__ import absolute_import +from __future__ import unicode_literals + +import mock +import os.path +import pytest +from plumbum import local + +from pre_commit import make_archives +from pre_commit.util import tarfile_open +from testing.fixtures import git_dir +from testing.util import get_head_sha +from testing.util import skipif_slowtests_false + + +def test_make_archive(tmpdir_factory): + output_dir = tmpdir_factory.get() + git_path = git_dir(tmpdir_factory) + # Add a files to the git directory + with local.cwd(git_path): + local['touch']('foo') + local['git']('add', '.') + local['git']('commit', '-m', 'foo') + # We'll use this sha + head_sha = get_head_sha('.') + # And check that this file doesn't exist + local['touch']('bar') + local['git']('add', '.') + local['git']('commit', '-m', 'bar') + + # Do the thing + archive_path = make_archives.make_archive( + 'foo', git_path, head_sha, output_dir, + ) + + assert archive_path == os.path.join(output_dir, 'foo.tar.gz') + assert os.path.exists(archive_path) + + extract_dir = tmpdir_factory.get() + + # Extract the tar + with tarfile_open(archive_path) as tf: + tf.extractall(extract_dir) + + # Verify the contents of the tar + assert os.path.exists(os.path.join(extract_dir, 'foo')) + assert os.path.exists(os.path.join(extract_dir, 'foo', 'foo')) + assert not os.path.exists(os.path.join(extract_dir, 'foo', '.git')) + assert not os.path.exists(os.path.join(extract_dir, 'foo', 'bar')) + + +@skipif_slowtests_false +@pytest.mark.integration +def test_main(tmpdir_factory): + path = tmpdir_factory.get() + + # Don't actually want to make these in the current repo + with mock.patch.object(make_archives, 'RESOURCES_DIR', path): + make_archives.main() + + for archive, _, _ in make_archives.REPOS: + assert os.path.exists(os.path.join(path, archive + '.tar.gz')) diff --git a/tests/util_test.py b/tests/util_test.py index e406d604..b34b47ab 100644 --- a/tests/util_test.py +++ b/tests/util_test.py @@ -12,6 +12,7 @@ from pre_commit.util import clean_path_on_failure from pre_commit.util import entry from pre_commit.util import memoize_by_cwd from pre_commit.util import shell_escape +from pre_commit.util import tmpdir @pytest.fixture @@ -112,3 +113,9 @@ def test_clean_path_on_failure_cleans_for_system_exit(in_tmpdir): ) def test_shell_escape(input_str, expected): assert shell_escape(input_str) == expected + + +def test_tmpdir(): + with tmpdir() as tempdir: + assert os.path.exists(tempdir) + assert not os.path.exists(tempdir)