瀏覽代碼

Add idf.py --version option

Update docs on how to check IDF version
Show dependencies check information only in verbose mode
Sergei Silnov 6 年之前
父節點
當前提交
2d03af30ab
共有 3 個文件被更改,包括 101 次插入14 次删除
  1. 2 3
      docs/en/versions.rst
  2. 2 3
      docs/zh_CN/versions.rst
  3. 97 8
      tools/idf.py

+ 2 - 3
docs/en/versions.rst

@@ -59,10 +59,9 @@ ESP-IDF uses `Semantic Versioning <http://semver.org/>`_. This means that:
 Checking the Current Version
 ----------------------------
 
-The local ESP-IDF version can be checked by using git::
+The local ESP-IDF version can be checked by using idf.py::
 
-  cd $IDF_PATH
-  git describe --tags --dirty
+  idf.py --version
 
 The ESP-IDF version is also compiled into the firmware and can be accessed (as a string) via the macro ``IDF_VER``. The default ESP-IDF bootloader will print the version on boot (the version information is not always updated in code, it only changes if that particular source file is recompiled).
 

+ 2 - 3
docs/zh_CN/versions.rst

@@ -57,10 +57,9 @@ ESP-IDF 采用了 `语义版本管理方法 <http://semver.org/>`_,即您可
 查看当前版本
 ----------------------------
 
-查看 ESP-IDF 本地副本的版本,请使用 git 命令::
+查看 ESP-IDF 本地副本的版本,请使用 idf.py 命令::
 
-    cd $IDF_PATH
-    git describe --tags --dirty
+    idf.py --version
 
 此外,由于 ESP-IDF 的版本也已编译至固件中,因此您也可以使用宏 ``IDF_VER`` 查看 ESP-IDF 的版本(以字符串的格式)。ESP-IDF 默认引导程序可以在设备启动时打印 ESP-IDF 的版本,但注意代码中的版本信息仅会在源代码重新编译时才会更新,因此打印出来的版本可能并不是最新的。
 

+ 97 - 8
tools/idf.py

@@ -121,8 +121,13 @@ def check_environment():
 
     (cmake will check a lot of other things)
     """
+    checks_output = []
+
     if not executable_exists(["cmake", "--version"]):
+        print_idf_version()
         raise FatalError("'cmake' must be available on the PATH to use %s" % PROG)
+
+    # verify that IDF_PATH env variable is set
     # find the directory idf.py is in, then the parent directory of this, and assume this is IDF_PATH
     detected_idf_path = _realpath(os.path.join(os.path.dirname(__file__), ".."))
     if "IDF_PATH" in os.environ:
@@ -138,9 +143,9 @@ def check_environment():
         os.environ["IDF_PATH"] = detected_idf_path
 
     # check Python dependencies
-    print("Checking Python dependencies...")
+    checks_output.append("Checking Python dependencies...")
     try:
-        subprocess.check_call(
+        out = subprocess.check_output(
             [
                 os.environ["PYTHON"],
                 os.path.join(
@@ -149,9 +154,15 @@ def check_environment():
             ],
             env=os.environ,
         )
-    except subprocess.CalledProcessError:
+
+        checks_output.append(out.decode('utf-8','ignore').strip())
+    except subprocess.CalledProcessError as e:
+        print(e.output.decode('utf-8','ignore'))
+        print_idf_version()
         raise SystemExit(1)
 
+    return checks_output
+
 
 def executable_exists(args):
     try:
@@ -494,6 +505,71 @@ def _safe_relpath(path, start=None):
         return os.path.abspath(path)
 
 
+def _idf_version_from_cmake():
+    version_path = os.path.join(os.environ["IDF_PATH"], "tools/cmake/version.cmake")
+    regex = re.compile(r"^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)")
+    ver = {}
+    try:
+        with open(version_path) as f:
+            for line in f:
+                m = regex.match(line)
+
+                if m:
+                    ver[m.group(1)] = m.group(2)
+
+        return "v%s.%s.%s" % (ver["MAJOR"], ver["MINOR"], ver["PATCH"])
+    except (KeyError, OSError):
+        sys.stderr.write("WARNING: Cannot find ESP-IDF version in version.cmake\n")
+        return None
+
+
+def idf_version():
+    """Print version of ESP-IDF"""
+
+    #  Try to get version from git:
+    try:
+        version = subprocess.check_output([
+            "git",
+            "--git-dir=%s" % os.path.join(os.environ["IDF_PATH"], '.git'),
+            "--work-tree=%s" % os.environ["IDF_PATH"], "describe", "--tags", "--dirty"
+        ]).decode('utf-8', 'ignore').strip()
+    except (subprocess.CalledProcessError, UnicodeError):
+        # if failed, then try to parse cmake.version file
+        sys.stderr.write("WARNING: Git version unavailable, reading from source\n")
+        version = _idf_version_from_cmake()
+
+    return version
+
+
+def print_idf_version():
+    version = idf_version()
+    if version:
+        print("ESP-IDF %s" % version)
+    else:
+        print("ESP-IDF version unknown")
+
+
+def idf_version_callback(ctx, param, value):
+    if not value or ctx.resilient_parsing:
+        return
+
+    version = idf_version()
+
+    if not version:
+        raise FatalError("ESP-IDF version cannot be determined")
+
+    print("ESP-IDF %s" % version)
+    sys.exit(0)
+
+
+def verbose_callback(ctx, param, value):
+    if not value or ctx.resilient_parsing:
+        return
+
+    for line in ctx.command.verbose_output:
+        print(line)
+
+
 def get_commandline_options(ctx):
     """ Return all the command line options up to first action """
     # This approach ignores argument parsing done Click
@@ -547,7 +623,7 @@ class PropertyDict(dict):
             raise AttributeError("'PropertyDict' object has no attribute '%s'" % name)
 
 
-def init_cli():
+def init_cli(verbose_output=None):
     # Click is imported here to run it after check_environment()
     import click
 
@@ -750,7 +826,7 @@ def init_cli():
     class CLI(click.MultiCommand):
         """Action list contains all actions with options available for CLI"""
 
-        def __init__(self, action_lists=None, help=None):
+        def __init__(self, action_lists=None, verbose_output=None, help=None):
             super(CLI, self).__init__(
                 chain=True,
                 invoke_without_command=True,
@@ -762,6 +838,11 @@ def init_cli():
             self.global_action_callbacks = []
             self.commands_with_aliases = {}
 
+            if verbose_output is None:
+                verbose_output = []
+
+            self.verbose_output = verbose_output
+
             if action_lists is None:
                 action_lists = []
 
@@ -1042,6 +1123,12 @@ def init_cli():
 
     root_options = {
         "global_options": [
+            {
+                "names": ["--version"],
+                "help": "Show IDF version and exit.",
+                "is_flag": True,
+                "callback": idf_version_callback
+            },
             {
                 "names": ["-C", "--project-dir"],
                 "help": "Project directory.",
@@ -1064,7 +1151,9 @@ def init_cli():
                 "names": ["-v", "--verbose"],
                 "help": "Verbose build output.",
                 "is_flag": True,
+                "is_eager": True,
                 "default": False,
+                "callback": verbose_callback
             },
             {
                 "names": ["--ccache/--no-ccache"],
@@ -1337,12 +1426,12 @@ def init_cli():
     except NameError:
         pass
 
-    return CLI(help="ESP-IDF build management", action_lists=all_actions)
+    return CLI(help="ESP-IDF build management", verbose_output=verbose_output, action_lists=all_actions)
 
 
 def main():
-    check_environment()
-    cli = init_cli()
+    checks_output = check_environment()
+    cli = init_cli(verbose_output=checks_output)
     cli(prog_name=PROG)