<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Dustin Blackman - Blog</title>
    <subtitle>My personal blogs for thoughts and projects</subtitle>
    <link href="https://dustinblackman.com/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://dustinblackman.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2023-11-29T00:00:00+00:00</updated>
    <id>https://dustinblackman.com/atom.xml</id>
    <entry xml:lang="en">
        <title>Stop using PhantomJS</title>
        <published>2023-11-29T00:00:00+00:00</published>
        <updated>2023-11-29T00:00:00+00:00</updated>
        <author>
          <name>Dustin Blackman</name>
        </author>
        <link rel="alternate" href="https://dustinblackman.com/posts/stop-using-phantomjs/" type="text/html"/>
        <id>https://dustinblackman.com/posts/stop-using-phantomjs/</id>
        
        <content type="html">&lt;hr &#x2F;&gt;
&lt;p&gt;Yesterday I archived a very old GitHub project of mine called &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;phantomized&#x2F;&quot;&gt;phantomized&lt;&#x2F;a&gt;. If memory serves right, it was my lazy solution to being able to run PhantomJS (a scriptable browser) within an Alpine docker image that I had built for an old Discord bot, when Alpine was making it&#x27;s way in to the Docker scene.&lt;&#x2F;p&gt;
&lt;p&gt;Every so often I look through my old projects, and anything I deem unmaintainable or no one uses it, I archive the repo. Good to keep things clean! When I reached phantomized, I looked and saw there has been no PhantomJS release since &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ariya&#x2F;phantomjs&#x2F;tags&quot;&gt;2016&lt;&#x2F;a&gt;, all the projects are archived, the packages are deprecated. I thought &lt;em&gt;&amp;quot;yep, it&#x27;s dead, everyone&#x27;s moved on to Puppeteer, let&#x27;s wrap this up&amp;quot;&lt;&#x2F;em&gt;, and I hit the archive button thinking this is just cleaning up and nothing more.&lt;&#x2F;p&gt;
&lt;p&gt;Man, I was wrong.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve received &lt;strong&gt;several&lt;&#x2F;strong&gt; messages across platforms I didn&#x27;t even know had a chat that I&#x27;ve broken production builds of both newish and legacy applications. I&#x27;m sorry, I didn&#x27;t mean to make your job today harder, I really thought this was long and dead.&lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re hitting my blog looking for answers, there are now &lt;strong&gt;a lot&lt;&#x2F;strong&gt; of &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;phantomized&#x2F;forks?include=active%2Cinactive%2Cnetwork&amp;amp;page=1&amp;amp;period=6mo&amp;amp;sort_by=last_updated&quot;&gt;forks&lt;&#x2F;a&gt; of people who&#x27;ve fixed up the repo and gotten the package available again that you can use. &lt;&#x2F;p&gt;
&lt;p&gt;Before you do, it&#x27;s important to point out that you really shouldn&#x27;t be using PhantomJS anymore. &lt;strong&gt;SEVEN years&lt;&#x2F;strong&gt; of not receiving any patches for a web browser is long, like really long. If you&#x27;re using it for things like CI of your web application you&#x27;re probably fine, but if you&#x27;re hitting the public internet then your app is susceptible to &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nvd.nist.gov&#x2F;vuln&#x2F;detail&#x2F;CVE-2019-17221&quot;&gt;CVE-2019-17221&lt;&#x2F;a&gt;. That&#x27;s scary, and this doesn&#x27;t include any other &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;cve.mitre.org&#x2F;cgi-bin&#x2F;cvekey.cgi?keyword=webkit&quot;&gt;WebKit&lt;&#x2F;a&gt; vulnerabilities that have popped up over the years.&lt;&#x2F;p&gt;
&lt;p&gt;If phantomized has helped you out in the past, I&#x27;m glad I could help! In return, do me a favour and have that likely difficult chat with your Boss on managing tech debt before some other open source maintainer hits archive on a repo. Better now than in a panic later.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for reading! Good luck.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Oatmeal</title>
        <published>2023-11-27T00:00:00+00:00</published>
        <updated>2023-11-27T00:00:00+00:00</updated>
        <author>
          <name>Dustin Blackman</name>
        </author>
        <link rel="alternate" href="https://dustinblackman.com/posts/oatmeal/" type="text/html"/>
        <id>https://dustinblackman.com/posts/oatmeal/</id>
        
        <content type="html">&lt;hr &#x2F;&gt;
&lt;p&gt;I can&#x27;t open HackerNews or GitHub Trending without seeing something around LLMs. The ecosystem is booming, there&#x27;s always something new, and it&#x27;s been pretty fun to watch! Recently I had a buddy show off &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;continue.dev&quot;&gt;Continue.dev&lt;&#x2F;a&gt;, a tool that seamlessly integrates an LLM of your choosing into your daily workflows. Its capabilities extend beyond mere code building; it simplifies mundane tasks, enhances test writing, and aids in debugging. Not to mention, it&#x27;s &lt;em&gt;fun&lt;&#x2F;em&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;While Continue.dev is impressive, my preference for the terminal, and specifically Neovim led me to seek an alternative. My goal was to build a solution that mirrored the interactivity of a Discord conversation, complete with slash commands like my old bot from a few years back, yet capable of integrating with Neovim for a broad range of topics and problems.&lt;&#x2F;p&gt;
&lt;p&gt;One weekend morning over breakfast I put together the first commit for Oatmeal. Despite the whimsical name, this project quickly transformed into a comprehensive tool that I&#x27;d find myself reaching for while working. It&#x27;s been my first attempt in the world of TUI&#x27;s, and thankfully there are fantastic libraries in the Rust ecosystem like &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ratatui.rs&#x2F;&quot;&gt;Ratatui&lt;&#x2F;a&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve definitely 2xed what I had initially intended as a first set of features, but I suppose all projects start off like that. Either way, it&#x27;s looking great so far:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Agnostic Backends:&lt;&#x2F;strong&gt; Choose between ChatGPT for expansive knowledge or Ollama for privacy concerns.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Integration with Editors:&lt;&#x2F;strong&gt; When using it in an editor like Neovim, it&#x27;s gotta feel like it&#x27;s part of the editor.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Fancy Chat Bubbles:&lt;&#x2F;strong&gt; It looks like a chat app! Less IRC, more iMessage.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Slash Commands:&lt;&#x2F;strong&gt; Simplifies actions with intuitive commands, from sending data back and forth between an editor, coping to clipboard, or changing models on the fly!&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Hotkeys&lt;&#x2F;strong&gt;: A mix of both what Neovim and Discord users would expect such as CTRL+U&#x2F;D for page up and down.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Syntax Highlighting:&lt;&#x2F;strong&gt; When using it for code, it&#x27;s gotta have the same look and feel as my editor, including the correct colours.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Session Management:&lt;&#x2F;strong&gt; Being able to look back on old convos, or reopen ones that I fit fingered closed by accident.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Oatmeal is not just another chat application; it&#x27;s a tool that caters to the needs of modern tech enthusiasts, developers, and anyone who loves a good terminal interface. It blends traditional UI elements with modern functionalities. Whether you&#x27;re looking to interact with LLMs, finding a new daily workflow, or simply enjoy a sleek terminal chat, I hope you find Oatmeal worth exploring.&lt;&#x2F;p&gt;
&lt;p&gt;Check it out on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;oatmeal&quot;&gt;Github&lt;&#x2F;a&gt;, and the quick Neovim integration demo below! Thanks for reading!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;post-images&#x2F;oatmeal.gif&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Why does everyone install crates globally?</title>
        <published>2023-11-27T00:00:00+00:00</published>
        <updated>2023-11-27T00:00:00+00:00</updated>
        <author>
          <name>Dustin Blackman</name>
        </author>
        <link rel="alternate" href="https://dustinblackman.com/posts/why-does-everyone-install-crates-globally/" type="text/html"/>
        <id>https://dustinblackman.com/posts/why-does-everyone-install-crates-globally/</id>
        
        <content type="html">&lt;hr &#x2F;&gt;
&lt;p&gt;Unless I&#x27;m missing some big piece in the Rust ecosystem &lt;strong&gt;(which could totally be true)&lt;&#x2F;strong&gt;, is everyone just ignoring the pains of managing teams working in Rust, and the global dependencies were all asked to install? Is that really the right way to do things?&lt;&#x2F;p&gt;
&lt;p&gt;Hear me out.&lt;&#x2F;p&gt;
&lt;p&gt;Take the fictional scenario that I&#x27;m a new guy joining a team of five working on a Rust project. I&#x27;m introduced to &lt;code&gt;cargo-awesometestrunner&lt;&#x2F;code&gt; as they all use it to run the test suite of the app. So I head over to the docs, and I see &lt;code&gt;cargo install cargo-awesometestrunner --locked&lt;&#x2F;code&gt;, paste it in my terminal, and bam I&#x27;m ready to go.&lt;&#x2F;p&gt;
&lt;p&gt;But wait... &lt;&#x2F;p&gt;
&lt;p&gt;Jane on the team says, &lt;em&gt;&amp;quot;wait a sec, let&#x27;s be sure were using the same version so we can repro any problems together&amp;quot;&lt;&#x2F;em&gt;. Sure, that makes sense. So I run &lt;code&gt;cargo install cargo-awesometestrunner --version 0.5.23 --locked&lt;&#x2F;code&gt; because that&#x27;s what she&#x27;s got installed. &lt;&#x2F;p&gt;
&lt;p&gt;Bob a desk over is like &lt;em&gt;&amp;quot;Hang on Jane, why is your version so old? Didn&#x27;t you upgrade to version X to fix the bug Y we saw last week?&amp;quot;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Jane is now confused. &lt;em&gt;&amp;quot;What bug? Did I miss the Slack message sent to @channel to upgrade to latest?&amp;quot;&lt;&#x2F;em&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;Bob looks, realizing he forgot to send it.&lt;&#x2F;p&gt;
&lt;p&gt;Lizzy at the end of the table heard the discussion through her headphones and brings up &lt;em&gt;&amp;quot;We can&#x27;t install the new version yet, project ABC isn&#x27;t compatible. We gotta stay on the old version&amp;quot;&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Jane is now frustrated, Lizzy is distracted, Bob is annoyed.&lt;&#x2F;p&gt;
&lt;p&gt;And then there&#x27;s me, wondering why we all install things globally.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve touched a bunch of languages and tool sets over the years. Professionally I&#x27;ve mainly done Typescript&#x2F;Javascript, Python, and Go. In the JS world, npm+friends scopes all binary dependencies within &lt;code&gt;node_modules&lt;&#x2F;code&gt;, allowing them to be accessed by running something like &lt;code&gt;npm run eslint --help&lt;&#x2F;code&gt;. Python does something similar where all dependencies are inside a virtual environment (&lt;code&gt;.venv&lt;&#x2F;code&gt;) that you activate to update your shells paths.&lt;&#x2F;p&gt;
&lt;p&gt;As part of the official tooling, Rust is missing that at the moment. That&#x27;s totally fine, they&#x27;re busy building the really important stuff. However, when I&#x27;m onboarding new people, or full teams on to the Rust language coming from ecosystems like JS and Python, this can be hard to manage. CI is another story. It&#x27;s frustrating when something unique is breaking your CI workflows, only to find it&#x27;s because some global dependency updated that you forgot to pin.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s where &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;cargo-run-bin&quot;&gt;&lt;code&gt;cargo-run-bin&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; comes in. Instead of installing all the additional Rust CLIs and Cargo extensions globally, you &lt;em&gt;just&lt;&#x2F;em&gt; install cargo-run-bin, and it scopes all your tooling to each project.&lt;&#x2F;p&gt;
&lt;p&gt;It works by adding a block in your Cargo.toml specifying all the tooling and versions you&#x27;d like attached and available to the developers working on your project. For example, cargo-run-bin has the &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;cargo-run-bin&#x2F;blob&#x2F;master&#x2F;Cargo.toml#L33C1-L45C34&quot;&gt;following tools&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; style=&quot;background-color:#2b303b;color:#c0c5ce;&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span&gt;[package.metadata.bin]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-binstall &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.4.4&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-cmd &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.3.1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-deny &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.13.5&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-insta &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.31.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;locked &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-llvm-cov &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.5.25&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-nextest &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.9.57&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;locked &lt;&#x2F;span&gt;&lt;span&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#d08770;&quot;&gt;true &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-release &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.24.11&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;cargo-watch &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;8.4.0&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;committed &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.0.20&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;dprint &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;0.40.2&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;git-cliff &lt;&#x2F;span&gt;&lt;span&gt;= { &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bf616a;&quot;&gt;version &lt;&#x2F;span&gt;&lt;span&gt;= &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3be8c;&quot;&gt;1.3.1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, for something like &lt;code&gt;dprint&lt;&#x2F;code&gt;, I can run &lt;code&gt;cargo bin dprint&lt;&#x2F;code&gt; and it&#x27;ll run the exact version that&#x27;s specified in Cargo.toml. Any local or CI script that is executing &lt;code&gt;dprint&lt;&#x2F;code&gt;, I can go and update with the new &lt;code&gt;cargo bin&lt;&#x2F;code&gt; prefix, and I&#x27;ll for sure have all versions are locked in.&lt;&#x2F;p&gt;
&lt;p&gt;If you don&#x27;t want to wait to every dependency to build, run-bin can be paired with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cargo-bins&#x2F;cargo-binstall&quot;&gt;&lt;code&gt;cargo-binstall&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; where it&#x27;ll look to download precompiled releases before attempting to build from source simply by adding it to &lt;code&gt;[package.metadata.bin]&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The real killer feature that cargo-run-bin has is the capability to assigning Cargo aliases for any of the &lt;code&gt;cargo-*&lt;&#x2F;code&gt; tools by running &lt;code&gt;cargo bin --sync-aliases&lt;&#x2F;code&gt;, where it adds lines to &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;cargo-run-bin&#x2F;blob&#x2F;master&#x2F;.cargo&#x2F;config.toml&quot;&gt;&lt;code&gt;.cargo&#x2F;config.toml&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. With this, the conversation between my fictional team and I never happen. By running &lt;code&gt;cargo nextest run&lt;&#x2F;code&gt;, run-bin will download, cache, and execute version &lt;code&gt;0.9.57&lt;&#x2F;code&gt;. &lt;&#x2F;p&gt;
&lt;p&gt;This is not the first time I&#x27;ve solved this issue. Every time I pick up a new language, I look for what may be missing in my development experience, and build that first! Go has the same problem, and I solved for my own apps a couple of years back with &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;gomodrun&quot;&gt;gomodrun&lt;&#x2F;a&gt;, which does close enough to the same thing by producing a tools.go file for all binaries, and updating the lock file accordingly. &lt;&#x2F;p&gt;
&lt;p&gt;If you&#x27;re having the same kinda issues as my fictional team, or are preparing for the release of your new open source project, check out cargo-run-bin on &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;cargo-run-bin&quot;&gt;GitHub&lt;&#x2F;a&gt;! If you&#x27;re looking to scope binaries that live outside the Rust ecosystem, the sister project &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dustinblackman&#x2F;cargo-gha&quot;&gt;&lt;code&gt;cargo-gha&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; gets the job done.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks for reading!&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
