[PATCH v2 5/5] binman: Make the tooldir configurable

Simon Glass sjg at chromium.org
Wed Feb 22 20:14:49 CET 2023


Add a command-line argument for setting the tooldir, so that the default
can be overridden. Add this directory to the toolpath automatically.
Create the directory if it does not already exist.

Put the default in the argument parser instead of the class, so that it
is more obvious.

Update a few tests that expect the utility name to be provided without
any path (e.g. 'futility'), so they can accept a path, e.g.
/path/to/futility

Update the documentation and add a few tests.

Improve the help for --toolpath while we are here.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v2:
- Add comment about setting of tooldir
- Change default tooldir to an empty string
- Use exist_ok with os.makedirs()

 tools/binman/binman.rst      | 19 +++++++++++++++----
 tools/binman/bintool.py      | 11 +++++++++--
 tools/binman/bintool_test.py | 11 ++++++++---
 tools/binman/cmdline.py      |  6 +++++-
 tools/binman/control.py      | 10 ++++++++--
 tools/binman/ftest.py        | 21 +++++++++++++++++++--
 6 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 29034da92f1..3b0a9c38d72 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -1407,7 +1407,15 @@ You can also use `--fetch all` to fetch all tools or `--fetch <tool>` to fetch
 a particular tool. Some tools are built from source code, in which case you will
 need to have at least the `build-essential` and `git` packages installed.
 
-Tools are fetched into the `~/.binman-tools` directory.
+Tools are fetched into the `~/.binman-tools` directory. This directory is
+automatically added to the toolpath so there is no need to use `--toolpath` to
+specify it. If you want to use these tools outside binman, you may want to
+add this directory to your `PATH`. For example, if you use bash, add this to
+the end of `.bashrc`::
+
+   PATH="$HOME/.binman-tools:$PATH"
+
+To select a custom directory, use the `--tooldir` option.
 
 Bintool Documentation
 =====================
@@ -1427,8 +1435,9 @@ Binman commands and arguments
 
 Usage::
 
-    binman [-h] [-B BUILD_DIR] [-D] [-H] [--toolpath TOOLPATH] [-T THREADS]
-        [--test-section-timeout] [-v VERBOSITY] [-V]
+    binman [-h] [-B BUILD_DIR] [-D] [--tooldir TOOLDIR] [-H]
+        [--toolpath TOOLPATH] [-T THREADS] [--test-section-timeout]
+        [-v VERBOSITY] [-V]
         {build,bintool-docs,entry-docs,ls,extract,replace,test,tool} ...
 
 Binman provides the following commands:
@@ -1453,11 +1462,13 @@ Options:
 -D, --debug
     Enabling debugging (provides a full traceback on error)
 
+--tooldir TOOLDIR     Set the directory to store tools
+
 -H, --full-help
     Display the README file
 
 --toolpath TOOLPATH
-    Add a path to the directories containing tools
+    Add a path to the list of directories containing tools
 
 -T THREADS, --threads THREADS
     Number of threads to use (0=single-thread). Note that -T0 is useful for
diff --git a/tools/binman/bintool.py b/tools/binman/bintool.py
index 6ca3d886200..7674dfdf7bd 100644
--- a/tools/binman/bintool.py
+++ b/tools/binman/bintool.py
@@ -51,8 +51,9 @@ class Bintool:
     # List of bintools to regard as missing
     missing_list = []
 
-    # Directory to store tools
-    tooldir = os.path.join(os.getenv('HOME'), '.binman-tools')
+    # Directory to store tools. Note that this set up by set_tool_dir() which
+    # must be called before this class is used.
+    tooldir = ''
 
     def __init__(self, name, desc, version_regex=None, version_args='-V'):
         self.name = name
@@ -113,6 +114,11 @@ class Bintool:
         obj = cls(name)
         return obj
 
+    @classmethod
+    def set_tool_dir(cls, pathname):
+        """Set the path to use to store and find tools"""
+        cls.tooldir = pathname
+
     def show(self):
         """Show a line of information about a bintool"""
         if self.is_present():
@@ -210,6 +216,7 @@ class Bintool:
         if result is not True:
             fname, tmpdir = result
             dest = os.path.join(self.tooldir, self.name)
+            os.makedirs(self.tooldir, exist_ok=True)
             print(f"- writing to '{dest}'")
             shutil.move(fname, dest)
             if tmpdir:
diff --git a/tools/binman/bintool_test.py b/tools/binman/bintool_test.py
index 57e866eff93..39e4fb13e92 100644
--- a/tools/binman/bintool_test.py
+++ b/tools/binman/bintool_test.py
@@ -134,8 +134,10 @@ class TestBintool(unittest.TestCase):
         dirname = os.path.join(self._indir, 'download_dir')
         os.mkdir(dirname)
         fname = os.path.join(dirname, 'downloaded')
+
+        # Rely on bintool to create this directory
         destdir = os.path.join(self._indir, 'dest_dir')
-        os.mkdir(destdir)
+
         dest_fname = os.path.join(destdir, '_testing')
         self.seq = 0
 
@@ -344,8 +346,11 @@ class TestBintool(unittest.TestCase):
 
     def test_failed_command(self):
         """Check that running a command that does not exist returns None"""
-        btool = Bintool.create('_testing')
-        result = btool.run_cmd_result('fred')
+        destdir = os.path.join(self._indir, 'dest_dir')
+        os.mkdir(destdir)
+        with unittest.mock.patch.object(bintool.Bintool, 'tooldir', destdir):
+            btool = Bintool.create('_testing')
+            result = btool.run_cmd_result('fred')
         self.assertIsNone(result)
 
 
diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py
index 986d6f1a315..4eed3073dce 100644
--- a/tools/binman/cmdline.py
+++ b/tools/binman/cmdline.py
@@ -7,6 +7,7 @@
 
 import argparse
 from argparse import ArgumentParser
+import os
 from binman import state
 
 def make_extract_parser(subparsers):
@@ -80,8 +81,11 @@ controlled by a description in the board device tree.'''
         help='Enabling debugging (provides a full traceback on error)')
     parser.add_argument('-H', '--full-help', action='store_true',
         default=False, help='Display the README file')
+    parser.add_argument('--tooldir', type=str,
+        default=os.path.join(os.getenv('HOME'), '.binman-tools'),
+        help='Set the directory to store tools')
     parser.add_argument('--toolpath', type=str, action='append',
-        help='Add a path to the directories containing tools')
+        help='Add a path to the list of directories containing tools')
     parser.add_argument('-T', '--threads', type=int,
           default=None, help='Number of threads to use (0=single-thread)')
     parser.add_argument('--test-section-timeout', action='store_true',
diff --git a/tools/binman/control.py b/tools/binman/control.py
index e64740094f6..abe01b76773 100644
--- a/tools/binman/control.py
+++ b/tools/binman/control.py
@@ -650,6 +650,14 @@ def Binman(args):
     from binman.image import Image
     from binman import state
 
+    tool_paths = []
+    if args.toolpath:
+        tool_paths += args.toolpath
+    if args.tooldir:
+        tool_paths.append(args.tooldir)
+    tools.set_tool_paths(tool_paths or None)
+    bintool.Bintool.set_tool_dir(args.tooldir)
+
     if args.cmd in ['ls', 'extract', 'replace', 'tool']:
         try:
             tout.init(args.verbosity)
@@ -667,7 +675,6 @@ def Binman(args):
                                allow_resize=not args.fix_size, write_map=args.map)
 
             if args.cmd == 'tool':
-                tools.set_tool_paths(args.toolpath)
                 if args.list:
                     bintool.Bintool.list_all()
                 elif args.fetch:
@@ -719,7 +726,6 @@ def Binman(args):
         try:
             tools.set_input_dirs(args.indir)
             tools.prepare_output_dir(args.outdir, args.preserve)
-            tools.set_tool_paths(args.toolpath)
             state.SetEntryArgs(args.entry_arg)
             state.SetThreads(args.threads)
 
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 062f54adb0e..7fe0ba4f3aa 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -1750,7 +1750,7 @@ class TestFunctional(unittest.TestCase):
 
     def _HandleGbbCommand(self, pipe_list):
         """Fake calls to the futility utility"""
-        if pipe_list[0][0] == 'futility':
+        if 'futility' in pipe_list[0][0]:
             fname = pipe_list[0][-1]
             # Append our GBB data to the file, which will happen every time the
             # futility command is called.
@@ -1812,7 +1812,7 @@ class TestFunctional(unittest.TestCase):
         self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
         of the input data (here, 'input.vblock').
         """
-        if pipe_list[0][0] == 'futility':
+        if 'futility' in pipe_list[0][0]:
             fname = pipe_list[0][3]
             with open(fname, 'wb') as fd:
                 if self._hash_data:
@@ -6386,6 +6386,23 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
         self.assertEqual(['u-boot', 'atf-2'],
                          fdt_util.GetStringList(node, 'loadables'))
 
+    def testTooldir(self):
+        """Test that we can specify the tooldir"""
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
+                                               'tool', '-l'))
+        self.assertEqual('fred', bintool.Bintool.tooldir)
+
+        # Check that the toolpath is updated correctly
+        self.assertEqual(['fred'], tools.tool_search_paths)
+
+        # Try with a few toolpaths; the tooldir should be at the end
+        with test_util.capture_sys_output() as (stdout, stderr):
+            self.assertEqual(0, self._DoBinman(
+                '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
+                'tool', '-l'))
+        self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
+
 
 if __name__ == "__main__":
     unittest.main()
-- 
2.39.2.637.g21b0678d19-goog



More information about the U-Boot mailing list