<?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: Arash Outadi</title>
    <description>The latest articles on Forem by Arash Outadi (@arashout).</description>
    <link>https://forem.com/arashout</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%2F287490%2Ff1148399-0c58-42bf-8723-73f4f68cd709.jpeg</url>
      <title>Forem: Arash Outadi</title>
      <link>https://forem.com/arashout</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/arashout"/>
    <language>en</language>
    <item>
      <title>Ensure auto-generated code is always up-to-date with compile-time assertions in Go</title>
      <dc:creator>Arash Outadi</dc:creator>
      <pubDate>Thu, 30 Jul 2020 17:58:34 +0000</pubDate>
      <link>https://forem.com/arashout/ensure-auto-generated-code-is-always-up-to-date-with-compile-time-assertions-in-go-48nc</link>
      <guid>https://forem.com/arashout/ensure-auto-generated-code-is-always-up-to-date-with-compile-time-assertions-in-go-48nc</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Do you get annoyed when others (or you) forget to run the code generation command and now nothing works/code is out-dated?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://commaok.xyz/post/compile-time-assertions/"&gt;Compile Time Assertions&lt;/a&gt; to the rescue!&lt;/p&gt;

&lt;h1&gt;
  
  
  Scenario
&lt;/h1&gt;

&lt;p&gt;Suppose you have an interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WithMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This interface has an associated implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterfaceImpl&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;privateField&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;MyInterfaceImpl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ... implementation code&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which you've have been auto-generating &lt;a href="https://stackoverflow.com/questions/3622455/what-is-the-purpose-of-mock-objects"&gt;mock objects&lt;/a&gt; for using the awesome &lt;a href="https://github.com/vektra/mockery"&gt;mockery package&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Why Though
&lt;/h3&gt;

&lt;p&gt;You are doing this because you want users of your library to be able to mock your library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thus allowing them to isolate their own code when writing unit tests.&lt;/li&gt;
&lt;li&gt;Meaning we don't actually use this mock in OUR tests, it is used by OTHERS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the interface definition above is augmented with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Generate mocks by running "go generate ./..."&lt;/span&gt;
&lt;span class="c"&gt;// go:generate mockery --name MyInteface&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WithMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which produces when &lt;code&gt;go generate ./...&lt;/code&gt; is ran:&lt;br&gt;
&lt;code&gt;mocks/MyInterface.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// MyInterface is an autogenerated mock type for the MyInterface type&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// WithMethod provides a mock function with given fields: method&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;MyInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;WithMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pkg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c"&gt;// ... some mock implementation code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;Now what happens when Greg who isn't aware of the auto-generated code, adds another method to &lt;code&gt;MyInterface&lt;/code&gt; and &lt;code&gt;MyInterfaceImpl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WithMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt;
    &lt;span class="n"&gt;WithAnotherMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="c"&gt;// New&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since the &lt;code&gt;MyInterface&lt;/code&gt; has changed but Greg didn't auto-generate the mocks using &lt;code&gt;go generate ./...&lt;/code&gt;, the mock object will not fulfill the interface and cannot be used for testing by downstream users (Thanks Greg)!&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;Add a &lt;a href="https://commaok.xyz/post/compile-time-assertions/"&gt;compile-assertion&lt;/a&gt; above the interface definition after you have initially generated the mock object (Also add --inpackage flag to go generate command to avoid import cycles).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Generate mocks by running "go generate ./..."&lt;/span&gt;
&lt;span class="c"&gt;// go:generate mockery --name MyInteface --inpackage&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MockMyInterface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c"&gt;// COMPILE-TIME Assertion&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WithMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now if Greg adds another method but forgets to run &lt;code&gt;go generate&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;MockMyInterface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WithMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt;
    &lt;span class="n"&gt;WithAnotherMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;MyInterface&lt;/span&gt; &lt;span class="c"&gt;// New&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;He will get hit with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cannot use &amp;amp;MockMyInterface literal (type *MockMyInterface) as type MyInterface in assignment:
    *MockMyInterface does not implement MyInterface (missing WithAnotherMethod method)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At which point, he might realize that he needs to add the method to the mock object using &lt;code&gt;go generate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Caveat: You will need to comment out the compile-time assertion &lt;code&gt;var _ MyInterface = &amp;amp;MockMyInterface{}&lt;/code&gt; when running &lt;code&gt;go generate&lt;/code&gt;/&lt;code&gt;mockery&lt;/code&gt; tool&lt;/p&gt;

</description>
      <category>go</category>
      <category>codegeneration</category>
      <category>interface</category>
    </item>
    <item>
      <title>Adding Contexts via Go AST (Code Instrumentation) </title>
      <dc:creator>Arash Outadi</dc:creator>
      <pubDate>Wed, 25 Dec 2019 06:54:42 +0000</pubDate>
      <link>https://forem.com/arashout/adding-contexts-via-go-ast-code-instrumentation-2ko7</link>
      <guid>https://forem.com/arashout/adding-contexts-via-go-ast-code-instrumentation-2ko7</guid>
      <description>&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;You changed one function to require a &lt;code&gt;ctx context.Context&lt;/code&gt; and now you have to change the function signatures of the&lt;br&gt;
all the upstream functions in your codebase 😠!&lt;br&gt;&lt;br&gt;
Do you have to make all these changes manually or can you automate the process somehow?&lt;/p&gt;

&lt;p&gt;We can automate it using Go's AST.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Check out this playground link to see how to source code can be programmatically changed to include the proper arguments/parameters: &lt;a href="https://play.golang.org/p/b8J5BykQjK-"&gt;PLAYGROUND&lt;/a&gt;&lt;br&gt;
We'll describe how it all works throughout the tutorial&lt;/p&gt;
&lt;h2&gt;
  
  
  Illustration
&lt;/h2&gt;

&lt;p&gt;We want to change this function to what is commented out in the &lt;code&gt;TODO:&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And imagine the function sits inside the fictitious file below, with many other functions calling it.&lt;br&gt;&lt;br&gt;
Again the &lt;code&gt;TODO:&lt;/code&gt;s indicate what needs to change to make this file compile.&lt;br&gt;&lt;br&gt;
NOTE: The other functions are not important, only there to illustrate we have to change all the functions that call our changed function&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fictitious File&lt;/strong&gt; Notice all the TODOs&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Manual Solution
&lt;/h2&gt;

&lt;p&gt;Fixing this manually, usually involves a trial and error solution process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Adjust the function body to correctly call your new function with &lt;code&gt;ctx&lt;/code&gt; arguments
&lt;/li&gt;
&lt;li&gt;Adjust the function definition/signature to include a &lt;code&gt;ctx context.Context&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;Iterate until the compiler no longer complains&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;a&gt; Programmatic Solution (Pseudo-Code)
&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The algorithm for the manual solution is very simple, so on a high level to automate this process we can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parse the Go code &lt;/li&gt;
&lt;li&gt;Generate an &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;AST&lt;/a&gt;(Abstract Syntax Tree) [3]&lt;/li&gt;
&lt;li&gt;Programmatically determine where we need "inject" code, specifically:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ctx&lt;/code&gt; argument to a function call&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ctx context.Context&lt;/code&gt; function parameter to function declaration&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Edit the AST&lt;/li&gt;
&lt;li&gt;Iterate until there are no more places where an "injection" is required&lt;/li&gt;
&lt;li&gt;Convert the AST back into the text representation -&amp;gt; Our new Golang source code&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Pre-Requisites
&lt;/h1&gt;

&lt;p&gt;In this tutorial I assume that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are proficient with Go&lt;/li&gt;
&lt;li&gt;Somewhat familiar with what an AST is

&lt;ul&gt;
&lt;li&gt;If you want to learn more about Go's AST, I recommend this &lt;a href="https://commandercoriander.net/blog/2016/12/30/reading-go-ast/"&gt;post from Eno Compton&lt;/a&gt;[7]&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Tutorial Conventions
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Playground Links
&lt;/h2&gt;

&lt;p&gt;After a code example, I will provide a full working example via the Go Playground see you can run the code for yourself.&lt;br&gt;
Look out for &lt;a href=""&gt;PLAYGROUND&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Brevity
&lt;/h2&gt;

&lt;p&gt;I will often only include the minimal amount of code to demonstrate a new concept in the code examples and will generally cut out any boiler-plate code.&lt;br&gt;
Look for the Playground links for full working examples.&lt;/p&gt;
&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Libraries
&lt;/h2&gt;

&lt;p&gt;Note in this tutorial we will be using these libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;github.com/dave/dst (Alternative to &lt;code&gt;go/ast&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can download them with the &lt;code&gt;go get&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;
go get github.com/dave/dst
&lt;/pre&gt;    

&lt;p&gt;&lt;code&gt;github.com/dave/dst&lt;/code&gt; is a fork of the official &lt;code&gt;go/ast&lt;/code&gt; package that is meant specifically for &lt;strong&gt;instrumenting&lt;/strong&gt; go code.&lt;br&gt;&lt;br&gt;
In contrast &lt;code&gt;go/ast&lt;/code&gt; was primarily meant for code generation.&lt;br&gt;&lt;br&gt;
This is an important difference because in code instrumentation, we only want to change a very specific region of code and leave the rest of the AST exactly as it was. &lt;code&gt;go/ast&lt;/code&gt; has a difficulties &lt;a href="https://github.com/golang/go/issues/20744"&gt;achieving this, especially with comments&lt;/a&gt; [4]   &lt;/p&gt;
&lt;h1&gt;
  
  
  Code
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Step 0 - Visualize the AST
&lt;/h2&gt;

&lt;p&gt;Using this &lt;a href="http://goast.yuroyoro.net/"&gt;go-ast visualizer&lt;/a&gt;, we can get an idea of what the Go AST looks like and what we need to look for when injecting new code [5].&lt;br&gt;&lt;br&gt;
So go to &lt;a href="http://goast.yuroyoro.net/"&gt;http://goast.yuroyoro.net/&lt;/a&gt; and play around with these &lt;a href="https://gist.github.com/arashout/3f3bad0bf3d70dc70a8e4b6fec568313.js"&gt;above gists&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Our primary focus should be on the on the &lt;a href="https://godoc.org/github.com/dave/dst#FuncDecl"&gt;&lt;code&gt;FuncDecl&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://godoc.org/github.com/dave/dst#CallExpr"&gt;&lt;code&gt;CallExpr&lt;/code&gt;&lt;/a&gt; Nodes since our injection points will be either when we are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Defining a function &amp;lt;-- Might need to add a &lt;code&gt;ctx context.Context&lt;/code&gt; parameter&lt;/li&gt;
&lt;li&gt;Calling a function &amp;lt;-- Might need to add a &lt;code&gt;ctx&lt;/code&gt; argument&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 1 - Use "dst" to parse Go code
&lt;/h2&gt;

&lt;p&gt;Before we start jumping into the logic of the program, let's just see a quick demo of how we parse Go code using the "dave/dst" package and print out the AST representation of the &lt;a href="https://godoc.org/github.com/dave/dst#FuncDecl"&gt;&lt;code&gt;FuncDecl&lt;/code&gt;&lt;/a&gt; nodes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://play.golang.org/p/w740yqGMDUY"&gt;PLAYGROUND&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've left comments in the above code snippet, so be sure to read those before moving on. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 - Helper Functions
&lt;/h2&gt;

&lt;p&gt;Remember that we either need to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;ctx context.Context&lt;/code&gt; parameter to a function declaration (&lt;code&gt;FuncDecl&lt;/code&gt; Node)&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;ctx&lt;/code&gt; argument to a function call (&lt;code&gt;CallExpr&lt;/code&gt;)
The Go AST structs for these two actions can be defined as follows:
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3 - Editing the AST
&lt;/h2&gt;

&lt;p&gt;To demonstrate how to add arguments and parameters using our helper functions, observe the following "naive" &lt;code&gt;applyFunc&lt;/code&gt; that adds an additional &lt;code&gt;ctx&lt;/code&gt; argument and &lt;code&gt;ctx context.Context&lt;/code&gt; parameter to every function call and function definition respectively.&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Let's use our applyFunc and print out the source code! Notice I added another utility function for converting the AST representation into actual Go code.&lt;br&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://play.golang.org/p/x6WiOgwNpTm"&gt;PLAYGROUND&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Notice that this &lt;code&gt;applyFunc&lt;/code&gt; doesn't check if it is actually necessary to inject additional code. It just does it.&lt;br&gt;&lt;br&gt;
To see why this &lt;code&gt;applyFunc&lt;/code&gt; is not adequate try running changing the &lt;code&gt;srcCodeString&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;alreadyHasContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Do some important work..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;makeDownstreamRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Some important data!"&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;Or if you prefer go to playground link below.&lt;br&gt;&lt;br&gt;
&lt;a href="https://play.golang.org/p/6txVwqu164P"&gt;PLAYGROUND&lt;/a&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4 - Being Selective
&lt;/h2&gt;

&lt;p&gt;Instead of indiscriminately adding &lt;code&gt;ctx&lt;/code&gt; everywhere like in the naive implementation, this time we will examine the nodes in the AST to determine where we need to inject a &lt;code&gt;ctx&lt;/code&gt; argument or &lt;code&gt;ctx content.Context&lt;/code&gt; function parameter.&lt;/p&gt;
&lt;h3&gt;
  
  
  FuncDecl Node
&lt;/h3&gt;

&lt;p&gt;Let's look at the &lt;code&gt;FuncDecl&lt;/code&gt;, node for the following code.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;h4&gt;
  
  
  Function Signature
&lt;/h4&gt;

&lt;p&gt;Specifically let's start the with &lt;a href="https://godoc.org/github.com/dave/dst#FuncType"&gt;&lt;code&gt;FuncType&lt;/code&gt;&lt;/a&gt;, which essentially describes the function signature&lt;br&gt;
&lt;a href="/img/changedFn_type.png" class="article-body-image-wrapper"&gt;&lt;img src="/img/changedFn_type.png" alt="changedFn signature"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;The feature that we care about most is &lt;a href="https://godoc.org/github.com/dave/dst#SelectorExpr"&gt;&lt;code&gt;SelectorExpr&lt;/code&gt;&lt;/a&gt; that contains the &lt;a href="https://godoc.org/github.com/dave/dst#Ident"&gt;&lt;code&gt;Ident&lt;/code&gt;&lt;/a&gt; for the &lt;code&gt;Context&lt;/code&gt; parameter. With this in mind, we can construct a function to check if the &lt;code&gt;FuncDecl&lt;/code&gt; contains a &lt;code&gt;context.Context&lt;/code&gt; as a parameter in the function signature&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
If it already has a &lt;code&gt;context.Context&lt;/code&gt; then we don't need to do anything and can move on.
&lt;h4&gt;
  
  
  Function Body
&lt;/h4&gt;

&lt;p&gt;To determine if we need to add a &lt;code&gt;context.Context&lt;/code&gt; to the function signature, we need to examine the function body to check if there are any calls to functions which require a &lt;code&gt;context.Context&lt;/code&gt; parameter.&lt;br&gt;&lt;br&gt;
At this point, you might be asking how we can know if a function requires a &lt;code&gt;Context&lt;/code&gt; in the first place?&lt;/p&gt;

&lt;p&gt;Below are two possible ways of determining that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If there is a function call to a function we have already determined needs a &lt;code&gt;Context&lt;/code&gt; (Infinite Recursion 😆)

&lt;ul&gt;
&lt;li&gt;Obviously, we would need a mechanism for recording which functions have &lt;code&gt;Context&lt;/code&gt; parameters&lt;/li&gt;
&lt;li&gt;Also we need a "seed" function which already has &lt;code&gt;Context&lt;/code&gt; parameter, so we have at-least one function which we KNOW requires &lt;code&gt;Context&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We can naively look for function calls that have a argument named &lt;code&gt;ctx&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this tutorial, we'll go over method 2 as it slightly simpler and doesn't require an initial scan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Functions To Examine The &lt;code&gt;FuncDecl&lt;/code&gt; &amp;amp; &lt;code&gt;CallExpr&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
Note: the global map &lt;code&gt;needsContextsFuncs&lt;/code&gt; (However, we use the &lt;code&gt;map&lt;/code&gt; as a Set)
&lt;h2&gt;
  
  
  Step 5 - Selective ApplyFunc
&lt;/h2&gt;

&lt;p&gt;To make the our &lt;code&gt;ApplyFunc&lt;/code&gt; function more selective we will have to examine the &lt;code&gt;FuncDecl&lt;/code&gt; and &lt;code&gt;CallExpr&lt;/code&gt; nodes&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selective Apply Function&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Step 6 - Is this it?
&lt;/h2&gt;

&lt;p&gt;So now we have a Selective &lt;code&gt;ApplyFunc&lt;/code&gt; will it be able to add all the &lt;code&gt;Context&lt;/code&gt;s now?&lt;br&gt;&lt;br&gt;
&lt;a href="https://play.golang.org/p/pQqwOwBjaU2"&gt;PLAYGROUND&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Spoilers... It doesn't&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 7 - Iterative Solution
&lt;/h2&gt;

&lt;p&gt;Our new ApplyFunc only manages to change the immediate ancestors, but if want the changes to propagate up further we need an iterative solution.&lt;br&gt;
Remember Step 5 of our pseudo code algorithm&lt;/p&gt;
&lt;h3&gt;
  
  
  Infinite For Loop?
&lt;/h3&gt;

&lt;p&gt;To make sure that all the ancestors are updated we could simply run the &lt;code&gt;Apply&lt;/code&gt; with our &lt;code&gt;ApplyFunc&lt;/code&gt; over and over again inside a &lt;code&gt;for {}&lt;/code&gt; loop, but when should we stop?&lt;br&gt;
A simple idea that will work is to stop when the previous code is the same as the current code generated.&lt;br&gt;&lt;br&gt;
That is when the &lt;code&gt;ApplyFunc&lt;/code&gt; deems that there are no new areas to add &lt;code&gt;ctx&lt;/code&gt; arguments or &lt;code&gt;ctx context.Context&lt;/code&gt; parameters.&lt;/p&gt;
&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;a href="https://play.golang.org/p/p9hRs_Sz63c"&gt;PLAYGROUND&lt;/a&gt;
&lt;h3&gt;
  
  
  Optional - Add comments describing iteration
&lt;/h3&gt;

&lt;p&gt;Lastly, as a illustrative exercise, below is a playground link for adding comments that describe in which iteration the &lt;code&gt;ctx&lt;/code&gt;/&lt;code&gt;ctx context.Context&lt;/code&gt; was added&lt;br&gt;&lt;br&gt;
&lt;a href="https://play.golang.org/p/ukgiuMJIhSC"&gt;PLAYGROUND&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Added on 'ctx context.Context' parameter on iteration 0&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;changedFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Do some important work..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// Now also make a downstream call&lt;/span&gt;
    &lt;span class="n"&gt;makeDownstreamRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Some important data!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Added on 'ctx context.Context' parameter on iteration 1&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;needsctx1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;changedFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Added on ctx arg on iteration 0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Added on 'ctx context.Context' parameter on iteration 2&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;needsctx2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;needsctx1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Added on ctx arg on iteration 1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Added on 'ctx context.Context' parameter on iteration 1&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;needsctx3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;needsctx2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;// Added on ctx arg on iteration 2&lt;/span&gt;

        &lt;span class="n"&gt;changedFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Added on ctx arg on iteration 0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;SS&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="c"&gt;// Added on 'ctx context.Context' parameter on iteration 2&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rec&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;SS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&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;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;needsctx1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Added on ctx arg on iteration 1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Future Work
&lt;/h1&gt;

&lt;p&gt;It's not to hard to extend this to changing the AST of a file via &lt;a href="https://godoc.org/github.com/dave/dst/decorator#ParseFile"&gt;&lt;code&gt;ParseFile&lt;/code&gt;&lt;/a&gt; and entire directories with &lt;a href="https://godoc.org/github.com/dave/dst/decorator#ParseDir"&gt;&lt;code&gt;ParseDir&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there is any interest, I'm happy to make a second tutorial covering these topics and additionally how to handle imported packages.&lt;/p&gt;

&lt;h1&gt;
  
  
  Thanks
&lt;/h1&gt;

&lt;p&gt;Thanks for reading this tutorial about using Go's AST I hope you found it useful.&lt;br&gt;&lt;br&gt;
Let me know if you liked it or hated it!&lt;br&gt;&lt;br&gt;
Also huge thanks to &lt;a href="https://github.com/dave"&gt;Dave&lt;/a&gt; for making the awesome &lt;a href="https://github.com/dave/dst"&gt;&lt;code&gt;dst&lt;/code&gt;&lt;/a&gt; package!&lt;br&gt;&lt;br&gt;
As well as all the other sources I used to make this tutorial&lt;/p&gt;

&lt;h1&gt;
  
  
  Related Reading
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;I recommend this article about &lt;a href="https://developers.mattermost.com/blog/instrumenting-go-code-via-ast/"&gt;Instrumenting Go code via AST&lt;/a&gt; which served as the basis of this post.
In some ways, they are solving a simpler problem because the function signature that they need to change is always the same, where in our case it can vary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Sources
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://faiface.github.io/post/context-should-go-away-go2/"&gt;https://faiface.github.io/post/context-should-go-away-go2/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@cep21/how-to-correctly-use-context-context-in-go-1-7-8f2c0fafdf39"&gt;https://medium.com/@cep21/how-to-correctly-use-context-context-in-go-1-7-8f2c0fafdf39&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;https://en.wikipedia.org/wiki/Abstract_syntax_tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/golang/go/issues/20744"&gt;https://github.com/golang/go/issues/20744&lt;/a&gt; "Free-floating comments are single-biggest issue when manipulating the AST"&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://goast.yuroyoro.net/"&gt;http://goast.yuroyoro.net/&lt;/a&gt; Golang AST visualizer&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://godoc.org/github.com/dave/dst"&gt;https://godoc.org/github.com/dave/dst&lt;/a&gt; GoDoc for github.com/dave/dst package&lt;/li&gt;
&lt;li&gt; &lt;a href="https://commandercoriander.net/blog/2016/12/30/reading-go-ast/"&gt;https://commandercoriander.net/blog/2016/12/30/reading-go-ast/&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>go</category>
      <category>ast</category>
      <category>codegeneration</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Wrapper functions for dangerous commands</title>
      <dc:creator>Arash Outadi</dc:creator>
      <pubDate>Fri, 20 Dec 2019 04:37:25 +0000</pubDate>
      <link>https://forem.com/arashout/wrapper-functions-for-dangerous-commands-hd6</link>
      <guid>https://forem.com/arashout/wrapper-functions-for-dangerous-commands-hd6</guid>
      <description>&lt;p&gt;Have you ever had a brain fart at work and accidentally deleted the PRODUCTION database because you thought you were in the development environment? Yeah, me too...&lt;/p&gt;

&lt;p&gt;Here's a simple bash script that might save your life (multiple times).&lt;/p&gt;

&lt;p&gt;Let me draw the scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your company has different environments (prod, dev, etc...)&lt;/li&gt;
&lt;li&gt;It's possible to accidentally run a bash command meant for development environment in a production environment, which will have fatal consequences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is a fictitious wrapper function for a &lt;code&gt;dangerous_cmd&lt;/code&gt; only meant to be used in a development environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;dangerous_cmd&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running dangerous_cmd wrapper"&lt;/span&gt;
    &lt;span class="c"&gt;# Assume that 'dangerous_cmd environment' returns the environment you are currently in&lt;/span&gt;
    &lt;span class="nb"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;dangerous_cmd environment&lt;span class="si"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$env&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"development"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# 'command' is a bash built-in that avoids shell function lookup&lt;/span&gt;
        &lt;span class="c"&gt;# We need this because otherwise we would be stuck in a infinite loop,&lt;/span&gt;
        &lt;span class="c"&gt;# calling 'dangeroud_cmd` over and over again&lt;/span&gt;
        &lt;span class="c"&gt;# '$@' passes all the arguments passed to the function to this call&lt;/span&gt;
        &lt;span class="nb"&gt;command &lt;/span&gt;dangerous_cmd &lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;return
    fi
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Not in development environment! Not running dangerous_cmd"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The main workhorse of of this function is the bash built-ins &lt;code&gt;command&lt;/code&gt; and &lt;code&gt;$@&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;command&lt;/code&gt;(&lt;a href="https://askubuntu.com/questions/512770/what-is-use-of-command-command"&gt;StackOverflow Description&lt;/a&gt;) runs our command without doing a shell function look-up, which we need to avoid infinitely calling &lt;code&gt;dangerous_cmd&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$@&lt;/code&gt; passes all the parameters to this point. &lt;a href="https://coderwall.com/p/85jnpq/bash-built-in-variables"&gt;Useful illustration&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The good thing about using a bash function wrapper with the same name is that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Autocomplete still works as usual&lt;/li&gt;
&lt;li&gt;You can add more complex checking logic as you see fit&lt;/li&gt;
&lt;li&gt;You don't have to remember any obscure commands&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I put bash functions like these in my &lt;code&gt;.bashrc&lt;/code&gt; or &lt;code&gt;bash_profile&lt;/code&gt; (Mac)&lt;/p&gt;

&lt;p&gt;Here is an example of a wrapper function that only allows running something like &lt;code&gt;skaffold delete&lt;/code&gt; (A command that cleans up your development environment by deleting all pods and services related to your application) in a &lt;code&gt;minikube&lt;/code&gt; (Basically development) Kubernetes environment. &lt;br&gt;
Trust me you don't want to run &lt;code&gt;skaffold delete&lt;/code&gt; in production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;function &lt;/span&gt;skaffold&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running skaffold wrapper"&lt;/span&gt;
    &lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl config current-context&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nv"&gt;$context&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"minikube"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;command &lt;/span&gt;skaffold &lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return
    fi
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Not in minikube context! Not running skaffold command"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>bash</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
