<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Romain Bruyère</title>
    <description>The latest articles on Forem by Romain Bruyère (@rombru).</description>
    <link>https://forem.com/rombru</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F364608%2F82c365bb-ece3-47bc-9d21-a06e9499392f.jpg</url>
      <title>Forem: Romain Bruyère</title>
      <link>https://forem.com/rombru</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rombru"/>
    <language>en</language>
    <item>
      <title>Building an IntelliJ Plugin with Debugger Integration</title>
      <dc:creator>Romain Bruyère</dc:creator>
      <pubDate>Sun, 22 Sep 2024 16:24:52 +0000</pubDate>
      <link>https://forem.com/rombru/building-an-intellij-plugin-with-debugger-integration-mgi</link>
      <guid>https://forem.com/rombru/building-an-intellij-plugin-with-debugger-integration-mgi</guid>
      <description>&lt;p&gt;Building an IntelliJ plugin for debugging purpose can offer valuable insights into the data being handled, allowing you present it more effectively and upgrade the developer experience. However, the limited documentation around IntelliJ’s APIs often makes plugin development challenging. In this guide, we’ll walk through the steps to create a plugin that can execute methods on objects available in the stack when the debugger is paused.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Plugin creation
&lt;/h2&gt;

&lt;p&gt;First, you will have to create an empty plugin. The easiest way to do it is directly inside IntelliJ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the &lt;strong&gt;New Project&lt;/strong&gt; wizard by selecting &lt;strong&gt;File | New | Project…&lt;/strong&gt; and fill in the required details:&lt;/li&gt;
&lt;li&gt;From the menu on the left, choose the &lt;strong&gt;IDE Plugin&lt;/strong&gt; project type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html" rel="noopener noreferrer"&gt;https://plugins.jetbrains.com/docs/intellij/creating-plugin-project.html&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Create an action
&lt;/h2&gt;

&lt;p&gt;The goal of this demo plugin will be to give to the user the power to execute a predefined method on a variable when the debugger is paused.&lt;/p&gt;

&lt;p&gt;Adding a new button in IntelliJ UI is the first step in designing the plugin behavior. It will create an entrypoint for the user to execute the plugin code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph6ber4n4w22o4iy7c6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fph6ber4n4w22o4iy7c6g.png" alt="Adding “My custom action” button" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The system designed for that in IntelliJ APIs is called an &lt;code&gt;Action&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;be.bruyere.romain.tutointellijplugindebug&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.actionSystem.ActionUpdateThread&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.actionSystem.AnAction&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.actionSystem.AnActionEvent&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.intellij.openapi.project.DumbAware&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomAction&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AnAction&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;DumbAware&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;actionPerformed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AnActionEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// TODO add action code&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AnActionEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;presentation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEnabledAndVisible&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getActionUpdateThread&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;ActionUpdateThread&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ActionUpdateThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BGT&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With a custom action like this one, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provide some code to be executed by the plugin, with &lt;code&gt;actionPerformed&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;Add logic if you want the action to be shown conditionnaly, with &lt;code&gt;update&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;Specify which thread will execute the &lt;code&gt;update&lt;/code&gt; method&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the plugin button to be shown to the user, you will have to define its anchor in &lt;code&gt;plugin.xml&lt;/code&gt; file, located in the &lt;code&gt;/resources/META-INF folder&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;actions&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"be.bruyere.romain.tutointellijplugindebug.CustomAction"&lt;/span&gt;
            &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"be.bruyere.romain.tutointellijplugindebug.CustomAction"&lt;/span&gt; &lt;span class="na"&gt;text=&lt;/span&gt;&lt;span class="s"&gt;"My custom action"&lt;/span&gt; &lt;span class="na"&gt;description=&lt;/span&gt;&lt;span class="s"&gt;"My custom action"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;add-to-group&lt;/span&gt; &lt;span class="na"&gt;group-id=&lt;/span&gt;&lt;span class="s"&gt;"XDebugger.ValueGroup"&lt;/span&gt; &lt;span class="na"&gt;anchor=&lt;/span&gt;&lt;span class="s"&gt;"first"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/action&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/actions&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the plugin button is placed as the first action in the right-click debugger menu. By running the Grable task &lt;code&gt;intellij.runPlugin&lt;/code&gt;, you can now try to use it.&lt;/p&gt;

&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://plugins.jetbrains.com/docs/intellij/basic-action-system.html" rel="noopener noreferrer"&gt;https://plugins.jetbrains.com/docs/intellij/basic-action-system.html&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Add a method invocation in debug mode
&lt;/h2&gt;

&lt;p&gt;To execute, on the fly, a method on an object when the debugger is paused, multiple steps are required:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the object reference&lt;/li&gt;
&lt;li&gt;Get the thread in which the method will be invoked&lt;/li&gt;
&lt;li&gt;Get the method reference&lt;/li&gt;
&lt;li&gt;Execute the method and get its return value&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before these steps, you need to enable the debugger features in your plugin. To do this, you’ll need to add a dependency on the &lt;code&gt;java&lt;/code&gt; plugin in the &lt;code&gt;build.gradle.kts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;intellij&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"2024.1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IC"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// To add&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.1 Get the object reference
&lt;/h3&gt;

&lt;p&gt;Jetbrains APIs provide a simple way to get the selected node from the right-click event context menu. The object reference value can then be accessed from there.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getObjectReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AnActionEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ObjectReferenceImpl&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;node&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;XDebuggerTreeActionBase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelectedNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;valueContainer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;valueContainer&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valueContainer&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;JavaValue&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;descriptor&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;ObjectReferenceImpl&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 Get the thread in which the method will be invoked
&lt;/h3&gt;

&lt;p&gt;When the debugger is paused, invoking a method on the fly must be done in a specific thread, called the manager thread. The manager thread manages tasks and operations related to the debugger, ensuring that certain operations are run on the correct thread during debugging sessions&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getManagerThread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AnActionEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;DebuggerManagerThreadImpl&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;node&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;XDebuggerTreeActionBase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSelectedNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dataContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;valueContainer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;valueContainer&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valueContainer&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;JavaValue&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;evaluationContext&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;managerThread&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As for the object reference, the manager thread can be accessed from the selected node.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Get the method reference
&lt;/h3&gt;

&lt;p&gt;With the object reference, any method can be accessed by its name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Example: getMethod(myObjectReference, "toString")&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetObjectRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectReferenceImpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;targetObjectRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;referenceType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;methodsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;methodName&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.4 Execute the method and get its return value
&lt;/h3&gt;

&lt;p&gt;Using the method and its associated object reference, you can construct a command that encapsulates the method call. You can then execute this command on the manager thread, wait for the response and return the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;executeMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AnActionEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;targetObjectRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectReferenceImpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;managerThread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DebuggerManagerThreadImpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DebuggerManagerEx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstanceEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debuggerSession&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;suspendManager&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;pausedContext&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomDebuggerCommandImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetObjectRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;managerThread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invokeAndWait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command &lt;code&gt;CustomDebuggerCommandImpl&lt;/code&gt; is not built in Jetbrains APIs. It’s a concrete implementation of the abstract class &lt;code&gt;DebuggerCommandImpl&lt;/code&gt;, representing a specific command that executes within the context of IntelliJ’s debugging system. You’ll have to add that class by yourself in the your plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomDebuggerCommandImpl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SuspendContextImpl&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;objectReference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ObjectReferenceImpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DebuggerCommandImpl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;threadReference&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;frameProxy&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;threadProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;threadReference&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectReference&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invokeMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;threadReference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="nc"&gt;ObjectReferenceImpl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;INVOKE_SINGLE_THREADED&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://docs.oracle.com/en/java/javase/13/docs/api/jdk.jdi/module-summary.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/javase/13/docs/api/jdk.jdi/module-summary.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/JetBrains/intellij-community/tree/master" rel="noopener noreferrer"&gt;https://github.com/JetBrains/intellij-community/tree/master&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Use of the result
&lt;/h2&gt;

&lt;p&gt;The result obtained from the method invocation is not a basic object type like &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;Integer&lt;/code&gt;, or any other standard object. Instead, it is a reference to an object created within the debugging context.&lt;/p&gt;

&lt;p&gt;For example, if the invoked method was &lt;code&gt;toString&lt;/code&gt;, you would receive a &lt;code&gt;StringReferenceImpl&lt;/code&gt;. You can then retrieve the string value from that object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;executeMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;objectReference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;managerThread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;stringValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;StringReferenceImpl&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringValue&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are various other implementations of type references, such as &lt;code&gt;IntegerValueImpl&lt;/code&gt; or, more generally, &lt;code&gt;ObjectReferenceImpl&lt;/code&gt; for custom classes.&lt;/p&gt;

&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://github.com/JetBrains/intellij-deps-jdi/tree/master/src/main/java/com/jetbrains/jdi" rel="noopener noreferrer"&gt;https://github.com/JetBrains/intellij-deps-jdi/tree/master/src/main/java/com/jetbrains/jdi&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Full code example
&lt;/h2&gt;

&lt;p&gt;Now that you understand the details of this IntelliJ plugin development process, here is a complete working example of the code: &lt;a href="https://github.com/rombru/tuto-intellij-plugin-debug" rel="noopener noreferrer"&gt;https://github.com/rombru/tuto-intellij-plugin-debug&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you'd like to see how this process was applied to create a published plugin, check out this plugin I developed for visualizing geometries on a map in debug mode:&lt;br&gt;
&lt;a href="https://plugins.jetbrains.com/plugin/25275-geometry-viewer" rel="noopener noreferrer"&gt;https://plugins.jetbrains.com/plugin/25275-geometry-viewer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/rombru/geometry-viewer" rel="noopener noreferrer"&gt;https://github.com/rombru/geometry-viewer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0mpieozhopq5i3rd33o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0mpieozhopq5i3rd33o.png" alt="Conclusion image" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>softwareengineering</category>
      <category>backend</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Docker and WSL2 without Docker Desktop</title>
      <dc:creator>Romain Bruyère</dc:creator>
      <pubDate>Thu, 09 May 2024 20:45:13 +0000</pubDate>
      <link>https://forem.com/rombru/docker-and-wsl2-without-docker-desktop-3pg3</link>
      <guid>https://forem.com/rombru/docker-and-wsl2-without-docker-desktop-3pg3</guid>
      <description>&lt;p&gt;Using Docker on Windows has grown more challenging over the past few years. This guide aims to walk you through the process, from start to finish, to help you make the most of Docker on Windows without having to install Docker Desktop.&lt;/p&gt;

&lt;p&gt;To use Docker without Docker Desktop, you’ll need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install WSL2, to serve as a runtime environment for Docker Engine&lt;/li&gt;
&lt;li&gt;Install Docker Engine inside WSL2, to be able to run containers&lt;/li&gt;
&lt;li&gt;Expose Docker Engine to be able to access it from Windows&lt;/li&gt;
&lt;li&gt;Install Docker command-line tools on Windows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install WSL2
&lt;/h2&gt;

&lt;p&gt;WSL2, or the Windows Subsystem for Linux, allows you to run a Linux distribution on Windows. To install it with the default Ubuntu distribution, open a terminal in administrator mode and use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to install a different Linux distribution instead of the default Ubuntu, you can list the available distributions and then install your preferred one using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;--online&lt;/span&gt;
wsl &lt;span class="nt"&gt;--install&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &amp;lt;DistroName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s not mandatory, but depending on your setup, you might find it helpful to limit the resources allocated to WSL2. To do this, create a file named &lt;code&gt;.wslconfig&lt;/code&gt; in your user folder. You can quickly access your user folder by typing &lt;code&gt;%UserProfile%&lt;/code&gt; in the File Explorer's search bar.&lt;/p&gt;

&lt;p&gt;Here’s an example of what a &lt;code&gt;.wslconfig&lt;/code&gt; file might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[wsl2]&lt;/span&gt;
&lt;span class="py"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4GB &lt;/span&gt;
&lt;span class="py"&gt;processors&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing WSL2, you can start it by typing &lt;code&gt;wsl&lt;/code&gt; in a terminal, or by launching the WSL program from your Windows Start menu. Once WSL2 is open, update your Linux distribution to ensure all packages are up to date with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To learn more about configuring WSL2 distributions and resource allocation, refer to the following sources.&lt;/p&gt;

&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install"&gt;https://learn.microsoft.com/en-us/windows/wsl/install&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/windows/wsl/wsl-config"&gt;https://learn.microsoft.com/en-us/windows/wsl/wsl-config&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Install Docker Engine on WSL2
&lt;/h2&gt;

&lt;p&gt;Next, let’s install the Docker Engine, which is the core component that runs Docker containers. The following two blocks of commands will first add the Docker apt repository and then install Docker. You can execute them directly in the WSL2 terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;ca-certificates curl
&lt;span class="nb"&gt;sudo install&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; 0755 &lt;span class="nt"&gt;-d&lt;/span&gt; /etc/apt/keyrings
&lt;span class="nb"&gt;sudo &lt;/span&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/docker.asc
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;a+r /etc/apt/keyrings/docker.asc

&lt;span class="c"&gt;# Add the repository to Apt sources:&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dpkg &lt;span class="nt"&gt;--print-architecture&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /etc/os-release &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION_CODENAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; stable"&lt;/span&gt; | &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that Docker is installed, let’s confirm that it’s working correctly. The following command will download and run the &lt;code&gt;hello-world&lt;/code&gt; container. If the installation was successful, it should display a confirmation message and then exit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, you need to use sudo with Docker commands for elevated permissions. To run Docker without sudo, you can create a group docker for Docker users and add your current user to that group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;groupadd docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On some distributions, the Docker group is created by default. You only need to add your user to this group to have the permission to run Docker without sudo. The Docker group is automatically managed by the Docker Engine, ensuring that only users in this group have permission to run Docker commands. After adding yourself to the Docker group, exit WSL2, then restart it, or simply log out and back in. Once you re-open WSL2, you should be able to use Docker without the need for sudo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re using a non-default WSL distribution, like a custom Linux distro, Docker might not start automatically when you launch WSL. To ensure Docker starts every time you open WSL, use the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;docker.service
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;containerd.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://docs.docker.com/engine/install/ubuntu/"&gt;https://docs.docker.com/engine/install/ubuntu/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.docker.com/engine/install/linux-postinstall/"&gt;https://docs.docker.com/engine/install/linux-postinstall/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Expose Docker Engine on Windows
&lt;/h2&gt;

&lt;p&gt;To access the Docker Engine from Windows, you’ll need to configure remote access for Docker. There are two ways to do this, by modifying the docker daemon, or by overriding systemd launch configuration.&lt;/p&gt;
&lt;h3&gt;
  
  
  With daemon.json
&lt;/h3&gt;

&lt;p&gt;For that method, you need to create or edit the &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt; file inside WSL2. Navigate to the &lt;code&gt;/etc/docker&lt;/code&gt; directory and use the following command to edit the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vi daemon.json

&lt;span class="c"&gt;# In vi,&lt;/span&gt;
&lt;span class="c"&gt;# You press the key 'I' to enter in insert mode and be able to edit the file&lt;/span&gt;
&lt;span class="c"&gt;# You press the key 'ESC', once you have finished inserting&lt;/span&gt;
&lt;span class="c"&gt;# You press the keys ':wq' to save and quit editing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add this content to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hosts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"unix:///var/run/docker.sock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp://0.0.0.0:2375"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  With systemd
&lt;/h3&gt;

&lt;p&gt;With that method, to override the systemd launch configuration for the Docker service, you can create or edit a systemd override file by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl edit docker.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add, or modify, the following lines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to only use one of the two methods, not both. No matter the method you choose, for these changes to be applied, you will need to restart the Docker service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart docker.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm that Docker is exposed on Windows, visit the URL &lt;a href="http://localhost:2375/version"&gt;http://localhost:2375/version&lt;/a&gt;. If you receive a response showing the current version of the Docker Engine, it means the exposure is successful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the link between WSL2 andWindows
&lt;/h3&gt;

&lt;p&gt;To ensure that the Docker agent on Windows can detect the Docker Engine installed on WSL2, you need to establish a connection between the two by adding a DOCKER_HOSTenvironment variable on Windows. It specifies the address of the Docker Engine and determines where Docker commands will be sent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh34l311y3kger2snwfq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh34l311y3kger2snwfq.png" alt="Adding an environment variable" width="720" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on the configuration of your computer, and the activation of IPv6, you can set it to &lt;code&gt;tcp://localhost:2375&lt;/code&gt; or &lt;code&gt;tcp://[::1]:2375&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://docs.docker.com/config/daemon/remote-access/"&gt;https://docs.docker.com/config/daemon/remote-access/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/styblope/dc55e0ad2a9848f2cc3307d4819d819f"&gt;https://gist.github.com/styblope/dc55e0ad2a9848f2cc3307d4819d819f&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Install Docker CLI on Windows
&lt;/h2&gt;

&lt;p&gt;The final step is to install the Docker CLI on Windows. The CLI consists of several executable files that must be placed in specific locations within the Windows filesystem.&lt;/p&gt;

&lt;p&gt;First, you must install the main executable. Create a folder for the installation wherever you’d like in the Windows filesystem, and then add that folder to your PATH. Next, visit &lt;a href="https://download.docker.com/win/static/stable/x86_64/"&gt;https://download.docker.com/win/static/stable/x86_64/&lt;/a&gt;, download the latest version, and unzip the executables into the folder you just created.&lt;/p&gt;

&lt;p&gt;You should now be able to run most Docker commands. To test it, try executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it doesn’t work, one advice is to try with the other value for the &lt;code&gt;DOCKER_HOST&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plugins, Buildx and Compose
&lt;/h3&gt;

&lt;p&gt;Simply installing the main executable usually isn’t enough if you want to use all of Docker’s features. The builder included with the executable is the legacy builder, and the &lt;code&gt;docker compose&lt;/code&gt; command will be unavailable. To access those additional features, you'll need to install some plugins.&lt;/p&gt;

&lt;p&gt;In your user folder, accessible by typing &lt;code&gt;%UserProfile%&lt;/code&gt; in the File Explorer's search bar, create the folder tree &lt;code&gt;.docker\cli-plugins\&lt;/code&gt; if it doesn’t exists already.&lt;/p&gt;

&lt;p&gt;To install the newest builder, download the latest version of the buildxplugin by visiting &lt;a href="https://github.com/docker/buildx/releases"&gt;https://github.com/docker/buildx/releases&lt;/a&gt;. Find the most recent release, go to the “Assets” section, and expand the list of assets. Download the file that ends with &lt;code&gt;windows-amd64.exe&lt;/code&gt;, like &lt;code&gt;buildx-v0.14.0.windows-amd64.exe&lt;/code&gt;. Place the downloaded file in the &lt;code&gt;cli-plugins&lt;/code&gt; folder you created earlier, and rename it to &lt;code&gt;docker-buildx.exe&lt;/code&gt;. Now, the command &lt;code&gt;docker build&lt;/code&gt; will automatically use the new builder.&lt;/p&gt;

&lt;p&gt;To install docker compose tool, download the latest version of the plugin by visiting &lt;a href="https://github.com/docker/compose/releases"&gt;https://github.com/docker/compose/releases&lt;/a&gt;. Find the most recent release, go to the “Assets” section, and expand the list of assets. Download the file that ends with &lt;code&gt;windows-x86_64.exe&lt;/code&gt;, like &lt;code&gt;docker-compose-windows-w86_64.exe&lt;/code&gt;. Place the downloaded file in the &lt;code&gt;cli-plugins&lt;/code&gt; folder you created earlier, and rename it to &lt;code&gt;docker-compose.exe&lt;/code&gt;. Now, we can use the command &lt;code&gt;docker compose&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The installation is finished ! 🥳&lt;br&gt;
I hope everything is working fine ! Don’t forget to start WSL2 when you want to use Docker.&lt;/p&gt;

&lt;p&gt;Sources:&lt;br&gt;
&lt;a href="https://docs.docker.com/engine/install/binaries/#install-server-and-client-binaries-on-windows"&gt;https://docs.docker.com/engine/install/binaries/#install-server-and-client-binaries-on-windows&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/docker/buildx/releases"&gt;https://github.com/docker/buildx/releases&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/docker/compose/releases"&gt;https://github.com/docker/compose/releases&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>wsl2</category>
      <category>windows</category>
    </item>
  </channel>
</rss>
