From 69095b74919045e49922b9be8b8016ff2d95a80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com> Date: Sat, 3 Apr 2021 06:29:23 +0200 Subject: [PATCH] grid: note git revision when installing from a git checkout Installing from a git checkout is a bad practice for production, but it's a common thing during development. One problem I often face is that I have a software release installed from a given revision and I want to make a small change to the software, but not recompile everything. To achieve this, I need to use the exact same git revision that was installed before, but most of the time, I don't remember what revision I have been using last time I installed. This change is about adding a buildout comment in the generated buildout.cfg made to install the profile, with the revision that was used for installing, so that we can re-install the same software again. --- slapos/grid/SlapObject.py | 28 ++++++++++++++++++++++++++++ slapos/tests/test_object.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/slapos/grid/SlapObject.py b/slapos/grid/SlapObject.py index b6463080e..580d927d2 100644 --- a/slapos/grid/SlapObject.py +++ b/slapos/grid/SlapObject.py @@ -28,6 +28,7 @@ # ############################################################################## +import datetime import errno import os import pkg_resources @@ -284,6 +285,7 @@ class Software(object): buildout_cfg = os.path.join(self.software_path, 'buildout.cfg') if not os.path.exists(buildout_cfg): self._create_buildout_profile(buildout_cfg, self.url, self.shared_part_list) + self._note_git_revision(buildout_cfg, self.url) additional_parameters = list(self._additional_buildout_parameters(extends_cache)) additional_parameters.extend(['-c', buildout_cfg]) @@ -327,6 +329,32 @@ class Software(object): parser.write(fout) self._set_ownership(buildout_cfg) + def _note_git_revision(self, buildout_cfg, url): + """Add a comment with the revision if the profile is a git checkout. + + This makes it easier to rebuild the same revision. + """ + git_revision = None + if os.path.exists(url): + try: + git_revision = subprocess.check_output( + ('git', 'describe', '--all', '--long', '--dirty'), + cwd=os.path.dirname(url), + ).decode() + except (OSError, subprocess.CalledProcessError): + self.logger.debug( + 'Error guessing git revision for profile %s', + url, + exc_info=True) + if git_revision: + with open(buildout_cfg) as f: + if git_revision in f.readlines()[-1]: + self.logger.debug('Current revision was already noted') + return + with open(buildout_cfg, 'a') as f: + f.write( + "# %s git revision: %s" % (datetime.datetime.utcnow(), git_revision)) + def uploadSoftwareRelease(self, tarpath): """ Try to tar and upload an installed Software Release. diff --git a/slapos/tests/test_object.py b/slapos/tests/test_object.py index 456bbc1ff..3d6cb32a8 100644 --- a/slapos/tests/test_object.py +++ b/slapos/tests/test_object.py @@ -27,8 +27,11 @@ import logging import os +import subprocess import time import unittest +import shutil +import tempfile from slapos.slap import ComputerPartition as SlapComputerPartition @@ -333,6 +336,34 @@ class TestSoftwareNetworkCacheSlapObject(MasterMixin, unittest.TestCase): software.install() self.assertTrue(getattr(self, 'uploaded', False)) + def test_software_install_note_git_revision(self): + tmpdir = tempfile.mkdtemp() + self.addCleanup(shutil.rmtree, tmpdir) + + subprocess.check_call(('git', 'init'), cwd=tmpdir) + profile_url = os.path.join(tmpdir, 'software.cfg') + open(profile_url, 'w').close() + subprocess.check_call(('git', 'add', 'software.cfg'), cwd=tmpdir) + subprocess.check_call( + ('git', 'commit', '-m', 'first commit'), + cwd=tmpdir, + env=dict( + os.environ, + GIT_AUTHOR_NAME='nobody', + GIT_AUTHOR_EMAIL='nobody@example.com', + GIT_COMMITTER_NAME='nobody', + GIT_COMMITTER_EMAIL='nobody@example.com',)) + + software = Software( + url=profile_url, + software_root=self.software_root, + buildout=self.buildout, + logger=logging.getLogger()) + software.install() + with open(os.path.join(software.software_path, 'buildout.cfg')) as f: + self.assertIn("git revision: heads/master-0-g", f.read()) + + class TestPartitionSlapObject(MasterMixin, unittest.TestCase): def setUp(self): MasterMixin.setUp(self) -- 2.30.9