Skip to content

Add NUKE build aligned with pipenv build products - #3129

Closed
OnePowerUser88 wants to merge 10 commits into
pyrevitlabs:developfrom
OnePowerUser88:NUKE-build
Closed

Add NUKE build aligned with pipenv build products#3129
OnePowerUser88 wants to merge 10 commits into
pyrevitlabs:developfrom
OnePowerUser88:NUKE-build

Conversation

@OnePowerUser88

@OnePowerUser88 OnePowerUser88 commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Description

Disclaimer: This PR was largely created with Cursor; someone familiar with the build process should review it.

The main reason for this PR is problems with pipenv; @jmcouffin and @sanzoghenzo had mentioned NUKE as an option.

This PR adds a NUKE-based build so the repo can be built without Python or pipenv. Running .\build.ps1 BuildProducts from the root folder produces the same artifacts as pipenv run pyrevit build products. Pipenv is not removed or changed developers can use either pipenv run pyrevit build products or .\build.ps1 BuildProducts.

Included

  • build/Build.cs, build.ps1, README.md, build.csproj. Targets: BuildDepsBuildLabsBuildLoadersBuildRuntimeDeployLibsToEnginesBuildAutocmp, plus Clean, Check, and release-related targets (SetVersion, SetYear, SetProducts, BuildInstallers, CommitAndTagBuild, etc.).
  • Telemetry build step removed — telemetry server is moving to another repository.
  • BuildLoaders – Uses RunProcess with captured MSBuild output on failure and /m:1 so Deploy targets don't race; Clean then BuildProducts succeeds on first run.
  • BuildAutocmp – Builds pyrevit-autocomplete.exe from the checked-in Go source (regenerate via pipenv run pyrevit build autocmp when CLI usage changes).
  • .gitignore.nuke/, build/bin/ (NUKE runner output; not committed).

No product source or DLL changes.
CI can be switched to NUKE later if desired.

Checklist

Before submitting your pull request, ensure the following requirements are met:

  • Build follows the existing structure (deps → labs → loaders → runtime → deploy libs → autocmp; telemetry step removed).
  • .\build.ps1 Check passes (dotnet and go on PATH).
  • .\build.ps1 Clean then .\build.ps1 BuildProducts succeeds.
  • C# and project changes follow the project's conventions (build script only; no product code changes).

Related Issues

  • N/A (build system addition; no linked issue).

Additional Notes

  • To test: From the root folder, run .\build.ps1 Check then .\build.ps1 BuildProducts (requires .NET SDK and Go). No pipenv needed.
  • build/README.md has the full target list, examples, and troubleshooting.

@devloai

devloai Bot commented Feb 23, 2026

Copy link
Copy Markdown
Contributor

Unable to trigger custom agent "Code Reviewer". You have run out of credits 😔
Please upgrade your plan or buy additional credits from the subscription page.

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Important note:
This is tested and gives no errors in Revit 2026, but has not been tested in older Revit versions.

@sanzoghenzo

Copy link
Copy Markdown
Contributor

Hi @OnePowerUser88 , thanks for the contribution.

The goal of using nuke is to completely remove the pipenv environment, also in the CI/CD.

There are other commands in the dev\pyrevit.py script that needs to be ported, and then we can remove those python files.

Do you think you can address these as well, or do you believe it should be done on a separate PR?
(I am an all-or-nothing kind of guy, that's why I never follow through this task...)

Also, can you please omit the not strictly needed files? This move to nuke should't change the DLLs.
Were the source code (and thus DLL) changes made by Cursor just to be able to finish its task? try to ask it to not touch them 😉

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Will look into it!

Just to make sure:
Should I leave pipenv for now, if both can be supported until nuke setup is finished?
What dlls should be included in PRs for testing the C# changes (I know this PR should probably not need any)

- build/: Build.cs, README, csproj, nuget.config
- build.ps1: bootstrap for .NET NUKE runner
- .gitignore: .nuke/, build/bin/

No DLL or source changes. Remaining pyrevit.py commands to be ported in follow-up for full pipenv removal.

Co-authored-by: Cursor <cursoragent@cursor.com>
@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Also, can you please omit the not strictly needed files? This move to nuke should't change the DLLs.
Were the source code (and thus DLL) changes made by Cursor just to be able to finish its task? try to ask it to not touch them 😉

I'm not able to find a solution to build without editing mongo.go and ScriptConsole.cs without it failing. Anyone have any input?

@jmcouffin

Copy link
Copy Markdown
Contributor

find a solution to build without editing mongo.go and ScriptConsole.cs

What is the error

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Summary of source file changes (this branch)

This comment describes the source code changes introduced alongside the NUKE build. These are product improvements and bug fixes that apply whether you use pipenv or NUKE. Verified in Revit 2024 and 2026 after build.


1. dev/pyRevitLabs.PyRevit.Runtime/ScriptConsole.cs — WPF theme loading (Script Console)

Problem

When pyRevit loads in Revit (especially 2026 / .NET Core), the Script Console window throws:

System.IO.IOException: Cannot locate resource 'styles/themes/light.blue.xaml'

The MahApps.Metro theme is loaded via a pack URI. In some hosts the resource is resolved with lowercase path (styles/themes/light.blue.xaml) instead of the canonical Styles/Themes/Light.Blue.xaml.
Additionally, Controls.xaml was merged into the window’s resources before the theme. Controls.xaml itself merges dictionaries that reference the theme, so WPF tries to resolve the theme during the load of Controls.xaml. If the theme is not yet in the window’s MergedDictionaries, that resolution fails and the exception is thrown.

Changes

  • TryAddThemeResource(string packUri)
    New helper that loads the Light.Blue theme with a fallback for path casing:

    • Tries the canonical pack URI: .../Styles/Themes/Light.Blue.xaml.
    • On any exception, tries the lowercase variant: .../styles/themes/light.blue.xaml.
    • Both attempts are wrapped in try/catch. If neither succeeds, no theme is added (window still opens; styling may be wrong but no crash).
  • Load order in SetupDynamicResources()
    The theme is now added first, before Controls.xaml and Fonts.xaml. When WPF then loads Controls.xaml and its merged dictionaries reference the theme, the theme is already in the window’s MergedDictionaries and the resource resolves correctly.

Result

Script Console loads without IOException in Revit 2024 and 2026. No change to behavior beyond fixing theme resolution and load order.


2. dev/pyRevitTelemetryServer/persistence/mongo.go — MongoDB Go driver v2

Problem

The telemetry server’s MongoDB code was written for the v1 driver API. The project already depended on go.mongodb.org/mongo-driver/v2 in go.mod, but the code still used v1-style calls and the deprecated connstring package (x/mongo/driver/connstring), which is not part of the v2 public API. As a result, go build failed with undefined symbols (mongo, options, readpref, bson, connstring, etc.).

Changes

  • Imports
    Switched to v2 packages:

    • go.mongodb.org/mongo-driver/v2/bson
    • go.mongodb.org/mongo-driver/v2/mongo
    • go.mongodb.org/mongo-driver/v2/mongo/options
    • go.mongodb.org/mongo-driver/v2/mongo/readpref
      Added net/url and strings for URI parsing.
  • mongo.Connect
    In v2, Connect takes only options (no context):
    mongo.Connect(options.Client().ApplyURI(uri)).
    All call sites were updated; context is used only for Ping, Disconnect, RunCommand, and InsertOne.

  • Connection string / database name
    Replaced connstring.ParseAndValidate(connStr) with a local helper mongoDatabaseFromURI(connStr) that:

    • Parses the URI with url.Parse.
    • Takes the path (e.g. /mydb), trims the leading slash and any query string.
    • Defaults to "admin" if the path is empty.
      commitMongo and any logic that used connStringInfo.Database now use this helper.
  • Error handling and defers

    • In GetVersion: check err after mongo.Connect and return early on failure; defer client.Disconnect(ctx) only when client is non-nil.
    • In commitMongo: defer client.Disconnect(ctx) and use a separate inner context for InsertOne to avoid variable shadowing (iCtx, iCancel).

Result

The Go telemetry server builds successfully with the v2 driver. Behavior is unchanged from a user perspective. Same binary works whether built via pipenv or NUKE.


3. dev/pyRevitTelemetryServer/go.mod and go.sum

  • go.mod
    Already declared go.mongodb.org/mongo-driver/v2; no functional change required for the mongo.go update.

  • go.sum
    Updated by running go mod tidy so that the v2 driver and its transitive dependencies have correct checksums. Needed for a reproducible Go build.


4. build/Build.cs — Full build includes telemetry

Change: BuildProducts again depends on BuildTelem. The default full build runs:
BuildDeps → BuildLabs → BuildLoaders → BuildRuntime → DeployLibsToEngines → BuildTelem → BuildAutocmp.

Reason: With mongo.go fixed, the telemetry server builds successfully; including it in the full build matches the pipenv “build products” behavior and produces bin/pyrevit-telemetryserver.exe in one shot.


5. build/README.md — Documentation

  • “Source code used by this build”
    Short section stating that ScriptConsole and mongo.go changes are product improvements (theme fix and telemetry v2), not NUKE-only workarounds, and that they benefit both pipenv and NUKE builds.

  • A reference to this summary (see below).


Quick reference

File What changed Why
ScriptConsole.cs Theme loaded via TryAddThemeResource (canonical + lowercase fallback); theme added before Controls.xaml Fix “Cannot locate resource 'styles/themes/light.blue.xaml'” in Revit 2024/2026
mongo.go v2 driver imports; mongo.Connect(opts); mongoDatabaseFromURI instead of connstring; error handling and defers Telemetry server Go build was broken; v2 API and no deprecated connstring
go.mod / go.sum go.sum updated via go mod tidy Reproducible build with v2 driver
Build.cs BuildProducts depends on BuildTelem again Full build produces telemetry exe like pipenv
build/README.md “Source code used by this build” section Clarify that changes are product improvements, not Nuke workarounds

@jmcouffin
jmcouffin requested a review from Copilot February 26, 2026 20:17
@jmcouffin jmcouffin added Command Line Utility (CLI) Issues related to pyRevit CLI tool [subsystem] go Pull requests that update Go code CI/CD Issues and PR related to the CI/CD workflow in github github_actions Pull requests that update GitHub Actions code labels Feb 26, 2026

This comment was marked as outdated.

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

I’ve pushed a follow‑up commit to address the review feedback and harden a couple of edge cases:

Mongo telemetry (dev/pyRevitTelemetryServer/persistence/mongo.go)

  • Fixed the Disconnect context in GetVersion:
    • mongo.Connect is still mongo.Connect(options.Client().ApplyURI(...)), but we no longer reuse the same ctx for Ping and RunCommand.
    • Disconnect now uses its own timeout context inside the defer, so it doesn’t run with a cancelled context.
  • Kept the v2 driver and URI‑based DB name parsing (mongoDatabaseFromURI using net/url + strings).

(If anyone can fully test the Telemetry changes it would be greate, I have built a separate AzureSQL telemetry service for the extension I maintain, so I don't have the setup for testing it properlty.)

NUKE build (build/Build.cs)

  • Go builds:
    • BuildTelemCore and BuildAutocmpCore now use only:
      • go build -o "<output>" .
    • The earlier go get ./... calls are removed, so NUKE builds no longer mutate go.mod / go.sum or pull in newer deps behind your back.
  • SetYear:
    • Ported the same 30‑day threshold logic as dev/_props.py:set_year:
      • Compute nextJan1 and threshold = nextJan1 - 30 days, bump the year only when now >= threshold.

NuGet config

  • Removed build/nuget.config, so there is no more repo‑level signatureValidationMode="accept".
    Anyone who needs to relax signature checks can do so in a user‑specific NuGet.Config outside this repo.

Tab coloring robustness (pyrevitlib/pyrevit/revit/tabs.py)

  • Hardened against legacy / C# config setup (PR refactor: Rewrite pyRevit configurations #2482) user configs:
    • tabstyle_index and family_tabstyle_index are now normalized to int with safe defaults (DefaultTabColoringStyleIndex / DefaultFamilyTabColoringStyleIndex), so "0", "1", etc. no longer cause TypeError: expected int, got str.
    • tab_filtercolors is normalized before use:
      • if it’s a list, we turn it into {color: ""} for each entry;
      • if it’s anything other than a dict, we fall back to {}.
    • hex_to_brush is now defensive: invalid color strings are caught and replaced with a default brush (first DefaultBrushes entry, with a final fallback to white) instead of throwing.
  • This fixes the startup errors I was seeing when the loaded user config contained old/bad tab coloring values.

Note: These tab‑coloring issues are very likely related to the ongoing work in “fix/configuration” in PR #2482 that ports config handling to C#. That branch was writing tabstyle_* and tab_filtercolors slightly differently (indices as strings, non‑dict filtercolors). The guards in tabs.py make the Python side tolerant of both the legacy Python writer and the new C# writer, so this PR should be compatible with both.

Merges & testing

  • Merged latest upstream/develop into NUKE-build.
  • NUKE:
    • ./build.ps1 Clean followed by ./build.ps1 BuildProducts succeeds from a clean tree.
  • Revit:
    • Basic testing in Revit 2024 and 2026:
      • pyRevit loads,
      • tab coloring works,
      • no loader errors on startup.
  • Telemetry:
    • Manually ran the built telemetry server:

      ./bin/pyrevit-telemetryserver.exe `
        "mongodb://pyrevit:pyrevit@localhost:27017/pyrevit" `
        --scripts=scripts `
        --events=events `
        --port=8090

      and got Server listening on 8090..., so the v2 driver wiring and build seems to be correct.

Let me know if you’d like any of these pieces split into separate PRs or see further tweaks to the NUKE targets.

@sanzoghenzo

Copy link
Copy Markdown
Contributor

Were the source code (and thus DLL) changes made by Cursor just to be able to finish its task?

Let me rephrase: ScriptConsole.cs, the telemetry server files and tabs.py should not be edited by this PR!

this only should add the build script using nuke, nothing more, nothing less.

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Thank you for the pushback @sanzoghenzo :)
I have reverted the files, but building the telemetry product will still fail because I think the pipenv actually does not successfully build it either?

pipenv doesn't check the go build exit code.
In _telem.py:

    utils.system(
        [go_tool, "build", "-o", output_bin, op.abspath(configs.TELEMETRYSERVER)],
        cwd=op.abspath(configs.TELEMETRYSERVERPATH),
    )
    print("Building telemetry server completed successfully")

utils.system() returns (stdout, returncode) but the return value is ignored, so the script always prints success. Pipenv was never building telem successfully, it was masking the failure?

Do you want this to be handled in a separate PR?

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Extra info on building telem, when I added exception handleing to pipenv build:

pipenv run pyrevit build telem
Courtesy Notice:
Pipenv found itself running within a virtual environment,  so it will 
automatically use that environment, instead of  creating its own for any 
project. You can set
PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and 
create  its own instead.
You can set PIPENV_VERBOSITY=-1 to suppress this warning.
# pyrevittelemetryserver/persistence
persistence\mongo.go:32:17: undefined: mongo
persistence\mongo.go:32:36: undefined: options
persistence\mongo.go:42:27: undefined: readpref
persistence\mongo.go:51:20: undefined: bson
persistence\mongo.go:52:13: undefined: bson
persistence\mongo.go:52:20: missing type in composite literal
persistence\mongo.go:86:25: undefined: connstring
persistence\mongo.go:96:17: undefined: mongo
persistence\mongo.go:96:36: undefined: options
> git config --global http.https://pkg.re.followRedirects true
Updating telemetry server dependencies...
> go get ./...
Telemetry server dependencies successfully updated
Building telemetry server...
> go build -o D:\GitRepos\onepoweruser88\pyRevit\dev\bin\pyrevit-telemetryserver.exe D:\GitRepos\onepoweruser88\pyRevit\dev\dev\pyRevitTelemetryServer\main.go
Telemetry build: go build failed (see output above)

@sanzoghenzo

Copy link
Copy Markdown
Contributor

I wouldn't worry about the telemerty server, since we're in the process of moving it to another repository. In fact, you could already remove that build step 😉

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Removed Telem build and updated PR description.
Let me know if there is anything else I shold look into for this PR.

- Refined .gitignore to include specific NUKE build files and directories.
- Updated variable name in build.ps1 for consistency with script context.
- Added .gitkeep to .nuke directory to ensure it is tracked in version control.

@sanzoghenzo sanzoghenzo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally had time to take a look at this, but I soon stopped because this is clearly AI generated code without much thought on it.

Nuke provides many facilities in order to call tools like dotnet, so you don't need to call the processes manually yourself.
Sure, the documentation is a bit lacking (The cli tools page has some non-exhaustive examples), but the tools are there and using any IDE with dotnet support you can find the namespaces, classes and methods available.

For cli tools not supported (such as go), you can use the Lightweight API to wrap the commands into a Tool.

Note that these are my change requests based on the first 90 lines of Build.cs, there colud be other things that need to be changed, but I value my time and I won't waste it on AI generated slop.

Comment thread build/README.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI slopped documentation interspersed with implementation details, unneeded references to the previous states (pipenv replacement, telemetry server) and design considerations/TODOs that have no place on a developer guide to document a tool usage. Please review it and get straight to the point.

@sanzoghenzo

Copy link
Copy Markdown
Contributor

Sorry I totally forgot about the disclaimer in the PR description, but this still holds.
I'm no expert on Nuke, but I just had to work on it for one of my projects at work and after a few hours I got the basic knowledge to understand this PR is more or less crap.

I understand you just wanted to actually do things instead of keep reading us only thinking and talking about this changes, but you can't vibe code your way through uncharted territories and then drop the ball to others to review.

@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Thank you for your honest reply @sanzoghenzo

To be honest, I have been thinking that I got carried away seeing a problem some of you mentioned needed handleing, and I wanted to help, but underestimating what it takes to do it properly...

I have set up a few WiX installers at work, and at a first glance I thought this was not that different... 🤦‍♂️

I'm open to scrapping the whole PR, but I also kind of want to dig into it some more and see what I can learn how to do it properly. 😂

I don't expect anyone to pick it up and fix it! If you think it's at a point where it is possible for me to keep working on it and get it to an acceptable solution, I'm happy to do so. If you think it is better letting someone with actual NUKE experience tackeling it from scratch, I totally understand.

@jmcouffin

Copy link
Copy Markdown
Contributor

No worries @OnePowerUser88 you're good willing.
Why don't we start from scratch and write here the steps to implement it properly?
@sanzoghenzo you'll probably be great a jotting down the plan

@sanzoghenzo

Copy link
Copy Markdown
Contributor

@sanzoghenzo you'll probably be great a jotting down the plan

No need to trash the pr, just converting the calls to dotnet to the proper DotNetTasks would be a great start (this is what made me abandon the review, AI failed at the basics 😅 ).

For the plan, other than reading the documentation, the resources and act upon the acquired knowledge, I don't have any...

@sanzoghenzo

Copy link
Copy Markdown
Contributor

Oh, another thing that should be used along with DotNetTask is the Solution & Project model

A silly example for a single project

[Solution]
readonly Solution Solution;

AbsolutePath OutputDirectory => RootDirectory / "output";
readonly string ProjectName = "MyBeautifulProject";

Target Publish => _ => _
    .Executes(() =>
    {
        var version = "0.0.0"; // obviously this needs to be calculated/read somehow
        DotNetTasks.DotNetPublish(_ => _
                .SetProcessWorkingDirectory(Solution.Directory)
                .SetProject(ProjectName)
                .SetConfiguration(Configuration)
                .AddProperty("VersionPrefix", version)
                .SetOutput(OutputDirectory));
    });

@jmcouffin
jmcouffin marked this pull request as draft March 31, 2026 19:03
@OnePowerUser88

Copy link
Copy Markdown
Contributor Author

Thank you both for your input.
I will start reading docs and update the PR as I go. Might be a few weeks until I have time to start due to work and parental leave.

@jmcouffin

Copy link
Copy Markdown
Contributor

@OnePowerUser88 well well well.
I discussed with @Nice3point (roman who is taking care of revitlookup + has nice extensions and Revit templates in c#)
He advised using https://github.com/thomhurst/ModularPipelines instead of nuke...
I'll take a look.
Closing this PR in the meantime

@jmcouffin jmcouffin closed this Apr 10, 2026
@sanzoghenzo

Copy link
Copy Markdown
Contributor

He advised using https://github.com/thomhurst/ModularPipelines instead of nuke...

Are you sure about that?
From a very quick look at the documentation, it seems more complicated than nuke 😅

@jmcouffin

Copy link
Copy Markdown
Contributor

He advised using https://github.com/thomhurst/ModularPipelines instead of nuke...

Are you sure about that? From a very quick look at the documentation, it seems more complicated than nuke 😅

Never sure. Never am until I try it myself.
Nuke documentation? As in human readable? 😅🤣

@jmcouffin

Copy link
Copy Markdown
Contributor

@sanzoghenzo convince me otherwise

@sanzoghenzo

Copy link
Copy Markdown
Contributor

Well, since we have little to no knowledge with both, I'm not willing to convince anyone 😅 it was just a sanity check...

I hope Roman can help you/us with this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD Issues and PR related to the CI/CD workflow in github Command Line Utility (CLI) Issues related to pyRevit CLI tool [subsystem] github_actions Pull requests that update GitHub Actions code go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants