From f00dce842565498ea6cdb69dd316f06350577f66 Mon Sep 17 00:00:00 2001 From: Ozan Unsal Date: Feb 03 2022 13:02:29 +0000 Subject: Create a tool to update short latest symlinks automatically JIRA: RHELCMP-4378 Signed-off-by: Ozan Unsal --- diff --git a/README.rst b/README.rst index 087b8dd..366216a 100644 --- a/README.rst +++ b/README.rst @@ -48,6 +48,8 @@ Contents **compose-write-repo-file** create a `.repo` file pointing to repositories in a compose +**compose-update-latest-symlinks** + create symbolic links of minor and major version to the given latest compose Related tools ------------- diff --git a/bin/compose-update-latest-symlinks b/bin/compose-update-latest-symlinks new file mode 100755 index 0000000..fbba229 --- /dev/null +++ b/bin/compose-update-latest-symlinks @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import argparse +import os +import sys + +here = sys.path[0] +if here != "/usr/bin": + sys.path.insert(0, os.path.dirname(here)) + +from pathlib import Path +from compose_utils import symlink + + +def main(args): + parser = argparse.ArgumentParser() + parser.add_argument( + "-p", + "--path", + type=Path, + help="Path to the generated composes", + required=True, + ) + args = parser.parse_args() + symlink.update_symlinks(args.path) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/compose_utils/symlink.py b/compose_utils/symlink.py index 35de469..33f2453 100644 --- a/compose_utils/symlink.py +++ b/compose_utils/symlink.py @@ -6,7 +6,8 @@ The `minor_version` argument was deprecated in 0.1.27 and should be removed in 0 import os import warnings - +import sys +import re import productmd @@ -94,3 +95,32 @@ def _deprecated_arg(arg, replace): warnings.warn( "%r argument is deprecated, use %r instead" % (arg, replace), DeprecationWarning ) + + +def update_symlinks(compose_path): + """Update the symlinks of the minor and major version of the compose""" + # Sorting filter for the symlink versions + def natsort(s): + return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\d+)', s)] + links = sorted(filter(lambda x: os.path.islink(os.path.join(compose_path, x)), os.listdir(compose_path)), key=natsort) + if not links: + warnings.warn("No full symlink of a compose found in the directory %s" % compose_path) + sys.exit(1) + latest_link = links[-1] + full_link = os.path.join(compose_path, latest_link) + tmp_link = full_link + for i in range(latest_link.count(".")): + version = tmp_link[:tmp_link.rfind(".")] + # Use the temp file in order to overwrite the existing symlinks + temp = os.path.join(compose_path, ".link.tmp") + # Create the symlink for the version + os.symlink( + os.path.relpath( + full_link, + compose_path + ), + temp + ) + os.rename(temp, version) + print("DONE: Create the symlink: %s" % version) + tmp_link = tmp_link[:tmp_link.rfind(".")] diff --git a/doc/compose-update-latest-symlinks.1 b/doc/compose-update-latest-symlinks.1 new file mode 100644 index 0000000..c3575b3 --- /dev/null +++ b/doc/compose-update-latest-symlinks.1 @@ -0,0 +1,26 @@ +.TH compose-update-latest-symlinks 1 +.SH NAME +compose-update-latest-symlinks \- Create the symbolic links of minor and major version to the given latest compose +.SH SYNOPSIS +.B compose-update-latest-symlinks +[\fIOPTIONS\fR...] +\fICOMPOSE_PATH\fR +.SH DESCRIPTION +.B compose-update-latest-symlinks +creates symbolic links of minor and major version pointing to the latest generated compose. + +It requires the compose path as an argument variable, which shows the path of generated composes. +.SH OPTIONS +.TP +.BR \-h ", " \-\-help +Print help and exit. +.TP +.BR \-p ", " \-\-path +The path of generated composes. +.SH EXIT CODE +This tool exits with status code of \fB0\fR on success and non-zero value on +failure. +.SH BUGS +Please report bugs at +.br +https://pagure.io/compose-utils/issues diff --git a/setup.py b/setup.py index 19b7478..db9f3a4 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ setup( 'bin/compose-print-essentials', 'bin/compose-report-package-moves', 'bin/compose-write-repo-file', + 'bin/compose-update-latest-symlinks', ], install_requires=[ 'productmd>=1.33', @@ -44,6 +45,7 @@ setup( 'doc/compose-print-essentials.1', 'doc/compose-report-package-moves.1', 'doc/compose-write-repo-file.1', + 'doc/compose-update-latest-symlinks.1', ]), ], include_package_data=True, diff --git a/tests/test_symlink.py b/tests/test_symlink.py index 5377458..b3227d5 100644 --- a/tests/test_symlink.py +++ b/tests/test_symlink.py @@ -123,3 +123,44 @@ class TestLatestSymlink(unittest.TestCase): with mock.patch('sys.stdout', new_callable=StringIO) as mock_out: symlink.print_latest_link(path, version_type=symlink.VersionType.MINOR) self.assertEqual(mock_out.getvalue(), 'latest-DP-1.0\n') + + +class TestUpdateSymlinks(unittest.TestCase): + def setUp(self): + self.compose_dir = tempfile.mkdtemp() + + def tearDown(self): + shutil.rmtree(self.compose_dir) + + def create_full_symlink(self, compose_id): + os.symlink('not-needed', os.path.join(self.compose_dir, compose_id)) + + def assert_symlink(self, name, dest): + link = os.path.join(self.compose_dir, name) + self.assertTrue(os.path.islink(link)) + self.assertEqual(os.readlink(link), dest) + + def test_two_component(self): + self.create_full_symlink('latest-DP-1.0') + + symlink.update_symlinks(self.compose_dir) + + self.assert_symlink('latest-DP-1', 'latest-DP-1.0') + + def test_three_component(self): + self.create_full_symlink('latest-DP-1.0.0') + + symlink.update_symlinks(self.compose_dir) + + self.assert_symlink('latest-DP-1', 'latest-DP-1.0.0') + self.assert_symlink('latest-DP-1.0', 'latest-DP-1.0.0') + + def test_scenario(self): + for y in range(1, 4): + self.create_full_symlink('latest-DP-1.%d.0' % y) + symlink.update_symlinks(self.compose_dir) + + self.assert_symlink('latest-DP-1', 'latest-DP-1.3.0') + self.assert_symlink('latest-DP-1.1', 'latest-DP-1.1.0') + self.assert_symlink('latest-DP-1.2', 'latest-DP-1.2.0') + self.assert_symlink('latest-DP-1.3', 'latest-DP-1.3.0')