From a919b4ef74e8e0c6d255ba9082765aff42ffc87e Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Thu, 5 Sep 2024 16:46:08 +0200 Subject: [PATCH 1/9] duplicate existing ipy script --- componentize_ipy_v2.py | 396 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 396 insertions(+) create mode 100644 componentize_ipy_v2.py diff --git a/componentize_ipy_v2.py b/componentize_ipy_v2.py new file mode 100644 index 0000000..53cf436 --- /dev/null +++ b/componentize_ipy_v2.py @@ -0,0 +1,396 @@ +from __future__ import print_function + +import argparse +import base64 +import json +import os +import re +import sys +import tempfile +import urllib +import zipfile +import StringIO + +import clr +import System +import System.IO + +GHPYTHON_SCRIPT_GUID = System.Guid("410755b1-224a-4c1e-a407-bf32fb45ea7e") +TEMPLATE_VER = re.compile("{{version}}") +TEMPLATE_NAME = re.compile("{{name}}") +TEMPLATE_GHUSER_NAME = re.compile("{{ghuser_name}}") + +TYPES_MAP = dict( + none="35915213-5534-4277-81b8-1bdc9e7383d2", + ghdoc="87f87f55-5b71-41f4-8aea-21d494016f81", + float="39fbc626-7a01-46ab-a18e-ec1c0c41685b", + bool="d60527f5-b5af-4ef6-8970-5f96fe412559", + int="48d01794-d3d8-4aef-990e-127168822244", + complex="309690df-6229-4774-91bb-b1c9c0bfa54d", + str="37261734-eec7-4f50-b6a8-b8d1f3c4396b", + datetime="09bcf900-fe83-4efa-8d32-33d89f7a3e66", + guid="5325b8e1-51d7-4d36-837a-d98394626c35", + color="24b1d1a3-ab79-498c-9e44-c5b14607c4d3", + point="e1937b56-b1da-4c12-8bd8-e34ee81746ef", + vector="15a50725-e3d3-4075-9f7c-142ba5f40747", + plane="3897522d-58e9-4d60-b38c-978ddacfedd8", + interval="589748aa-e558-4dd9-976f-78e3ab91fc77", + uvinterval="74c906f3-db02-4cea-bd58-de375cb5ae73", + box="f29cb021-de79-4e63-9f04-fc8e0df5f8b6", + transform="c4b38e4c-21ff-415f-a0d1-406d282428dd", + line="f802a8cd-e699-4a94-97ea-83b5406271de", + circle="3c5409a1-3293-4181-a6fa-c24c37fc0c32", + arc="9c80ec18-b48c-41b0-bc6e-cd93d9c916aa", + polyline="66fa617b-e3e8-4480-9f1e-2c0688c1d21b", + rectangle="83da014b-a550-4bf5-89ff-16e54225bd5d", + curve="9ba89ec2-5315-435f-a621-b66c5fa2f301", + mesh="794a1f9d-21d5-4379-b987-9e8bbf433912", + surface="f4070a37-c822-410f-9057-100d2e22a22d", + subd="20f4ca9c-6c90-4fd6-ba8a-5bf9ca79db08", + brep="2ceb0405-fdfe-403d-a4d6-8786da45fb9d", + geometrybase="c37956f4-d39c-49c7-af71-1e87f8031b26", +) + +EXPOSURE = dict(valid=set([-1, 2, 4, 8, 16, 32, 64, 128]), default=2) +ACCESS = dict(valid=set([0, 1, 2]), map=dict(item=0, list=1, tree=2), default=0) +PARAM_TYPE = dict( + valid=set(TYPES_MAP.values()), map=TYPES_MAP, default=TYPES_MAP["ghdoc"] +) +WIRE_DISPLAY = dict( + valid=set([0, 1, 2]), map=dict(default=0, faint=1, hidden=2), default=0 +) + + +def fetch_ghio_lib(target_folder="temp"): + """Fetch the GH_IO.dll library from the NuGet packaging system.""" + ghio_dll = "GH_IO.dll" + filename = "lib/net48/" + ghio_dll + + response = urllib.urlopen("https://www.nuget.org/api/v2/package/Grasshopper/") + dst_file = os.path.join(target_folder, ghio_dll) + zip_file = zipfile.ZipFile(StringIO.StringIO(response.read())) + + with zip_file.open(filename, "r") as zipped_dll: + with open(dst_file, "wb") as fp: + fp.write(zipped_dll.read()) + + return dst_file + + +def find_ghio_assembly(libdir): + for root, _dirs, files in os.walk(libdir): + for basename in files: + if basename.upper() == "GH_IO.DLL": + filename = os.path.join(root, basename) + return filename + + +def bitmap_from_image_path(image_path): + with open(image_path, "rb") as imageFile: + img_string = base64.b64encode(imageFile.read()) + return System.Convert.FromBase64String(img_string) + + +def validate_source_bundle(source): + icon = os.path.join(source, "icon.png") + code = os.path.join(source, "code.py") + data = os.path.join(source, "metadata.json") + + if not os.path.exists(icon): + raise ValueError( + "icon missing, make sure icon.png is present in the source bundle: {}".format( + source + ) + ) + if not os.path.exists(code): + raise ValueError( + "code missing, make sure code.py is present in the source bundle: {}".format( + source + ) + ) + if not os.path.exists(data): + raise ValueError( + "metadata missing, make sure metadata.json is present in the source bundle: {}".format( + source + ) + ) + + icon = bitmap_from_image_path(icon) + + with open(code, "r") as f: + python_code = f.read() + + with open(data, "r") as f: + data = json.load(f) + + if "exposure" not in data: + data["exposure"] = EXPOSURE["default"] + + if data["exposure"] not in EXPOSURE["valid"]: + raise ValueError( + "Invalid exposure value. Accepted values are {}".format( + sorted(EXPOSURE["valid"]) + ) + ) + + ghpython = data.get("ghpython") + sdk_mode = ghpython and ghpython.get("isAdvancedMode", False) + + if r'"""' not in python_code and sdk_mode is False: + python_code = r'"""{}"""{}{}'.format( + data.get("description", "Generated by Componentizer"), + os.linesep, + python_code, + ) + + return icon, python_code, data + + +def parse_param_access(access): + try: + access = int(access) + except ValueError: + # Maybe string? + access = ACCESS["map"].get(access) + + if access not in ACCESS["valid"]: + raise ValueError( + "Invalid param access value. Valid values are {}".format( + sorted(ACCESS["valid"]) + ) + ) + + return access + + +def parse_wire_display(wire_display): + try: + wire_display = int(wire_display) + except ValueError: + wire_display = WIRE_DISPLAY["map"].get(wire_display) + + if wire_display not in WIRE_DISPLAY["valid"]: + raise ValueError( + "Invalid wire display value. Valid values are {}".format( + sorted(WIRE_DISPLAY["valid"]) + ) + ) + + return wire_display + + +def parse_param_type_hint(type_hint_id): + type_hint_id = type_hint_id or PARAM_TYPE["default"] + + if type_hint_id in TYPES_MAP: + type_hint_id = TYPES_MAP[type_hint_id] + + if type_hint_id not in PARAM_TYPE["valid"]: + raise ValueError( + 'Invalid param type hint ID ("{}"). Valid values are {}'.format( + type_hint_id, sorted(PARAM_TYPE["valid"]) + ) + ) + + try: + type_hint_id = System.Guid.Parse(type_hint_id) + except SystemError: + raise ValueError("Unable to parse type hint ID: {}".format(type_hint_id)) + + return type_hint_id + + +def replace_templates(code, version, name, ghuser_name): + if version: + code = TEMPLATE_VER.sub(version, code) + + code = TEMPLATE_NAME.sub(name, code) + code = TEMPLATE_GHUSER_NAME.sub(ghuser_name, code) + + return code + + +def create_ghuser_component(source, target, version=None, prefix=None): + from GH_IO.Serialization import GH_LooseChunk + + icon, code, data = validate_source_bundle(source) + + code = replace_templates(code, version, data["name"], os.path.basename(target)) + + instance_guid = data.get("instanceGuid") + if not instance_guid: + instance_guid = System.Guid.NewGuid() + else: + instance_guid = System.Guid.Parse(instance_guid) + + prefix = prefix or "" + + root = GH_LooseChunk("UserObject") + + root.SetGuid("BaseID", GHPYTHON_SCRIPT_GUID) + root.SetString("Name", prefix + data["name"]) + root.SetString("NickName", data["nickname"]) + root.SetString("Description", data.get("description", "")) + root.SetInt32("Exposure", data.get("exposure", EXPOSURE["default"])) + root.SetString("Category", data["category"]) + root.SetString("SubCategory", data["subcategory"]) + root.SetGuid("InstanceGuid", instance_guid) + root.SetByteArray("Icon", icon) + + ghpython_data = data["ghpython"] + ghpython_root = GH_LooseChunk("UserObject") + ghpython_root.SetString("Description", data.get("description", "")) + ghpython_root.SetBoolean("HideOutput", ghpython_data.get("hideOutput", True)) + ghpython_root.SetBoolean("HideInput", ghpython_data.get("hideInput", True)) + ghpython_root.SetBoolean( + "IsAdvancedMode", ghpython_data.get("isAdvancedMode", False) + ) + ghpython_root.SetInt32("IconDisplay", ghpython_data.get("iconDisplay", 0)) + ghpython_root.SetString("Name", data["name"]) + ghpython_root.SetString("NickName", data["nickname"]) + ghpython_root.SetBoolean( + "MarshalOutGuids", ghpython_data.get("marshalOutGuids", True) + ) + ghpython_root.SetString("CodeInput", code) + + # ghpython_root.CreateChunk('Attributes') + # for mf in ('Bounds', 'Pivot', 'Selected'): + params = ghpython_root.CreateChunk("ParameterData") + inputParam = ghpython_data.get("inputParameters", []) + outputParam = ghpython_data.get("outputParameters", []) + + params.SetInt32("InputCount", len(inputParam)) + for i, _pi in enumerate(inputParam): + params.SetGuid( + "InputId", i, System.Guid.Parse("84fa917c-1ed8-4db3-8be1-7bdc4a6495a2") + ) + params.SetInt32("OutputCount", len(outputParam)) + for i, _po in enumerate(outputParam): + params.SetGuid( + "OutputId", i, System.Guid.Parse("8ec86459-bf01-4409-baee-174d0d2b13d0") + ) + + for i, pi in enumerate(inputParam): + input_instance_guid = System.Guid.NewGuid() + pi_chunk = params.CreateChunk("InputParam", i) + pi_chunk.SetString("Name", pi["name"]) + pi_chunk.SetString("NickName", pi.get("nickname") or pi["name"]) + pi_chunk.SetString("Description", pi.get("description")) + pi_chunk.SetBoolean("Optional", pi.get("optional", True)) + pi_chunk.SetBoolean("AllowTreeAccess", pi.get("allowTreeAccess", True)) + pi_chunk.SetBoolean("ShowTypeHints", pi.get("showTypeHints", True)) + pi_chunk.SetInt32( + "ScriptParamAccess", + parse_param_access(pi.get("scriptParamAccess", ACCESS["default"])), + ) + pi_chunk.SetInt32("SourceCount", 0) + pi_chunk.SetGuid("InstanceGuid", input_instance_guid) + pi_chunk.SetGuid("TypeHintID", parse_param_type_hint(pi.get("typeHintID"))) + pi_chunk.SetInt32( + "WireDisplay", + parse_wire_display(pi.get("wireDisplay", WIRE_DISPLAY["default"])), + ) + pi_chunk.SetBoolean("ReverseData", pi.get("reverse", False)) + pi_chunk.SetBoolean("SimplifyData", pi.get("simplify", False)) + # Mutually exclusive options + if pi.get("flatten", False): + pi_chunk.SetInt32("Mapping", 1) + elif pi.get("graft", False): + pi_chunk.SetInt32("Mapping", 2) + + for i, po in enumerate(outputParam): + output_instance_guid = System.Guid.NewGuid() + po_chunk = params.CreateChunk("OutputParam", i) + po_chunk.SetString("Name", po["name"]) + po_chunk.SetString("NickName", po.get("nickname") or po["name"]) + po_chunk.SetString("Description", po.get("description")) + po_chunk.SetBoolean("Optional", po.get("optional", False)) + po_chunk.SetInt32("SourceCount", 0) + po_chunk.SetGuid("InstanceGuid", output_instance_guid) + po_chunk.SetBoolean("ReverseData", po.get("reverse", False)) + po_chunk.SetBoolean("SimplifyData", po.get("simplify", False)) + # Mutually exclusive options + if po.get("flatten", False): + po_chunk.SetInt32("Mapping", 1) + elif po.get("graft", False): + po_chunk.SetInt32("Mapping", 2) + + # print(ghpython_root.Serialize_Xml()) + root.SetByteArray("Object", ghpython_root.Serialize_Binary()) + + System.IO.File.WriteAllBytes(target, root.Serialize_Binary()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Create GHUser components out of python code." + ) + parser.add_argument( + "source", + type=str, + help="Source directory where code for all components is stored", + ) + parser.add_argument("target", type=str, help="Target directory for ghuser files") + parser.add_argument( + "--ghio", + type=str, + required=False, + help="Folder where the GH_IO.dll assembly is located. Defaults to ./lib", + ) + parser.add_argument( + "--version", type=str, required=False, help="Version to tag components" + ) + parser.add_argument( + "--prefix", + type=str, + required=False, + help="Add this prefix to the name of each generated component", + ) + args = parser.parse_args() + + sourcedir = args.source + if not os.path.isabs(sourcedir): + sourcedir = os.path.abspath(sourcedir) + + targetdir = args.target + if not os.path.isabs(targetdir): + targetdir = os.path.abspath(targetdir) + + if args.ghio is None: + libdir = tempfile.mkdtemp("ghio") + fetch_ghio_lib(libdir) + else: + libdir = os.path.abspath(args.ghio) + gh_io = find_ghio_assembly(libdir) + source_bundles = [ + d + for d in os.listdir(sourcedir) + if os.path.isdir(os.path.join(sourcedir, d)) + and d not in ("__pycache__", ".git") + ] + + print("GHPython componentizer") + print("======================") + + print("[x] Source: {} ({} components)".format(sourcedir, len(source_bundles))) + print("[ ] Target: {}\r".format(targetdir), end="") + if not os.path.exists(targetdir): + os.mkdir(targetdir) + print("[x]") + + print("[ ] GH_IO assembly: {}\r".format(gh_io or args.ghio), end="") + if not gh_io: + print("[-]") + print(" Cannot find GH_IO Assembly! Aborting.") + sys.exit(-1) + clr.AddReferenceToFileAndPath(gh_io) + print("[x]") + print() + + print("Processing component bundles:") + for d in source_bundles: + source = os.path.join(sourcedir, d) + target = os.path.join(targetdir, d + ".ghuser") + print(" [ ] {}\r".format(d), end="") + create_ghuser_component(source, target, args.version, args.prefix) + print(" [x] {} => {}".format(d, target)) From 42a8ef452828eb591b7bb4e8ed1f8c13e8959155 Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Thu, 5 Sep 2024 16:47:21 +0200 Subject: [PATCH 2/9] changes necessary to create `modern` ipy components --- componentize_ipy_v2.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/componentize_ipy_v2.py b/componentize_ipy_v2.py index 53cf436..9fb4580 100644 --- a/componentize_ipy_v2.py +++ b/componentize_ipy_v2.py @@ -15,7 +15,8 @@ import System import System.IO -GHPYTHON_SCRIPT_GUID = System.Guid("410755b1-224a-4c1e-a407-bf32fb45ea7e") +# this GUID means "Modern IronPython interpreter" +GHPYTHON_SCRIPT_GUID = System.Guid("97aa26ef-88ae-4ba6-98a6-ed6ddeca11d1") TEMPLATE_VER = re.compile("{{version}}") TEMPLATE_NAME = re.compile("{{name}}") TEMPLATE_GHUSER_NAME = re.compile("{{ghuser_name}}") @@ -251,7 +252,6 @@ def create_ghuser_component(source, target, version=None, prefix=None): ghpython_root.SetBoolean( "MarshalOutGuids", ghpython_data.get("marshalOutGuids", True) ) - ghpython_root.SetString("CodeInput", code) # ghpython_root.CreateChunk('Attributes') # for mf in ('Bounds', 'Pivot', 'Selected'): @@ -315,7 +315,16 @@ def create_ghuser_component(source, target, version=None, prefix=None): elif po.get("graft", False): po_chunk.SetInt32("Mapping", 2) - # print(ghpython_root.Serialize_Xml()) + # this is new in Rhino8, istead of setting the code as a string, we set it as a base64 blob + script = ghpython_root.CreateChunk("Script") + code_base64 = base64.b64encode(code.encode("utf-8")) + code_base64 = str(code_base64) + script.SetString("Text", code_base64) + script.SetString("Title", "IPy2") + language_spec = script.CreateChunk("LanguageSpec") + language_spec.SetString("Taxon", "*.ironpython.python") + language_spec.SetString("Version", "2.*") + root.SetByteArray("Object", ghpython_root.Serialize_Binary()) System.IO.File.WriteAllBytes(target, root.Serialize_Binary()) From ee0808328a015460779722bda3da4e48c5ab45f7 Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 17:35:51 +0200 Subject: [PATCH 3/9] added missing geometry type. disable the `out` parameter --- componentize_ipy_v2.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/componentize_ipy_v2.py b/componentize_ipy_v2.py index 9fb4580..8cd0045 100644 --- a/componentize_ipy_v2.py +++ b/componentize_ipy_v2.py @@ -50,6 +50,7 @@ subd="20f4ca9c-6c90-4fd6-ba8a-5bf9ca79db08", brep="2ceb0405-fdfe-403d-a4d6-8786da45fb9d", geometrybase="c37956f4-d39c-49c7-af71-1e87f8031b26", + pointcloud="d73c9fb0-365d-458f-9fb5-f4141399311f", ) EXPOSURE = dict(valid=set([-1, 2, 4, 8, 16, 32, 64, 128]), default=2) @@ -236,6 +237,7 @@ def create_ghuser_component(source, target, version=None, prefix=None): root.SetString("Category", data["category"]) root.SetString("SubCategory", data["subcategory"]) root.SetGuid("InstanceGuid", instance_guid) + root.SetBoolean("UsingStandardOutputParam", False) root.SetByteArray("Icon", icon) ghpython_data = data["ghpython"] From dca0a15a65ed3c52d9c3bfc726e4285661321814 Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 17:38:37 +0200 Subject: [PATCH 4/9] added branch for the new ipy_v2 script --- action.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/action.yml b/action.yml index 2628e73..aa60dda 100644 --- a/action.yml +++ b/action.yml @@ -27,6 +27,9 @@ runs: if ("${{ inputs.interpreter }}" -eq "cpython") { $command="python" $componentizer="${{ github.action_path }}/componentize_cpy.py" + } elseif ("${{ inputs.interpreter }}" -eq "ipy_v2"){ + $command="ipy" + $componentizer="${{ github.action_path }}/componentize_ipy_v2.py" } else { $command="ipy" $componentizer="${{ github.action_path }}/componentize_ipy.py" From 7e8ea3302a411b7c2386531b78c5f9ae4d56ba3b Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 18:34:48 +0200 Subject: [PATCH 5/9] fixed wrong guids --- componentize_ipy_v2.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/componentize_ipy_v2.py b/componentize_ipy_v2.py index 8cd0045..6a61b8f 100644 --- a/componentize_ipy_v2.py +++ b/componentize_ipy_v2.py @@ -22,13 +22,13 @@ TEMPLATE_GHUSER_NAME = re.compile("{{ghuser_name}}") TYPES_MAP = dict( - none="35915213-5534-4277-81b8-1bdc9e7383d2", - ghdoc="87f87f55-5b71-41f4-8aea-21d494016f81", - float="39fbc626-7a01-46ab-a18e-ec1c0c41685b", + none="6a184b65-baa3-42d1-a548-3915b401de53", + ghdoc="1c282eeb-dd16-439f-94e4-7d92b542fe8b", + float="9d51e32e-c038-4352-9554-f4137ca91b9a", bool="d60527f5-b5af-4ef6-8970-5f96fe412559", int="48d01794-d3d8-4aef-990e-127168822244", complex="309690df-6229-4774-91bb-b1c9c0bfa54d", - str="37261734-eec7-4f50-b6a8-b8d1f3c4396b", + str="3aceb454-6dbd-4c5b-9b6b-e71f8c1cdf88", datetime="09bcf900-fe83-4efa-8d32-33d89f7a3e66", guid="5325b8e1-51d7-4d36-837a-d98394626c35", color="24b1d1a3-ab79-498c-9e44-c5b14607c4d3", @@ -49,8 +49,8 @@ surface="f4070a37-c822-410f-9057-100d2e22a22d", subd="20f4ca9c-6c90-4fd6-ba8a-5bf9ca79db08", brep="2ceb0405-fdfe-403d-a4d6-8786da45fb9d", - geometrybase="c37956f4-d39c-49c7-af71-1e87f8031b26", pointcloud="d73c9fb0-365d-458f-9fb5-f4141399311f", + geometrybase="c37956f4-d39c-49c7-af71-1e87f8031b26", ) EXPOSURE = dict(valid=set([-1, 2, 4, 8, 16, 32, 64, 128]), default=2) @@ -264,12 +264,12 @@ def create_ghuser_component(source, target, version=None, prefix=None): params.SetInt32("InputCount", len(inputParam)) for i, _pi in enumerate(inputParam): params.SetGuid( - "InputId", i, System.Guid.Parse("84fa917c-1ed8-4db3-8be1-7bdc4a6495a2") + "InputId", i, System.Guid.Parse("08908df5-fa14-4982-9ab2-1aa0927566aa") ) params.SetInt32("OutputCount", len(outputParam)) for i, _po in enumerate(outputParam): params.SetGuid( - "OutputId", i, System.Guid.Parse("8ec86459-bf01-4409-baee-174d0d2b13d0") + "OutputId", i, System.Guid.Parse("08908df5-fa14-4982-9ab2-1aa0927566aa") ) for i, pi in enumerate(inputParam): From 344289fb27028bbcce5d5bd03e734102c805f971 Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 18:36:10 +0200 Subject: [PATCH 6/9] added example component --- examples/ipy_v2/Test_KitchenSink/code.py | 19 +++++ examples/ipy_v2/Test_KitchenSink/icon.png | Bin 0 -> 2759 bytes .../ipy_v2/Test_KitchenSink/metadata.json | 68 ++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 examples/ipy_v2/Test_KitchenSink/code.py create mode 100644 examples/ipy_v2/Test_KitchenSink/icon.png create mode 100644 examples/ipy_v2/Test_KitchenSink/metadata.json diff --git a/examples/ipy_v2/Test_KitchenSink/code.py b/examples/ipy_v2/Test_KitchenSink/code.py new file mode 100644 index 0000000..cb9ae7a --- /dev/null +++ b/examples/ipy_v2/Test_KitchenSink/code.py @@ -0,0 +1,19 @@ +""" +Do something silly. + +This component does nothing useful, it's only a kitchen sink example showing most available options. + + Args: + x: X value + y: Y value + z: Z value + Returns: + result: The sum of all three values. +""" +from ghpythonlib.componentbase import executingcomponent as component + + +class KitchenSinkComponent(component): + def RunScript(self, x, y, z): + self.Message = "COMPONENT v{{version}}" + return x + y + z diff --git a/examples/ipy_v2/Test_KitchenSink/icon.png b/examples/ipy_v2/Test_KitchenSink/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c8df236e3a30d99b26c306af3495da68e531e6e3 GIT binary patch literal 2759 zcmcgudsGu=77ubjprv&IvC67ruz-)rJo11HL4;BCF^%yq$8 zJf7omT9s%_RK{QgqZQyJqoxFAt)4^kctOEtJx-)kMnFxa(mEOc{>e^0K$9|lf>;SF z^21wMkA)d1+{hSI43ja{sJJQ00Lo)HS^o$85$BmSXZ|xfhBOnT^ z5EK&&F(JAHMlcwjfGQc1)>v#%#0rH2REP)@`Tq*XDTc(2_=}MwfoT|n7Uz2;}mz*a&mjLBdOTu6?W@Y#7qSXi8a(a;&(0=p_A6i|eRNf4<-0-^$BoTyTXDRit6 z*AbLLF5`2B5zsV=`Afwbv04-W3dNKZL{O0sl!^#7h!7Hz#3?l)3LvKJRvKt-GvXP~dbP45 zIgf}?qMN`72LSR~DI{k2SPqSe&q$x#Lk zj0*?D3G0TC@d>LED3U)pO+Tj|FBN&x-jqghPG6vpiRdh&F`94#6_U!;?j;lm{T6)| z&w4R=T#S=yoIpWTf{H<$;@YYfNk~u=pus6bEYYYX(y8QajYAXQ&g0p)E94=n$nIln>6N>aJS6c1>1Nj(e`z$NyLfX+`g*tS&5y6o zPeFx+Cw94gA5$CezW;(BRr7_@On((RP`uyalEU#HT^BuPWF9zr`eJP!uoHCXxX^v; z^Qa%drdnrT>0h_pmpux4^x=alHqhmZ`ah~}r)mlXwYim_%$;>8j@h-gzEl}|VZHm} zGlhu}yGZnE0npHm$j!pgJ#V#uDs? z-tS!cmxfI-VEg`#%g&{p^X+erOpogylxrxV=MQ(hES2AV<+%M^Psw0mqkXt*n#ocS zoAX)j?>}eqD@>NLFMs-GBb0k9=#k&|h4wI#RGqo@+pTeyYd1nKeTo(bC+zgS*Sz5F zqR$qwbz=*cXB_s)tvP6SL;kcY|I?(Iqk@xeg`N?KUTyx8r0N;Yz@`-)-$9xD;^GnlpgT75&yDWV(D?V)2*0rR~&P$m_yaBmoKZy4l zEpeE2@FTRdV2JI%lwb0bIHbs{`O5X|4TnUYdC_|u%MO2it7<4Dc?ZfnqjPUCw>LKh zR-6c)m)Ocb?^M)X#C>FhiU2Wr*{yC~OU{85 z_k2o&fmfnyT58T7!FxBjFRhlD|Eb^K)NkM4zii$|zw>>PQ>ZHqdjA(=+ry}1Nshol zHYcPyP(*{V{)0#xr06}h*nMy;N$_U&>vqW_W~9b>R^G>5>Z9j)K6Pos&hTl&t$W#3 zOD#Sn;TKI~zc>YNY;nDkANk|T_9yeFwaPs57GQ1s^C=HrbBU+F^=j-~=lT@rIFKL; z3n_FhU$eK^kF1@(aE3r0Gwk`W{ATyP`@5^;zOQ=4?pe2BP(HkE=QMY02)q)zHwn4@ zPScFQ2g1N3V;lXHo%_mE$A!^P*Q4uVG{w@@p`Npc!g957v)|ghrSET1e^2?b&#jeF z6Su%lRQGkMqiEvyxscVQr&GqR-9k9&-+P> cdf~`i)t_^mjx6cBXZ_SvgvZL8LsJU=4QD(61^@s6 literal 0 HcmV?d00001 diff --git a/examples/ipy_v2/Test_KitchenSink/metadata.json b/examples/ipy_v2/Test_KitchenSink/metadata.json new file mode 100644 index 0000000..0974e77 --- /dev/null +++ b/examples/ipy_v2/Test_KitchenSink/metadata.json @@ -0,0 +1,68 @@ +{ + "name": "Kitchen sink component example", + "nickname": "Everything", + "category": "Componentizer", + "subcategory": "ALL", + "description": "This is an example with the everything and the kitchen sink in it, just to show all available options.", + "exposure": 4, + "instanceGuid": "cdd47086-f902-4b77-825b-6b79c3aaecc1", + "ghpython": { + "hideOutput": true, + "hideInput": true, + "isAdvancedMode": true, + "marshalOutGuids": true, + "iconDisplay": 2, + "inputParameters": [ + { + "name": "X", + "nickname": "x", + "description": "The X value of the component.", + "optional": true, + "allowTreeAccess": true, + "showTypeHints": true, + "scriptParamAccess": "item", + "wireDisplay": "faint", + "sourceCount": 0, + "typeHintID": "float", + "reverse": true, + "simplify": false + }, + { + "name": "Y", + "nickname": "y", + "description": "The Y value of the component.", + "optional": true, + "allowTreeAccess": true, + "showTypeHints": true, + "scriptParamAccess": "item", + "wireDisplay": "default", + "sourceCount": 0, + "typeHintID": "float", + "simplify": true + }, + { + "name": "Z", + "nickname": "z", + "description": "The Z value of the component.", + "optional": true, + "allowTreeAccess": true, + "showTypeHints": true, + "scriptParamAccess": "item", + "wireDisplay": "faint", + "sourceCount": 0, + "typeHintID": "float", + "flatten": true + } + ], + "outputParameters": [ + { + "name": "result", + "nickname": "result", + "description": "Result of the computation", + "optional": false, + "sourceCount": 0, + "graft": true + } + ] + } +} \ No newline at end of file From dd369a020ad599cd785afcbc4884b850d72e5184 Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 18:38:41 +0200 Subject: [PATCH 7/9] updated readme --- README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/README.md b/README.md index 9d6e392..f9ba6e7 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,37 @@ jobs: path: build ``` +For IronPython2 (RhinoV8): + +```yaml +on: [push] + +jobs: + build_ipy_ghuser_components: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - uses: NuGet/setup-nuget@v1.0.5 + + - name: Install IronPython + run: | + choco install ironpython --version=2.7.8.1 + + - uses: compas-dev/compas-actions.ghpython_components@v5 + with: + source: components + target: build + interpreter: ipy_v2 + + # The components have been built at this step. + # Now you can choose what to do with them, e.g.: + # upload them as artifacts: + - uses: actions/upload-artifact@v2 + with: + name: ipy_ghuser-components + path: build +``` + Commit, push and enjoy! 🍿 @@ -90,16 +121,19 @@ Make sure to have IronPython or Python3/pythonnet installed and the `GH_IO.dll` Then start the script pointing it to a source and target folder, e.g.: ipy componentize_ipy.py examples/ipy build + ipy componentize_ipy_v2.py examples/ipy_v2 build python componentize_cpy.py examples/cpy build Optionally, tag it with a version: ipy componentize_ipy.py examples/ipy build --version 0.1.2 + ipy componentize_ipy_v2.py examples/ipy_v2 build --version 0.1.2 python componentize_cpy.py examples/cpy build --version 0.1.2 An optional name prefix can help tell components apart from other similarly named ones: ipy componentize_ipy.py examples/ipy build --prefix "(PACKAGE-NAME)" + ipy componentize_ipy.py examples/ipy_v2 build --prefix "(PACKAGE-NAME)" python componentize_cpy.py examples/cpy build --prefix "(PACKAGE-NAME)" ## How to create components From cb971b3d958559e2851ebea41938dda46f122473 Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 18:42:22 +0200 Subject: [PATCH 8/9] updated version of actions/upload-artifact --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0ee9f05..a32b960 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: target: build interpreter: cpython - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: cpy_ghuser-components path: build @@ -42,7 +42,7 @@ jobs: source: examples/ipy target: build - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: ipy_ghuser-components path: build \ No newline at end of file From b7f2ff1666e55f6244f7c6177d61c0d63850d13f Mon Sep 17 00:00:00 2001 From: Chen Kasirer Date: Fri, 13 Sep 2024 18:48:37 +0200 Subject: [PATCH 9/9] added new action branch to build workflow --- .github/workflows/build.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a32b960..77f3f56 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,4 +45,26 @@ jobs: - uses: actions/upload-artifact@v4 with: name: ipy_ghuser-components + path: build + + build_ipy_v2_ghuser_components: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - uses: NuGet/setup-nuget@v1.0.5 + + - name: Install IronPython + run: | + choco install ironpython --version=2.7.8.1 + + - name: Run + uses: ./ + with: + source: examples/ipy_v2 + target: build + interpreter: ipy_v2 + + - uses: actions/upload-artifact@v4 + with: + name: ipy_v2_ghuser-components path: build \ No newline at end of file