You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by no...@apache.org on 2020/12/29 12:24:56 UTC

[buildstream] 08/15: Allow cache quota to be set with human friendly input e.g. 2K

This is an automated email from the ASF dual-hosted git repository.

not-in-ldap pushed a commit to branch jennis/136-clean-remote-cache
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 5c38fa0ae26283333a9cd23a5a6192f6ccdd8265
Author: James Ennis <ja...@codethink.com>
AuthorDate: Thu Apr 26 16:07:37 2018 +0100

    Allow cache quota to be set with human friendly input e.g. 2K
    
    utils.py: Added _parse_size() function
    pushreceive.py: Altered receive_main() so that it now accepts
    human friendly input.
---
 buildstream/_artifactcache/pushreceive.py | 14 ++++++----
 buildstream/utils.py                      | 44 +++++++++++++++++++++++++++++++
 doc/source/artifacts.rst                  |  6 +++--
 3 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/buildstream/_artifactcache/pushreceive.py b/buildstream/_artifactcache/pushreceive.py
index d276c71..bcd2e4a 100644
--- a/buildstream/_artifactcache/pushreceive.py
+++ b/buildstream/_artifactcache/pushreceive.py
@@ -33,6 +33,7 @@ from urllib.parse import urlparse
 import click
 import gi
 
+from ..utils import _parse_size
 from .. import _signals  # nopep8
 from .._profile import Topics, profile_start, profile_end
 
@@ -573,7 +574,11 @@ class OSTreeReceiver(object):
     def __init__(self, repopath, pull_url, cache_quota):
         self.repopath = repopath
         self.pull_url = pull_url
-        self.cache_quota = cache_quota
+        if cache_quota:
+            # Parse the string and find the quota in bytes (int)
+            self.cache_quota = _parse_size(cache_quota, repopath)
+        else:
+            self.cache_quota = None
 
         if self.repopath is None:
             self.repo = OSTree.Repo.new_default()
@@ -800,8 +805,9 @@ def push(repo, remote, branches, output):
 @click.option('--debug', '-d', is_flag=True, default=False, help="Debug mode")
 @click.option('--pull-url', type=str, required=True,
               help="Clients who try to pull over SSH will be redirected here")
-@click.option('--cache-quota', type=int,
-              help="Implement a quota on the cache (in bytes) here")
+@click.option('--cache-quota', type=str,
+              help="Implement a cache quota. Accepted suffixes are: K, M, G, T "
+              "or no suffix (for bytes).\nExample: --cache-quota 20G for 20 Gb")
 @click.argument('repo')
 def receive_main(verbose, debug, pull_url, cache_quota, repo):
     """A BuildStream sister program for receiving artifacts send to a shared artifact cache
@@ -814,7 +820,5 @@ def receive_main(verbose, debug, pull_url, cache_quota, repo):
     logging.basicConfig(format='%(module)s: %(levelname)s: %(message)s',
                         level=loglevel, stream=sys.stderr)
 
-    # IDEA: have it so that cache_quota can allow human friendly input.
-
     receiver = OSTreeReceiver(repo, pull_url, cache_quota)
     return receiver.run()
diff --git a/buildstream/utils.py b/buildstream/utils.py
index e6e5989..c1aee35 100644
--- a/buildstream/utils.py
+++ b/buildstream/utils.py
@@ -1126,3 +1126,47 @@ def _deduplicate(iterable, key=None):
             if k not in seen:
                 seen_add(k)
                 yield element
+
+
+# _parse_size():
+#
+# Convert a string representing data size to a number of
+# bytes. E.g. "2K" -> 2048.
+#
+# This uses the same format as systemd's
+# [resource-control](https://www.freedesktop.org/software/systemd/man/systemd.resource-control.html#).
+#
+# Arguments:
+#     size (str) The string to parse
+#     volume (str) A path on the volume to consider for percentage
+#                  specifications
+#
+# Returns:
+#     (int|None) The number of bytes, or None if 'infinity' was specified.
+#
+# Raises:
+#     UtilError if the string is not a valid data size.
+#
+def _parse_size(size, volume):
+    if size == 'infinity':
+        return None
+
+    matches = re.fullmatch(r'([0-9]\.?[0-9]*)([KMGT%]?)', size)
+    if matches is None:
+        raise UtilError("{} is not a valid data size."
+                        "\nOptions are: K, M, G, T and %.".format(size))
+
+    num, unit = matches.groups()
+
+    if unit == '%':
+        num = float(num)
+        if num > 100:
+            raise UtilError("{}% is not a valid percentage value.".format(num))
+
+        stat_ = os.statvfs(volume)
+        disk_size = stat_.f_blocks * stat_.f_bsize
+
+        return disk_size * (num / 100)
+
+    units = ('', 'K', 'M', 'G', 'T')
+    return int(num) * 1024**units.index(unit)
diff --git a/doc/source/artifacts.rst b/doc/source/artifacts.rst
index f181c67..23a389f 100644
--- a/doc/source/artifacts.rst
+++ b/doc/source/artifacts.rst
@@ -160,8 +160,10 @@ For this you will want something like the following in your ``/etc/ssh/sshd_conf
 	# command must be specified here; 'artifacts' is
 	# the HOME relative path to the artifact cache.
 	# The exact pull URL must also be specified.
-	# A cache-quota is optional and should be specified in bytes
-	## FIXME: The above should have a function which converts 20G -> bytes...
+	# A cache-quota is optional and can either be specified
+	# by the exact integer, or in human friendly form,
+	# for example, a 20 GB quota is specified with "20G"
+
         ForceCommand bst-artifact-receive --pull-url https://example.com/artifacts --cache-quota quota_in_bytes --verbose artifacts