i2c: add tree.py to parse i2c bus info to tree

The i2c topo is so complex if there are many i2c buses and muxes,
it's hard to understand the i2c bus info from the output of
"i2cdetect -l". This patch adds a python script to parse the i2c bus
info to a tree, which is easy to understand.

ps: maybe add a tree view to the i2ctools, but it's not easy to me.

Example:
```
ssh user@<ip> "i2cdetect -l" | python tree.py
root
├── i2c-4
│   ├── i2c-16
│   │   ├── i2c-129
│   │   ├── i2c-130
│   │   ├── i2c-131
│   │   └── i2c-132
│   ├── i2c-17
│   │   ├── i2c-113
│   │   ├── i2c-114
│   │   ├── i2c-115
│   │   ├── i2c-116
│   │   ├── i2c-117
│   │   ├── i2c-118
│   │   ├── i2c-119
│   │   └── i2c-120
│   ├── i2c-18
│   │   ├── i2c-105
│   │   ├── i2c-106
│   │   ├── i2c-107
│   │   ├── i2c-108
....
```

Change-Id: Ia434b093c7ccff80ea52ad7416bcda609890cecd
Signed-off-by: Jian Zhang <zhangjian.3032@bytedance.com>
diff --git a/i2c/requirements.txt b/i2c/requirements.txt
new file mode 100644
index 0000000..53eba46
--- /dev/null
+++ b/i2c/requirements.txt
@@ -0,0 +1 @@
+anytree
diff --git a/i2c/tree.py b/i2c/tree.py
new file mode 100644
index 0000000..87d28d1
--- /dev/null
+++ b/i2c/tree.py
@@ -0,0 +1,92 @@
+#!/bin/python
+
+import re
+import sys
+
+from anytree import Node, RenderTree
+
+usage = """
+Usage: using local file or stdin to parse i2c bus info to tree
+    1. ssh user@<ip> "i2cdetect -l" > i2c_bus_info.txt
+    2. python tree.py i2c_bus_info.txt
+
+    or
+
+    ssh user@<ip> "i2cdetect -l" | python tree.py
+"""
+
+node_dict = {}
+root = Node("root")
+
+
+def parse_line(line):
+    line = line.strip()
+    regex = re.compile(r"(i2c-\d+)\s+i2c\s+(.*)\s+I2C adapter")
+    m = regex.match(line)
+    if m:
+        bus = m.group(1)
+        name = m.group(2).strip()
+        return (bus, name)
+    else:
+        return None
+
+
+def draw(line):
+    i2c = parse_line(line)
+    if not i2c:
+        return
+
+    bus, name = i2c
+
+    if "mux" not in name:
+        node_dict[bus] = Node(bus, parent=root)
+    else:
+        mux_regex = re.compile(r"i2c-(\d+)-mux \(chan_id (\d+)\)")
+        m = mux_regex.match(name)
+        if m:
+            i2c = m.group(1)
+            if "i2c-" + i2c in node_dict:
+                node_dict[bus] = Node(bus, parent=node_dict["i2c-" + i2c])
+
+
+def parse_from_file(file):
+    with open(file, "r") as f:
+        lines = f.readlines()
+        for line in lines:
+            draw(line)
+
+
+def parse_from_stdin():
+    lines = sys.stdin.readlines()
+    for line in lines:
+        draw(line)
+
+
+def print_tree():
+    for pre, fill, node in RenderTree(root):
+        print("%s%s" % (pre, node.name))
+
+
+if __name__ == "__main__":
+    if len(sys.argv) == 2:
+        if (
+            sys.argv[1] == "-h"
+            or sys.argv[1] == "--help"
+            or sys.argv[1] == "help"
+            or sys.argv[1] == "?"
+        ):
+            print(usage)
+            sys.exit(0)
+
+    try:
+        if len(sys.argv) == 2:
+            file = sys.argv[1]
+            parse_from_file(file)
+        else:
+            parse_from_stdin()
+    except Exception as e:
+        print(e)
+        print(usage)
+        sys.exit(1)
+
+    print_tree()