Golang UK Conference 2017 | Mark Ryan - Command Line Scripting with Templates

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
good morning everybody my name is Mark Ryan I work for Intel's open-source Technology Center here in London my talk is about command-line scripting with templates and while I talk about templates what I'm talking about is little scripts that you can write using the templating engine that is supplied with go standard library so I don't know if you guys know this or not but there is actually a programming language built into the standard library and it's a template based programming language and it is usually used to create documents so what you can do is you can take a document that's annotated with some template directives and you can combine this document with a go variable to produce a new document now this is typically used to create HTML documents text documents and sometimes even code the slide you're looking at right now was created from a template by the co-present tool so you can see the useful applications of these templates you're probably wondering what this has to do with the command line and with command line tools well it turns out that some applications some notable applications like docker cube CTL and go list allow the user to supply a template on the command line arguments now you're probably wondering why they do this well to understand the motivation for this consider that you might have to write a program yourself a command line tool and this command line tool is going to provide access to some sort of data now this data could come from anywhere it could come from your local hard drive it could come from the result of a REST API query it could come from a hive mind it doesn't really matter what's important is that you have to come up with a user interface for your application to allow the users to get at the data so you'll probably think you might do this by adding a whole pile of commands and options these commands that let the users issue their queries and format their data in all kinds of different ways but the problem is that if if your data source is non-trivial and your data source probably isn't on trivial if you're writing a tool to provide access to it you're not going to be able to anticipate all of the needs that your users are going to have you might try buying a whole pile of options but eventually you'll have a really cluttered command-line interface and there will still be some people who are unhappy with and they will not star your project so there are there is another way and this is used by some really kind of high-profile Co utilities and what these utilities do is rather than provide a whole plethora of options they provide one option it's called - eff and - this - eff you can pass a script and to this script these tools pass a go variable and you can then write a little scripts that can analyze this go variable to produce various outputs and this go variable I should have mentioned this this go variable represents some view of the data model that is exposed by the application so this is a really powerful way for tool writers to expose their data models to end-users and this is quite important because sometimes you know if you're writing a command-line tool this tool is going to output some information to the screen and in a pretty way that users can consume but also the tool could be used by another tool and so when this is the case you really do want to have tight control over the output so it can be easily progressed processed programmatically so this is already fantastic at least I thought it was fantastic because about nine months ago I started modifying some of our go tools in Intel to accept command-line templates and I was delighted myself I called all my team members together it gave a presentation on the topic I was expected to be promoted given the CTO job but that this didn't happen and the reason it didn't happen was because my team members were bewildered and the reason they were bewildered was that it turned out to be really difficult to ride go templates to extract the sort of data we needed from our data model so I went back to the drawing board but I was not defeated and the reason I wasn't defeated is that Disko template language is extensible and by extensible I mean you can add new keywords so I said about adding a whole pile of new keywords to implement the various use cases we had for our tool and when I finished I realized that all of these keywords I had added were totally generic and so I did what any self-respecting go programmer would do i bundled them up into a package and i shoved it on github and this package is called template for tools affectionately known as t4 tools by me because I'm the only user right now but yeah that's the package name as well yeah so this is basically what I'm going to be talking about today I'm going to be talking about this package t4 tools and how you use it in your command-line tools but before I dive into t4 tools I am gonna do an overview of gos scripting language because I'm a little concerned if I start talking about t4 tools directly and present you with lots of examples if you've never seen this language before you will be totally bewildered and I don't want to lose half of the audience so soon into the talk so we're going to start off with a simple example I have some go code up here you can see that I have two types of person struct which has some fields in it like a family name and two phone numbers and it has an address which is itself a structure and then I have a variable called DB which is just a slice of these persons and I have a job to do I need to convert this in memory in memory database to a HTML table and so I have a little function here it's called F print table and it's gonna do the job for me so if I run this we should see I've got a nicely formatted HTML document which is fantastic what is not fantastic is the code that generated it it's pretty hideous as you can see it's quite big it's difficult to tell what function is doing just by looking at it there is loads it's quite complicated there's loads of if statements and for statements and there is a more pernicious problem which I shall demonstrate by running the program live now I hope this works yes okay so I have the program here I am gonna run it it's called table func go and if I run it you see the output and what I'm gonna do now is just redirect this output to a file I'm gonna open that file in my browser and you see and you see the table which isn't very good and you also see what is even worse a message which says I'm being hacked and the now being hacked is in my in-memory model I heard there was an HTML injection attack which you can sort of see here and our F pin table function has just copied that injection attack directly into the resulting HTML which is pretty bad so you're probably thinking there must be a better way to do this and there is a better way to do this and go you can do this using the template language so here is another example of producing a similar HTML document but this time I'm using the template language and so this I hope you can see is a lot simpler there's a lot less code it's kind of obvious what this function does it's going to produce a document of some kind you can also even determine the structure of the document just by looking at this which is quite nice and you can see in bold this hasn't come out very well but this bit here is in bold and you can see part of this document has some funny directives in it and these directives are delineated by the opening and closing double curly braces and these are the template directives that I mentioned before and we'll talk about what all these mean in a minute but basically what this is doing is it's just a sort of a simple loop that is creating a new HTML table row on each iteration now down at the bottom of the function this is quite interesting we have two commands the first command creates a new template object and it does this by parsing this document okay so that's template parse and then once we've created the template document we can template object we can execute it and when we execute it we give it two pieces of information we give it a writer which is where the output is going to go and we give it a go variable and DB if you remember from the first slide is a slice of Persons so if I run this now you see that I get a similar document which is good with less code and if I actually run the program excuse me and I opened that you see that rather than having a nasty you've been hacked dialog popped up the nasty attack has been escaped and so this is much more secure okay so let's take a little look at some of the directives in the templating language the first thing you need to understand about the templating language is this concept of a pipeline and that is illustrated in this first example here so a pipeline is just a template expression in surrounded by curly braces and what it does is it valuates the expression and it outputs to the writer associated with the template object now in this case the expression is a string and it evaluates to itself and so that is what is output to the writer if you look at the bottom here I have declared a new variable P which is a type of person again and I'm gonna pass this to the template script via the execute command once I've done that I can access the elements of this go variable using the dot symbol so the dot symbol represents something called a context a context always refers to a go variable and when you first start executing your template the contexts always reverse the variable you've passed into template execute so in this case it's P so P a sorry so dot first name here this actually evaluates to P dot first name which is Marcus and you can change the meaning of the context with various direct directives one example of this is with so with changes the meaning of the current context to its argument so within this with block the meaning of the dot is actually P dot address so dot country here actually evaluates to P dot address dot country which evaluates to UK finally one other thing you can do is sometimes you need to actually access the top-level context object from inside a wiff block and you can do that using dollar dot so dollar dot evaluates to P dot first name even though I'm in a whisper okay and hence it evaluates to Marcos so if I run this you should see what we expect who is this guy and where do you live Marcos Marcos lives in the UK all right another directive that affects the context is the range directive so range can be used to iterate through a collection so slice a map or an array and I have a little E and actually on each iteration of the of the range loop the dot operator is set to the current element in the collection so if I run this I just should see the phone numbers today's to the screen I thought I would try and liven things up a bit at this stage by presenting you with some fun facts about templates there are only two fun facts about templates to my certain knowledge the first one is that there are actually two template packages this text template and HTML text HTML template text template is for generating HTML documents and text template and a text template is used for generating text documents the HTML template package generates HTML documents which are safe from HTML injection attacks as we have seen there are two packages have identical api's and so you need to be a little bit careful when you're using them particularly if you use something like going ports because when you start typing the code template parse it will automatically stick an import in for you and the import it sticks in is HTML template at least that's what it does for me so that may not be what you want so you need to be a little bit careful about that fun fact number two you can access structure fields from inside a template as we have seen but you can only do so if those fields are exported so here you see a little example we have a variable called test which is an instance of a structure with one a unexploited field call name and I have a little template here it's going to try and access this field but if I run it you will see nothing is output because we cannot access the field because it is not exported so if I export it quickly we should see some goodness and we do ok a little bit more about template directives there is an if statement which allows you to conditionally output data to your documents I have a very simple example but it's not actually a very simple example I have an example here which converts a slice of phone numbers to Jason and the if statement here is used to avoid outputting a leading comma in front of the first phone number to ensure my JSON is valid so if I run that you see I get my slice the phone numbers will return to this example a little bit later on you can access the individual members of a collection using the index method so if I'm accessing the members of an array or slice I'm going to provide the array or slice and then I'm going to provide a number so in this case this example what it's going to do is it's just going to print out the elements of this slice in reverse order and finally we're going to talk a little bit about functions so you can invoke functions inside the templating language and not only can you invoke functions you can actually define new functions which you can define your own functions and add them to the template language and then your scripts can call them and this is kind of a fundamental facility and the T for tools package is built almost entirely on this on this capability so let's have a look here we have we're gonna add some new functions to the go templating language and we do it by calling the funks method on the template object now the funks method takes a map as a parameter and the map is going to take two pieces of information it is going to map textual names to go functions and then these go functions become available via these textual names inside your script so if we have a little look at this example we have a script here and we are passing it the variable P and P just has one field to find first-name which has a word with white space on both sides so first name when I execute this pipeline I'm just going to get shamrock printed with the white space trim which is taken from the standard library is going to trim the white space on both sides and print out shamrock without any one space and in the third example trim is going to trim the white space and then it's going to pass a result of trimming the white space to the title function which is going to put it in title case so if I run this you should see we've got white space we've got no white space we've got no white space and title case there is other ways you can chain functions together and this is the notation I typically use actually you can use round brackets like this I want to show you this because all my examples that are on use this notation so you get the same result fantastic okay that's the overview of templates if you've already know about templates you're probably incredibly bored you may well be asleep now it's a time to wake up because we're going to talk about how we use these in command-line tools if you've never come across templates before you probably a little bit wildered but it doesn't really matter too much you just need to accept that this templating language exists and it has support for some common programming language constructs like if and so forth and you can use it to access and process go variables okay go list so the first command-line tool that I know of that started using templates allowing users to pass templates is go lists go list is a tool in the go tool chain and it allows you to find information out about the go packages that are installed on your system so let's have a look at how this works you run go list and you pass it you give it a package specification so I'm gonna give it their t for a tool specification and what it does is it outputs all of the packages that match the T for tool specification is this big enough actually can people see this of the bike should I make this a bit bigger okay I hope that's good okay so it just told us the package names that match the specification which isn't very interesting but if you provide a template script to go list you can extract all kinds of information about your packages now to be able to write this template script you need to know what the type of the variable go list is going to pass to your script and you can find this information out by looking at the help so if I do go lists help I see a whole pile of information and right up at the top I have a nice description of a structure called package and here you have lots of lovely information you can find out for example where your where the package is actually stored on the disk you can find out what go files constitute the package you can even find out and this is really really interesting all of the other packages that your package imports and you can also get a recursive list of all the dependencies which is pretty useful so let's take a look at how we extract some of this information we've got a provider scripts first of all let's have a look at all the go files in my package so I'm gonna use range to print them out is that right it is so there you are so I can get a list of all of the go packages in my Tifa tools package now let's do something different let's have a look at all of the other packages that t4 tools imports and there you are you get a list of all the packages at t4 tools imports the nice thing about this actually is you can see that it doesn't import anything that isn't outside that isn't in the standard library so t4 tools is nice and easy to vendor okay you can do other stuff like get a list of your recursive dependencies I think that's enough examples of go list but it gives you an idea there's a whole plethora of information stored in these packages and you can access these packages via go lists by providing a template script so this is all really good but as I mentioned there are quite a few problems with using the standard template language to enable command line scripting and the first problem is you have to document the types you're passing to your user scripts otherwise your users will be able to write those scripts and so how do you provide that documentation well go list does it by hard-coding the type information in a help string so you can see here this is a string and then we've got a whole pile of type information inside this help and this is problematic because it means that if you change the underlying type you have to remember to change the documentation and the compiler is not going to tell you that your documentation is out of date and this was particularly problematic for us because we didn't have just one data structure we had loads of different data structures for each of our different commands and so trying to keep all the help up-to-date was a bit of a nightmare and the other problem and actually this is really the same problem given multiple examples of the same problem but some it's just really really hard to write the scripts to extract the information you want I have an example here where we all I want to do is print out the first three dependencies for my package using go lists and you can see there's quite a bit of code here if you cast your mind back to the JSON example that was hideous I mean there was maybe a through nine lines of code it was quite confusing wasn't really obvious what it was doing convert and that was only converting one slice to Jason so that was pretty horrible there's some basic things that you can't actually do at least I couldn't work out how to do how do I kind of perform a query so how do I do asko list how many files in my package have the word debug in their name and then count those a count can't be a number of elements that match that query inside the template function I couldn't work out how to do it I couldn't work out how to access the last element of a generic collection with a template and there's basic things you can't do as well you could there's no sorting in the language and it's difficult to output the information the way you want it for example if you want to output to a table there's no easy way to do that so this is where a template for tools comes in so template for tools was conceived to solve all of these problems it is open source it is on github under Intel t4 tools and it provides as you might imagine solutions to all of the problems we have just discussed so I'm not going to go through all these but we've already talked about it well actually I am going to go through all of these I'm going to go through all of these in great detail but just not on this slide so let's start okay the first thing it helps with is generating help messages and so this facility is designed to make lives easier for the people who are writing the tools themselves so as we've seen you need to tell your user what your type looks like and if you don't want to automatically if you don't want to include all of that information your help documentation you can use this function called generate usage and decorate it so if you look at this example here I've got a new type it's a stock I've got a bunch of fields and then I have a slice of these things called fictional stocks remember fictional stocks because we're going to see that in a lot of the examples if I pass this variable to generate usage undecorated I am going to get a nice formatted type description so there's no longer any need to embed this information directly in your help strings you can just call this function and it will generate a string for you which you can output to the user the nice thing about generate usage undecorated is it won't add information about fields that are not exported and it doesn't do that because the user can't access them from inside the template script it will however output information about any exported methods that are defined on your types because these interest me enough are executable from inside a template script as we shall see a little bit later on there is the second version of this function called generated usage decorated and this prints out the type information as a variable you pass to it and it also prints out information about all the new keywords that we've added to the template library so up the top you can see the type definition and then if I scroll down you see information about all these new functions such as filter filter contains and so forth we'll have a look at some of these in a minute this function needs a bit of work when I first wrote it I didn't have very many functions but now I have quite a few functions it generates far too much output so I need to find a way to generate a more succinct description of the functions that are available ok so the next facility that it provides is also a helper function for tool writers it's called output to template and what this does is given a script and a writer and a go variable it's going to create a new template object for you it's gonna parse that script it is gonna add all of the new functions that template for tool supports to this template object and then it's going to execute the script and send the output to the writer so it just saves you writing maybe I don't know six or seven lines of code ok so that's all the help that we provide to tool authors the rest of the talk is about the help we provide to people who are actually writing the scripts the end user and the first example and this is my favorite function it's called table table operates on a slice of structures or an array of structures and it just pretty prints but a slice so if I run it you see a nice printed slice of structures and it also automatically determines the column heading from the field name so these things like ticker name last trade these all come from the field names of the type we have another formatting function called select and select also works on slices of structures and it views that slice of structures as the table and it allows you to extract one column from that slice of structure so if I run this you see I select it selected all of the elements from the ticker column there is a sort method which is really nice so sort operates on a slice or array of structures and it allows you to sort that slicer array by a given field and actually what it does is it will create a new slice for you containing all the elements but in the right order and because it's returning you a new slice of structures you can then pass it directly to table which is quite cool so most of the functions I'm going to talk about here that we've added are composable so you can chain them all together Wow I am running slow so as you can see everything is sorted let me try and sort by descending order you can do that and you can also sort by different types so there I was sorting by strings if I sort by volume that's an int you can see that you can also sort by volumes right let's take a look at extracting data so the whole pile of functions that allow you to extract data and what these functions do is that given a slice of structures they perform a filter on a given feel about slice of structures and return you a new array or a slice with the elements that match the search criteria so in this case here I'm just going to filter on the company on the name field and I'm going to filter for any companies that have the name company or the word company in their names so as you can see we're able to filter the whole pile of these functions you can filter on that suffix or prefix on a regular expression or you can do a case insensitive comparison there are two functions called head and tail which allow you to extract the first and last elements of a slice or an array as you might imagine so if I run this you see I'm getting the first elements you can do tail as well these functions actually return the slice and the reason they return a slice is that you can also specify give me the last three elements for example so I do that and I get my last three elements there are two more extraction functions rose and calls Rose operates on a slice of functions and allows you base a slice of any slice actually it works on and it just allows you to request the particular rose that you're interested in so in this example here I'm gonna print out a table with the second fourth and sixth rows and calls is similar in some ways but it's also different in that it only works on a slice or tape array of structures and you have to specify the column names that you're interested in so I can there we go okay let's get to the last few functions these are related to formatting there is a method called to jason which allows you to convert your variable to jason so if i run that it prints everything out nicely to the screen but you don't have to print out the entire variable you can select the part of the variable you actually want so if I just wanted to print out the first element I would do something like this and you just get the first element in jason if i just was interested in the name i could do this so you can you know star select exactly the part of the data structure input interested in and output that to jason described I'll skip describe I'll talk about that a little bit in a minute promote is a function that allows you to take a structure field which is embedded in the forest of data structures and promote that to a top level slice and this is kind of interesting if you need to extract information out of that's deeply embedded in data structures to to visualize so in this example here I'm promoting the name field from the fictional DB database fictional stocks database and what is going to do is it's going to return me a slice of strings containing all name's okay right so that was probably all a little bit abstract and contrived but the good news is I have a non contrived example and this is a piece of code that was written by one of my colleagues Manohar Castle Eno and he sent me an email a couple of weeks ago and said hey I found this use for your tool for your package and I took a look at it and then I marveled at its beauty for twenty minutes and then I shoved it in directly to slide 16 because he was so beautiful I wanted to share it with you and the reason is beautiful is because it illustrates just how powerful these templates and this t4 tools packages so this is the code in its entirety it is an elf dump tool so elf is the binary format we use on Linux for executables and libraries and object files and what this tool allows you to do is it allows you to explore the metadata that is included in these in these executable files and it does it in about 15 lines of code so it opens a file it takes that file and it passes it to a package in the go standard library called elf and elf parses this file and then it returns me a go variable and now I've got to go variable I can pass it directly to template for tools and we can invent we can explore the elf headers so actually on Mac OS obviously you've got macho not else so I've downloaded a Linux binary here the binary I'm going to be showing you is curl I hope okay so what you've got to do is you've got to give this two parameters the first is a script and the second is a file name so if I run this I've used the describe command and describe is like generate usage undecorated but you can actually run it from inside the template so what describe does is it's telling me all the information about the variable that has been passed to my script and you can see here we've got a whole pile of information about the elf file itself and you've also got a whole pile of methods that provide information or we can go ahead and call some of those methods now so let me let's have a look at all of the imported libraries of I spelt like correctly it's not right no I have not spelt it correctly okay so you can see that my curl binary is importing four different libraries now let's have a look at the symbols and the symbols are kind of cool because if you look at the imported symbols method which I shall show you is if that one you see that it returns a slice of structures and because it returns a slice of structures we can pass it directly to table and we will get out a nice table see yeah pretty cool but we can do better than that we can actually filter the table for the information that we're interested in now I'm only interested in seeing the symbols that come that are imported from the standard library so if I specifies a library field and then what does it Lib don't see no Oh live coding and file thank you thank you and it's still not working that filer Oh aha okay fantastic it worked so there you go yes so you can also take a look at some of the if I go back to describe we can take a look at some of the information in the header so for example there's a program header here which contains some interesting information so let's just get at that and I'm gonna do table frogs and because the information I actually want is embedded within a structure I'm gonna use promotes frog right and you can see a list of all the program headers if I hadn't used promote what would have happened is that I would have been given a table which contains a structure and a reader which isn't very interesting and so what promote does it allows me to focus in on the information I want and then promote that up so that is elf dump there's also a version which I don't think I have time to show you called macho dump which is pretty much the same only it works on OSX and it works just by changing two lines of code okay just I think I need to finish up do I have time to go through the slide I've got time yeah oh right that's okay so I'll slow down a bit catch my breath yeah I got okay okay okay that's perfect that's perfect so let's slow down and consider the last slide actually would a be like to see macho dump before I should we do much a dump okay so what I'm gonna add some more live coding I'm gonna change this to macho dump so I'm just gonna change to little piece of the code I hope this is gonna work so if I run this now if I run it you should probably give me an error and it does because it says invalid magic number because I'm running it on the Linux binary but if I run it on the Mac OS version of curl it oh that's because that field probably doesn't exist let me do is right okay and here we are so now we've just made a small modification to our program and now we have um not show a dumb program where we can explore information about matcher files and as you can see here you have a slightly different data structure right but you have lots of similar information such as imported symbols so why not let's have a look at it I'm not gonna print it out in a loop but if I just print it out like that you get all of the important symbols so I hope this kind of illustrates how useful this can be with just a few lines of code you can take a go variable and you can explore the data structure programmatically from without modifying any of the original code okay elf number and latinum so I'm going to finish up with some guidelines and these are guidelines for people writing command-line tools guideline number one is you should allow users to tailor the output of your tools I mentioned this on the first slide and the point was that you know you can't possibly anticipate all the different things users going to want to do with your tools all different ways they're going to want to query your data all the different ways you're they're going to want to format it and so because of this you should allow them some flexibility with how they consume your data and my recommendation of course is to do this using a template provide a minus F option if you do this you must make sure that you document the types that you're going to pass to go program some tools allow you to pass a template but don't actually tell you much about the types they're going to pass your scripts and so it makes you it makes it really difficult for you to write the scripts because you don't know the structure of the data so always document the types pass your template scripts as we have seen with go list you need to consider that once you start passing go types and go variables to template scripts these template scripts are now part of a public API because people are going to be coding against them so you need to be very careful to make sure you do not break backward compatibility when you introduce changes to these structures otherwise you're going to break a lot of users scripts which won't be very good another issue to consider is something that go list does that I don't really like very much when you execute go list and you can actually specify a wild card and that wild card can match multiple packages right and we already saw that we saw a multiple package is being printed to the screen but if you specify a template and your wildcard matches multiple packages your template is invoked once for each of those packages and that makes it hard to perform a computation across the entire set of packages so for example if you wanted to find out get right one template scripts that computed and sorted the list of all dependencies of group of packages you couldn't really do that with go list so my advice would be only execute the template script once and if you've got a collection of items you want to pass to that template script pass the collection as a slice rather than invoking the script multiple times on each element of that collection and finally yeah don't use interface in your public types because it also makes it really difficult for users to use those kind of variables and when I say avoid interface new public types avoid interface empty interface in the variables that you're passing to your go scripts I just have a little example here I have a slice of fictional stalks but rather than using the stock type here it's I use the empty interface type here so I'm losing type information so when I run this you can see I don't get any useful type information but if this is stock I do get useful type information now even though we're passing the template and interface object the template if it knows what that type is you can still access it so I can still do index 0 I think I can try that and that will that will work right but I you know I had to know this I can't easily get this information and there's no guarantee if I treated this as a stock there's no guarantee that each element of that collection would be a stock and so this code might work for element one but it might not work for element 2 so don't do that either yeah so that's it go ahead and use templates in your tools yeah so we have time for questions if that's okay no problems so I was good the the very first one he showed that listed all of the types that had where they had the hard-coded string where they'd put comments in yeah can you do something summer the very first so you said in their goal if do you meet there so they have that literal that says this is the structure and you fix that through your described method but it also listed here's the thing name whatever and it has some comment about the comments yeah yes no that does not work and that's an excellent question it is possible if the go source is present on the system then I think with the comments I think that you could do it but if you had just a if you just had the binary file I'm not sure you could do it I was thinking of maybe coming up with some sort of system based on tags to allow you to provide this information but that is definitely a shortcoming and it is not addressed yet but I think there will be a workaround and like you say will use tags yeah I should enter an issue thank you so some command-line tools let you output I guess the the response in say Jason or yeah more format right and with Jason you can use like the JQ tool to type the data into that and then do your filtering separately what do you think of some of the advantages of doing it in the command line tool itself versus leaving it to an external tool to do the filtering it looked like some of the interesting ones there well like you can use methods in go templating arise with like Jason you just have the raw data but I wonder if you had any thoughts on that not not particularly I suppose the thing I like about doing everything in the template is that it reduces the number of tools you need and so everything is fairly self-contained reduces your dependencies but yeah you could use it an external processing tool I wonder if you looked at other tools that make extensive use of templates up you go comes to mind is having a very rich set of functions that they inject some of which are very similar to yours and I wonder whether you did any sort of research to sort of look for common patterns that could be pulled out yeah I do take a little look at Hugo and it does essentially do the same sort of thing of course it has a different purpose it's to generate HTML pages but yeah I guess I need to take a closer look and see if there are any sort of synergies between the two and see if there's any functions that we can exchange but you know when I looked at this I sort of felt that this this package was viable because it had a sort of a different a different purpose in mind it is specifically for enabling templates in command-line tools and so I felt that the purpose was you know sufficiently distinct from you go to make it viable and useful right any more questions okay well thank you very much [Applause]
Info
Channel: GopherCon UK
Views: 3,399
Rating: 4.8297873 out of 5
Keywords: golang, uk, london, computer science, google
Id: UMbicEbSIjc
Channel Id: undefined
Length: 43min 53sec (2633 seconds)
Published: Mon Sep 18 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.