From 771fdd25f3755a835dc28113b203b8c201809913 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Feb 04 2020 12:52:23 +0000
Subject: [PATCH 1/3] add file-locking to koji-gc


Fixes: https://pagure.io/koji/issue/1332

---

diff --git a/util/koji-gc b/util/koji-gc
index 19d7e26..d8a5f88 100755
--- a/util/koji-gc
+++ b/util/koji-gc
@@ -7,7 +7,7 @@
 #       Mike McLean <mikem@redhat.com>
 
 from __future__ import absolute_import
-
+import fcntl
 import datetime
 import fnmatch
 import optparse
@@ -111,6 +111,9 @@ def get_options():
     parser.add_option("--weburl", default="http://localhost/koji", metavar="URL",
                       help=_("url of koji web server (for use in notifications)"))
     parser.add_option("-s", "--server", help=_("url of koji XMLRPC server"))
+    parser.add_option("--lock-file", help=_("koji-gc will wait while specified file exists"))
+    parser.add_option("--exit-on-lock", action="store_true",
+                      help=_("quit if --lock-file exists, don't wait"))
     #parse once to get the config file
     (options, args) = parser.parse_args()
 
@@ -148,6 +151,8 @@ def get_options():
         ['trashcan_tag', None, 'string'],
         ['no_ssl_verify', None, 'boolean'],
         ['timeout', None, 'integer'],
+            ['lock_file', None, 'string'],
+            ['exit_on_lock', None, 'boolean'],
         ]
     for name, alias, type in cfgmap:
         if alias is None:
@@ -954,12 +959,40 @@ if __name__ == "__main__":
 
     session_opts = koji.grab_session_options(options)
     session = koji.ClientSession(options.server, session_opts)
+
     rv = 0
     try:
+        lock_fd = None
+        if options.lock_file:
+            # acquire lock file
+            while not lock_fd:
+                # fail, if it is completely inaccessible
+                lock_fd = os.open(options.lock_file, os.O_CREAT | os.O_RDWR)
+                try:
+                    fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+                    break
+                except (IOError, OSError):
+                    if options.exit_on_lock:
+                        try:
+                            session.logout()
+                        except:
+                            pass
+                        sys.exit(1)
+                os.close(lock_fd)
+                lock_fd = None
+                if options.debug:
+                    print("Waiting on lock: %s" % options.lock_file)
+                time.sleep(10)
+
         if not options.skip_main:
             rv = main(args)
         if not rv:
             rv = 0
+
+        if lock_fd:
+            # release lock file
+            fcntl.flock(lock_fd, fcntl.LOCK_UN)
+            os.close(lock_fd)
     except KeyboardInterrupt:
         pass
     except SystemExit:

From 3367c6e1535b0211ac9e1066f70c288a557856bf Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Feb 04 2020 12:53:30 +0000
Subject: [PATCH 2/3] default value for --lock-file option


---

diff --git a/util/koji-gc b/util/koji-gc
index d8a5f88..8a3d5a9 100755
--- a/util/koji-gc
+++ b/util/koji-gc
@@ -111,7 +111,8 @@ def get_options():
     parser.add_option("--weburl", default="http://localhost/koji", metavar="URL",
                       help=_("url of koji web server (for use in notifications)"))
     parser.add_option("-s", "--server", help=_("url of koji XMLRPC server"))
-    parser.add_option("--lock-file", help=_("koji-gc will wait while specified file exists"))
+    parser.add_option("--lock-file", help=_("koji-gc will wait while specified file exists. "
+                                            "Default path is /run/user/<uid>/koji-gc.lock"))
     parser.add_option("--exit-on-lock", action="store_true",
                       help=_("quit if --lock-file exists, don't wait"))
     #parse once to get the config file
@@ -963,26 +964,27 @@ if __name__ == "__main__":
     rv = 0
     try:
         lock_fd = None
-        if options.lock_file:
-            # acquire lock file
-            while not lock_fd:
-                # fail, if it is completely inaccessible
-                lock_fd = os.open(options.lock_file, os.O_CREAT | os.O_RDWR)
-                try:
-                    fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
-                    break
-                except (IOError, OSError):
-                    if options.exit_on_lock:
-                        try:
-                            session.logout()
-                        except:
-                            pass
-                        sys.exit(1)
-                os.close(lock_fd)
-                lock_fd = None
-                if options.debug:
-                    print("Waiting on lock: %s" % options.lock_file)
-                time.sleep(10)
+        if not options.lock_file:
+            options.lock_file = '/run/user/%d/koji-gc.lock' % os.getuid()
+        # acquire lock file
+        while not lock_fd:
+            # fail, if it is completely inaccessible
+            lock_fd = os.open(options.lock_file, os.O_CREAT | os.O_RDWR)
+            try:
+                fcntl.flock(lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+                break
+            except (IOError, OSError):
+                if options.exit_on_lock:
+                    try:
+                        session.logout()
+                    except:
+                        pass
+                    sys.exit(1)
+            os.close(lock_fd)
+            lock_fd = None
+            if options.debug:
+                print("Waiting on lock: %s" % options.lock_file)
+            time.sleep(10)
 
         if not options.skip_main:
             rv = main(args)

From e9ed8bdd954b58a162ff8b066e5417df3c72db3e Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Feb 10 2020 14:22:30 +0000
Subject: [PATCH 3/3] more detailed help message


---

diff --git a/util/koji-gc b/util/koji-gc
index 8a3d5a9..1f04f4a 100755
--- a/util/koji-gc
+++ b/util/koji-gc
@@ -112,7 +112,9 @@ def get_options():
                       help=_("url of koji web server (for use in notifications)"))
     parser.add_option("-s", "--server", help=_("url of koji XMLRPC server"))
     parser.add_option("--lock-file", help=_("koji-gc will wait while specified file exists. "
-                                            "Default path is /run/user/<uid>/koji-gc.lock"))
+                                            "Default path is /run/user/<uid>/koji-gc.lock. "
+                                            "For service usage /var/lock/koji-gc.lock is "
+                                            "recommended."))
     parser.add_option("--exit-on-lock", action="store_true",
                       help=_("quit if --lock-file exists, don't wait"))
     #parse once to get the config file

