diff --git a/flake.lock b/flake.lock index bc13ec9..cd4e0d6 100644 --- a/flake.lock +++ b/flake.lock @@ -36,35 +36,84 @@ "type": "github" } }, - "gazebros2nix": { + "flakoboros": { "inputs": { "flake-parts": "flake-parts", - "gepetto-lib": "gepetto-lib", "nix-ros-overlay": "nix-ros-overlay", "nixpkgs": [ "gepetto", "gazebros2nix", + "flakoboros", "nix-ros-overlay", "nixpkgs" ], - "pyproject-build-systems": "pyproject-build-systems", - "pyproject-nix": "pyproject-nix", "systems": [ "gepetto", "gazebros2nix", + "flakoboros", "nix-ros-overlay", "flake-utils", "systems" ], - "treefmt-nix": "treefmt-nix", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1774365635, + "narHash": "sha256-QjJ/CURzUwkO54xMKmGS1U4q+dog3KNQotxUtJ+JFz8=", + "owner": "gepetto", + "repo": "flakoboros", + "rev": "a42bc6287c3f47a7f2aea0699a344df22426e581", + "type": "github" + }, + "original": { + "owner": "gepetto", + "repo": "flakoboros", + "type": "github" + } + }, + "gazebros2nix": { + "inputs": { + "flake-parts": [ + "gepetto", + "gazebros2nix", + "flakoboros", + "flake-parts" + ], + "flakoboros": "flakoboros", + "nix-ros-overlay": [ + "gepetto", + "gazebros2nix", + "flakoboros", + "nix-ros-overlay" + ], + "nixpkgs": [ + "gepetto", + "gazebros2nix", + "flakoboros", + "nixpkgs" + ], + "pyproject-build-systems": "pyproject-build-systems", + "pyproject-nix": "pyproject-nix", + "systems": [ + "gepetto", + "gazebros2nix", + "flakoboros", + "systems" + ], + "treefmt-nix": [ + "gepetto", + "gazebros2nix", + "flakoboros", + "treefmt-nix" + ], "uv2nix": "uv2nix" }, "locked": { - "lastModified": 1773524302, - "narHash": "sha256-0phiMh2h3tZoe3rJGWWKMMJhuLMMHa65hRtgkzbXBJQ=", + "lastModified": 1774365734, + "narHash": "sha256-ZgPXr7KvYJBxD2t8DgT2u1dQ96JMvbrX0jXo27SxtsA=", "owner": "gepetto", "repo": "gazebros2nix", - "rev": "0eb9151c41ec370e29d4d4ae1640aa4c6c4aa7a7", + "rev": "e96f1edcccb79b73658ffbddc60ad61d6a30a75c", "type": "github" }, "original": { @@ -80,6 +129,11 @@ "gazebros2nix", "flake-parts" ], + "flakoboros": [ + "gepetto", + "gazebros2nix", + "flakoboros" + ], "gazebros2nix": "gazebros2nix", "home-manager": "home-manager", "nix-ros-overlay": [ @@ -108,11 +162,11 @@ ] }, "locked": { - "lastModified": 1773834979, - "narHash": "sha256-pxEUfvPZG3lMMiorJxKPt0kjjNE2gQDA3w/cRHvSUX4=", + "lastModified": 1774371946, + "narHash": "sha256-foMnMtcuEkBEp2gYL/AOzr1xhjldbw0CExsokwq1Mzk=", "owner": "gepetto", "repo": "nix", - "rev": "57036f98001a3b66384cd68ace974d237e3fa78b", + "rev": "049aec0d7dadc234bd6cc4e1b6731ce25e66e337", "type": "github" }, "original": { @@ -121,21 +175,6 @@ "type": "github" } }, - "gepetto-lib": { - "locked": { - "lastModified": 1772454823, - "narHash": "sha256-jROeQxiRkzpHHAWDAxHJVfW/liA+t6JKDyPMJFqUE9E=", - "owner": "Gepetto", - "repo": "nix-lib", - "rev": "4500b5aa6af20c60011926ad6f42238375779c90", - "type": "github" - }, - "original": { - "owner": "Gepetto", - "repo": "nix-lib", - "type": "github" - } - }, "home-manager": { "inputs": { "nixpkgs": [ @@ -144,11 +183,11 @@ ] }, "locked": { - "lastModified": 1773681845, - "narHash": "sha256-o8hrZrigP0JYcwnglCp8Zi8jQafWsxbDtRRPzuVwFxY=", + "lastModified": 1774274588, + "narHash": "sha256-dnHvv5EMUgTzGZmA+3diYjQU2O6BEpGLEOgJ1Qe9LaY=", "owner": "nix-community", "repo": "home-manager", - "rev": "0759e0e137305bc9d0c52c204c6d8dffe6f601a6", + "rev": "cf9686ba26f5ef788226843bc31fda4cf72e373b", "type": "github" }, "original": { @@ -165,6 +204,11 @@ "gepetto", "flake-parts" ], + "flakoboros": [ + "hpp-manipulation", + "gepetto", + "flakoboros" + ], "gazebros2nix": [ "hpp-manipulation", "gepetto", @@ -195,11 +239,11 @@ ] }, "locked": { - "lastModified": 1773846451, - "narHash": "sha256-J3t/rLFMEWvlRFByGKbBGzH/dopFA1bq9T3Vlyyell8=", + "lastModified": 1774373131, + "narHash": "sha256-3DoRbwCcCeMeMDiBzhK6enZiFDKt5Er5Wh8ec60vClI=", "owner": "humanoid-path-planner", "repo": "hpp-manipulation", - "rev": "e413c6f7e3e3315c403424ab9a2520d7868d1dc6", + "rev": "e314dbc9ebe3993270c2a9933f12ee19bbeed9f4", "type": "github" }, "original": { @@ -214,11 +258,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1773393994, - "narHash": "sha256-zm24obq1c4ielRR8KlUQ2M5XnNfUIcQjN++9s6CFvxc=", + "lastModified": 1774047596, + "narHash": "sha256-UNT8fGmAm2ZlaktMmiVYPeHgok2IJoCfLg698rO3Kq8=", "owner": "lopsided98", "repo": "nix-ros-overlay", - "rev": "a522c5a050a6d50471a29bbf6a060e2df16abf44", + "rev": "c0659dc45d4c1736d71d5578b17f12e3b1afe190", "type": "github" }, "original": { @@ -299,11 +343,11 @@ ] }, "locked": { - "lastModified": 1772555609, - "narHash": "sha256-3BA3HnUvJSbHJAlJj6XSy0Jmu7RyP2gyB/0fL7XuEDo=", + "lastModified": 1773870109, + "narHash": "sha256-ZoTdqZP03DcdoyxvpFHCAek4bkPUTUPUF3oCCgc3dP4=", "owner": "pyproject-nix", "repo": "build-system-pkgs", - "rev": "c37f66a953535c394244888598947679af231863", + "rev": "b6e74f433b02fa4b8a7965ee24680f4867e2926f", "type": "github" }, "original": { @@ -321,11 +365,11 @@ ] }, "locked": { - "lastModified": 1773190977, - "narHash": "sha256-fkJvOxz80cJViPz6GVaayC8BVCs5fclJ8qHDaNUpoEA=", + "lastModified": 1773909723, + "narHash": "sha256-HmcZQ/hMPHR22Ri/6Sl7Z0B5J8nZa9bRnZJtDFInM7I=", "owner": "pyproject-nix", "repo": "pyproject.nix", - "rev": "10ebca8a137bf26b7fbd3e94b339bf68cee18693", + "rev": "d37dcf34ac7194eac4b0d10520d01298c434267d", "type": "github" }, "original": { @@ -340,6 +384,10 @@ "gepetto", "flake-parts" ], + "flakoboros": [ + "gepetto", + "flakoboros" + ], "gazebros2nix": [ "gepetto", "gazebros2nix" @@ -439,6 +487,7 @@ "nixpkgs": [ "gepetto", "gazebros2nix", + "flakoboros", "nixpkgs" ] }, @@ -470,11 +519,11 @@ ] }, "locked": { - "lastModified": 1773359304, - "narHash": "sha256-knv2C6tIk5ysix+9TxWIenPvpB20kFjQ1CH6SJMBNsU=", + "lastModified": 1774315256, + "narHash": "sha256-jhlzSXk0Rv4cSHoRgEecEcv+veN0q3sD3PIAgqgpwcI=", "owner": "pyproject-nix", "repo": "uv2nix", - "rev": "27b135ea72ab1637fc5845a61c101ea66d6636d6", + "rev": "0623db9a65da877e4f6f67ed946ffd65401720f0", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 6f0c1ea..2baa83f 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,7 @@ inputs = { gepetto.url = "github:gepetto/nix"; + flakoboros.follows = "gepetto/flakoboros"; gazebros2nix.follows = "gepetto/gazebros2nix"; flake-parts.follows = "gepetto/flake-parts"; nixpkgs.follows = "gepetto/nixpkgs"; @@ -24,9 +25,9 @@ imports = [ inputs.gepetto.flakeModule { - gazebros2nix = { + flakoboros = { overlays = [ inputs.hpp-manipulation.overlays.default ]; - pyOverrides.hpp-python = + pyOverrideAttrs.hpp-python = _final: python-final: (super: { propagatedBuildInputs = super.propagatedBuildInputs ++ [ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37bdee6..679bdc1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -171,3 +171,7 @@ add_python_library( pyhpp/manipulation/urdf FILES pyhpp/manipulation/urdf/util.cc pyhpp/manipulation/urdf/bindings.cc LINK_LIBRARIES hpp-manipulation-urdf::hpp-manipulation-urdf) + +# Install tool submodule +python_install_on_site(pyhpp/tools __init__.py) +python_install_on_site(pyhpp/tools xacro.py) diff --git a/src/pyhpp/tools/__init__.py b/src/pyhpp/tools/__init__.py new file mode 100644 index 0000000..ce53a5e --- /dev/null +++ b/src/pyhpp/tools/__init__.py @@ -0,0 +1 @@ +from .xacro import process_xacro, retrieve_resource # noqa: F401 diff --git a/src/pyhpp/tools/xacro.py b/src/pyhpp/tools/xacro.py new file mode 100644 index 0000000..fcc4c74 --- /dev/null +++ b/src/pyhpp/tools/xacro.py @@ -0,0 +1,76 @@ +import os +import sys +import xml + + +try: # python 2 + _basestr = basestring + encoding = {"encoding": "utf-8"} +except NameError: # python 3 + _basestr = str + unicode = str + encoding = {} + + +def process_xacro(*args): + import xacro + + opts, input_file_name = xacro.process_args(args) + try: + # If AMENT_PREFIX_PATH is defined (ROS 2), pass the content to retrieve resources + ament_prefix_path = os.getenv("AMENT_PREFIX_PATH") + if ament_prefix_path is not None: + dirs = list(map(lambda s: s + "/share", ament_prefix_path.split(":"))) + # open and process file + doc = xacro.process_file(retrieve_resource(input_file_name, dirs), **vars(opts)) + + # error handling + except xml.parsers.expat.ExpatError as e: + xacro.error(f"XML parsing error: {unicode(e)}", alt_text=None) + if xacro.verbosity > 0: + xacro.print_location() + print(file=sys.stderr) # add empty separator line before error + print("Check that:", file=sys.stderr) + print(" - Your XML is well-formed", file=sys.stderr) + print( + " - You have the xacro xmlns declaration:", + 'xmlns:xacro="http://www.ros.org/wiki/xacro"', + file=sys.stderr, + ) + sys.exit(2) # indicate failure, but don't print stack trace on XML errors + + except Exception as e: + msg = unicode(e) + if not msg: + msg = repr(e) + xacro.error(msg) + if xacro.verbosity > 0: + xacro.print_location() + if xacro.verbosity > 1: + print(file=sys.stderr) # add empty separator line before error + raise # create stack trace + else: + sys.exit(2) # gracefully exit with error condition + + # write output + return doc.toprettyxml(indent=" ", **encoding) + + +def retrieve_resource(path, dirs=None, env_var="ROS_PACKAGE_PATH"): + """ + Retrieve resource of the form "package://", resolving the package in the list of + dirs. + If the list of dirs is None, it is initialized with + the content of the environnement variable env_var. + """ + if path.startswith("package://"): + relpath = path[len("package://") :] + import os + + if dirs is None: + dirs = os.environ[env_var].split(":") + for dir in dirs: + abspath = os.path.join(dir, relpath) + if os.path.isfile(abspath): + return abspath + return path