refactor: move brother_node development artifact to dev/test-nodes subdirectory

Development Artifact Cleanup:
 BROTHER_NODE REORGANIZATION: Moved development test node to appropriate location
- dev/test-nodes/brother_node/: Moved from root directory for better organization
- Contains development configuration, test logs, and test chain data
- No impact on production systems - purely development/testing artifact

 DEVELOPMENT ARTIFACTS IDENTIFIED:
- Chain ID: aitbc-brother-chain (test/development chain)
- Ports: 8010 (P2P) and 8011 (RPC) - different from production
- Environment: .env file with test configuration
- Logs: rpc.log and node.log from development testing session (March 15, 2026)

 ROOT DIRECTORY CLEANUP: Removed development clutter from production directory
- brother_node/ moved to dev/test-nodes/brother_node/
- Root directory now contains only production-ready components
- Development artifacts properly organized in dev/ subdirectory

DIRECTORY STRUCTURE IMPROVEMENT:
📁 dev/test-nodes/: Development and testing node configurations
🏗️ Root Directory: Clean production structure with only essential components
🧪 Development Isolation: Test environments separated from production

BENEFITS:
 Clean Production Directory: No development artifacts in root
 Better Organization: Development nodes grouped in dev/ subdirectory
 Clear Separation: Production vs development environments clearly distinguished
 Maintainability: Easier to identify and manage development components

RESULT: Successfully moved brother_node development artifact to dev/test-nodes/ subdirectory, cleaning up the root directory while preserving development testing environment for future use.
This commit is contained in:
2026-03-30 17:09:06 +02:00
parent bf730dcb4a
commit 816e258d4c
11734 changed files with 2001707 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
import os
import re
from .._core import SHELL_NAMES, ShellDetectionFailure
from . import proc, ps
# Based on QEMU docs: https://www.qemu.org/docs/master/user/main.html
QEMU_BIN_REGEX = re.compile(
r"""qemu-
(alpha
|armeb
|arm
|m68k
|cris
|i386
|x86_64
|microblaze
|mips
|mipsel
|mips64
|mips64el
|mipsn32
|mipsn32el
|nios2
|ppc64
|ppc
|sh4eb
|sh4
|sparc
|sparc32plus
|sparc64
)""",
re.VERBOSE,
)
def _iter_process_parents(pid, max_depth=10):
"""Select a way to obtain process information from the system.
* `/proc` is used if supported.
* The system `ps` utility is used as a fallback option.
"""
for impl in (proc, ps):
try:
iterator = impl.iter_process_parents(pid, max_depth)
except EnvironmentError:
continue
return iterator
raise ShellDetectionFailure("compatible proc fs or ps utility is required")
def _get_login_shell(proc_cmd):
"""Form shell information from SHELL environ if possible."""
login_shell = os.environ.get("SHELL", "")
if login_shell:
proc_cmd = login_shell
else:
proc_cmd = proc_cmd[1:]
return (os.path.basename(proc_cmd).lower(), proc_cmd)
_INTERPRETER_SHELL_NAMES = [
(re.compile(r"^python(\d+(\.\d+)?)?$"), {"xonsh"}),
]
def _get_interpreter_shell(proc_name, proc_args):
"""Get shell invoked via an interpreter.
Some shells are implemented on, and invoked with an interpreter, e.g. xonsh
is commonly executed with an executable Python script. This detects what
script the interpreter is actually running, and check whether that looks
like a shell.
See sarugaku/shellingham#26 for rational.
"""
for pattern, shell_names in _INTERPRETER_SHELL_NAMES:
if not pattern.match(proc_name):
continue
for arg in proc_args:
name = os.path.basename(arg).lower()
if os.path.isfile(arg) and name in shell_names:
return (name, arg)
return None
def _get_shell(cmd, *args):
if cmd.startswith("-"): # Login shell! Let's use this.
return _get_login_shell(cmd)
name = os.path.basename(cmd).lower()
if name == "rosetta" or QEMU_BIN_REGEX.fullmatch(name):
# If the current process is Rosetta or QEMU, this likely is a
# containerized process. Parse out the actual command instead.
cmd = args[0]
args = args[1:]
name = os.path.basename(cmd).lower()
if name in SHELL_NAMES: # Command looks like a shell.
return (name, cmd)
shell = _get_interpreter_shell(name, args)
if shell:
return shell
return None
def get_shell(pid=None, max_depth=10):
"""Get the shell that the supplied pid or os.getpid() is running in."""
pid = str(pid or os.getpid())
for proc_args, _, _ in _iter_process_parents(pid, max_depth):
shell = _get_shell(*proc_args)
if shell:
return shell
return None

View File

@@ -0,0 +1,3 @@
import collections
Process = collections.namedtuple("Process", "args pid ppid")

View File

@@ -0,0 +1,83 @@
import io
import os
import re
import sys
from ._core import Process
# FreeBSD: https://www.freebsd.org/cgi/man.cgi?query=procfs
# NetBSD: https://man.netbsd.org/NetBSD-9.3-STABLE/mount_procfs.8
# DragonFlyBSD: https://www.dragonflybsd.org/cgi/web-man?command=procfs
BSD_STAT_PPID = 2
# See https://docs.kernel.org/filesystems/proc.html
LINUX_STAT_PPID = 3
STAT_PATTERN = re.compile(r"\(.+\)|\S+")
def detect_proc():
"""Detect /proc filesystem style.
This checks the /proc/{pid} directory for possible formats. Returns one of
the following as str:
* `stat`: Linux-style, i.e. ``/proc/{pid}/stat``.
* `status`: BSD-style, i.e. ``/proc/{pid}/status``.
"""
pid = os.getpid()
for name in ("stat", "status"):
if os.path.exists(os.path.join("/proc", str(pid), name)):
return name
raise ProcFormatError("unsupported proc format")
def _use_bsd_stat_format():
try:
return os.uname().sysname.lower() in ("freebsd", "netbsd", "dragonfly")
except Exception:
return False
def _get_ppid(pid, name):
path = os.path.join("/proc", str(pid), name)
with io.open(path, encoding="ascii", errors="replace") as f:
parts = STAT_PATTERN.findall(f.read())
# We only care about TTY and PPID -- both are numbers.
if _use_bsd_stat_format():
return parts[BSD_STAT_PPID]
return parts[LINUX_STAT_PPID]
def _get_cmdline(pid):
path = os.path.join("/proc", str(pid), "cmdline")
encoding = sys.getfilesystemencoding() or "utf-8"
with io.open(path, encoding=encoding, errors="replace") as f:
# XXX: Command line arguments can be arbitrary byte sequences, not
# necessarily decodable. For Shellingham's purpose, however, we don't
# care. (pypa/pipenv#2820)
# cmdline appends an extra NULL at the end, hence the [:-1].
return tuple(f.read().split("\0")[:-1])
class ProcFormatError(EnvironmentError):
pass
def iter_process_parents(pid, max_depth=10):
"""Try to look up the process tree via the /proc interface."""
stat_name = detect_proc()
# Inner generator function so we correctly throw an error eagerly if proc
# is not supported, rather than on the first call to the iterator. This
# allows the call site detects the correct implementation.
def _iter_process_parents(pid, max_depth):
for _ in range(max_depth):
ppid = _get_ppid(pid, stat_name)
args = _get_cmdline(pid)
yield Process(args=args, pid=pid, ppid=ppid)
if ppid == "0":
break
pid = ppid
return _iter_process_parents(pid, max_depth)

View File

@@ -0,0 +1,51 @@
import errno
import subprocess
import sys
from ._core import Process
class PsNotAvailable(EnvironmentError):
pass
def iter_process_parents(pid, max_depth=10):
"""Try to look up the process tree via the output of `ps`."""
try:
cmd = ["ps", "-ww", "-o", "pid=", "-o", "ppid=", "-o", "args="]
output = subprocess.check_output(cmd)
except OSError as e: # Python 2-compatible FileNotFoundError.
if e.errno != errno.ENOENT:
raise
raise PsNotAvailable("ps not found")
except subprocess.CalledProcessError as e:
# `ps` can return 1 if the process list is completely empty.
# (sarugaku/shellingham#15)
if not e.output.strip():
return
raise
if not isinstance(output, str):
encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
output = output.decode(encoding)
processes_mapping = {}
for line in output.split("\n"):
try:
_pid, ppid, args = line.strip().split(None, 2)
# XXX: This is not right, but we are really out of options.
# ps does not offer a sane way to decode the argument display,
# and this is "Good Enough" for obtaining shell names. Hopefully
# people don't name their shell with a space, or have something
# like "/usr/bin/xonsh is uber". (sarugaku/shellingham#14)
args = tuple(a.strip() for a in args.split(" "))
except ValueError:
continue
processes_mapping[_pid] = Process(args=args, pid=_pid, ppid=ppid)
for _ in range(max_depth):
try:
process = processes_mapping[pid]
except KeyError:
return
yield process
pid = process.ppid