 Hello, everyone. Hi. Hi. Okay, so we're going to talk about command line tools and closure, which is not the most usual way of using closure. But I was curious to see what we could do, like what was the state of the art for closure programs in the command line, if it was acceptable, if we could run something useful. So it's, okay, maybe a spoiler, but you won't be able to release the new, like, new grab or new curl that will replace the old tools, because it is like, you see, it's a bigger binary and it takes a bit longer to start up. But it could be very useful for your own workflow, like you could have your own command line tools to deploy your new version of your server and to stop, start, or to consume data from some remote system, right, remote service. Can you see there? Yeah. So nothing that I showed today is something that I invented or I created. It's just a survey of things that exist in the community. So the most obvious thing is that in the closure core, there is this dynamic variable that is the command line arcs. So when you run a program, this variable will be populated with a string of old parameters. So initially, I thought, okay, I can use that. I can parse. I can, like, split with spaces and parse. It shouldn't be too hard. But if you really want to do all the validation and all the possible cases to have alias for different commands, that's a lot of work. And also if you want to have a help command, like to show the usage. So I found this closure tools CLI, which is an official library to do this. It makes things much easier. So let's see here. So this is the command line arcs that I was talking about. Well, there is this closure tools CLI, right? So if you use that, you can just declare your program with gen class. So generate the Java thing. You declare the structure with the options. You can give it, like, a default value, the function that will be called. And then you just have your main function calling parse options and this structure. And it works fairly well. It creates automatically this summary with the options. So it can describe. You can have alias, like, it could be dash p or dash dash port. OK, so it works fairly well. I was happy with this. But I kept searching. There is this CLJ sub command, which is a bit better, I think. And, yeah, and it can basically do the same things. I think it's a bit better, but the other one has the advantage that it is official. But you see that it generates pretty much the same map. So I didn't see much difference. Now there is, like, the one that was most impressive is the CLIMATIC. It does much more. And it was much harder to find. I don't know why when I was searching for it, it took me much longer. I didn't know this project existed. So I was just searching for command line libraries in closure. And this project almost never showed up. I only found it in a link in a blog post. So they say it's built on top of the official one. But it's one higher level of abstraction. So it can consume other things, like it can consume JSON or YAML. You can pass, like, if the command is a location, like a URI, like a URL, or a file path or something, it automatically consumes the JSON file and parses and returns the data structure to your program. And it can slope files and can parse EDN. It has some type. So you can specify that a certain parameter is a number, like an integer, or a float. It validates. It shows error messages if the user uses the wrong way. So it's much more convenient. So this is the one I recommend. If I had to write it to create a command line program now, I would use this library. It can use a spec. It's a more modern thing. You can read about it. I won't show everything now. To parse the arguments, I would choose this last one. Now, something that will almost certainly be useful is that there is this name space, closure, Java shell, that pretty much only has this function, SH. It's basically the only thing there. And then you can use it to invoke external commands. So you want to do something that your program cannot do, or it's not implemented in Java, or you want to use some other command line tool that exists, or that is faster, or for whatever reason. You can just do this and do a focus of process. It will parse a shell, and parse the arguments, and returns. Pretty simple, but very useful. So once you have your program done and completed, how do you run it? How do you package? How do you do it? There is this line bin plus program here. Yeah, this is the SH command. Yeah, let's backtrack a bit. SH imparts the parameters here as many strings. So after this, we have this line bin plus. So it's just a line in plugin that you can specify the path of the binary, the name, the JVM options, and it will make it executable. So you run. There's no magic here. Nothing special, but it makes a tool for you. It's convenient. Another thing that sounds very promising, and that was the original thing that was the inspiration for this talk, is that I wanted to play with GrauVM. And one of the reasons that it is useful to make command line programs. So I don't know who has heard of GrauVM. Okay, good. So it is like a compiler and virtual machine to run many languages in the same machine. You can compile JavaScript or Java and Python and a bunch of languages in the same runtime. So there are some projects for interoff between Java and JavaScript using this. You can run two different languages in the same platform. It's pretty cool. And it can generate a binary for you. So that is the advantage for us here. There's also Joker, which is an implementation of Clojure written in Go. So it would be also better for command line programs, right? Because it loads faster. Another different approach is that you could use ClojureScript. So you could use Plank or Lumo or Shadow. All of these could work to create their own script. But again, it's not something that they would deploy probably because then the person must have a node. So we'll probably not release this, but it's just some tool that could improve your workflow. And you could have some other lists that are not Clojure. So I didn't go deep in these other ones, but they are related. Maybe some people here have more experience with them and are interested. In particular, Pixi is almost Clojure. It's created by a guy from the Clojure community and it's heavily inspired by Clojure. The only problem is that it is abandoned now, like the last commit was like two years ago. And yeah, there is this application. Let me show you. Okay, so you can see all of those. If you are interested in one of these, all the tabs open here, so if you want to see more details, I can show you. Hi. So this Clojure shell is one example of a command line application that looks super cool. So it's one example of something that you could create using these things. If you see the animated GIF here, it's basically a shell, but every time you have something with parenthesis, it will treat as a Clojure function call. So you can mix shell commands like a ls and pipe, a word count, but if you prefer to count the words using the count function in Clojure, you can just use parenthesis and it knows that it's supposed to be a Clojure call. So you can use reverse and group by, partition by, all the list processing functions. I have not used this yet, but I think it's super cool. It might be useful considering testing this. Okay, if you want to see some, not specifically related to Clojure, but if you want to see how to create a program, can you see or is it too small? Probably small. Yeah. What is the command? Anybody remember? I never do this. Yeah. Control plus. Yeah, not really working. Yeah, no, maybe. Yes, thanks. Okay, can you see? Yeah. Okay, so for LUMO, for example, you just created a CLJS file and you put this at the top so it will execute this command. With LUMO, passing your, in this case, I'm using tools CLI, so you just specify the path of the jar. And then you put your script here. There is no NS, like namespace clause in the beginning. You can just put everything through it here because it will evaluate this file anyway. And here you can do any Clojure script function, normal, you can define it, and any operation is valid. So in this case, we're parsing the arguments. Here, let's show you. Here, LUMO, I marked it as executable with CHmod. If I pass some arguments here, you see the command line, the library tools CLI in action. It parsed these arguments and it's showing this, the options. I didn't specify anything there in the code, so it's just telling me this. I think I can run with the help. Yeah, okay. Didn't show anything interesting, but... Help is true. Help is true. What is it? Help is true. Okay, okay. Sorry. Good. Yeah, help is true, right? So there is... Yeah, so it detected that you're using the help command, so if you declared another command here, you would get something in the map of the options that are set. You saw that it took a while to run, so it takes a couple of seconds on my machine. Yeah, I see 1.9 here. So for some applications, this might be too long, but if it's something that you just want to stop your remote server and start again in like two seconds, it should be totally fine. And same thing. Now this is the LUMU version. There is the one that is just closure and it's using the CLJ command line tool. And it's doing, in this case, it's doing the same thing. And the source code is the same pretty much. I only changed the top here, right? So instead of being SAH, it changes to being a closure and then you can just use it, but it's basically the same code tool work, as long as you use libraries that exist in closure and closure script. So there is nothing special. You don't have to set up a whole project. It's just one file. It's really a script. I think it's very lightweight and convenient to do this way for quick tasks. Now there is this one. This is an example for the binary that I generated here. Let me show you how it works. You can generate a native image here. You have to pass this flag so that it doesn't throw an exception when it's compiling. Because usually it doesn't allow dynamic loading of libraries, but closure is dynamically loaded into the JVM. So if you're doing anything with closure, you have to pass this flag and no server and JAR and then you create this JAR. It takes some time to run. And once it is generated, you can just run the command. In this case, like if you see the source code here, it's a toy calculator. So it can add numbers, subtract numbers. It's just normal functions here. In this case, it is calling two strings at parsing. But you see that it's very declarative. You can just put the map here with the options, the command, the types, like type is an integer. And if you try to run here, you can pass the first argument three, second is four, it returns seven. So it works like you have a command line application. You saw that it's still kind of slow. So it's still 1.6. So it takes much longer to run than basic commands. Like if you do time whatever, like this, time this, it's almost zero. 0.002. So it should be much faster than that. So again, it's only for certain cases that you can use closure for this. But if you see the official page here, actually not the official page, the closure example there used, they say here in the normal execution, it takes 1.5 seconds. And the compiled image, it takes almost nothing. And I don't know what I was doing wrong. When I ran, it was only the first case. I thought I was doing the same as the second one. Maybe I'm doing something wrong. I have to investigate. But they claim that it could run almost instantly. So there is hope. So if this is true, then you can use it for basically anything. The only downside compared to the common tools like LIS or Grab or something, is that those tools are super small. And this one, if you make a binary with the whole VM, it is many megabytes. Let's see. Here, they say it's like 25 megabytes, and you can zip to 7 megabytes. But still, you probably wouldn't distribute that. But again, if you're running on your machine, what is 25 megabytes? It shouldn't be a problem. And then I think that's it. Yeah, I could have more examples, but it would be more of the same. I could have an example with Shadow, CLJS or something. But it shouldn't be very different from what it saw here. So I think that's enough. Any questions? So I have a question about the code here. The Cascale code. The code or how to run the code here? So to look for why you need to pass, it is a tool string here. Why I have to code to string? Honestly... You want to change the way? Let's try. Let's try. Let's see what happens. I think this was in the example, so I didn't... Actually, I have to compile again. Yes, let's see what happens. It will be good to see all the things it does. Again, that it takes a while. Right, right. I forgot the other command. I think it will take forever to run. What was the other command? I mean, just line, overjar and compile. This should be enough. So obviously, you would not develop this like this way because the workflow would be super slow. So maybe you would just create a normal project and only compile when you're about to deploy. While we are waiting for this, let's see here. So I think that since it is compiling, it wants to print a string, so it doesn't like the fact that it cannot tell the type of this argument. Maybe that's it, but I haven't played much with that. That's my intuition. If you specify the conversion, it is easier to infer the type of the result. Yeah, there you go. How long did it take? One minute and a half. Okay, it worked as well. Yeah, honestly, no idea. This was from the example. I don't know why in the example they did this. Ah, I know actually. It's because you have a base, so it has to be more, to have one more feature. So in the calculator you can press a new parameter, next parameter with a base. That's the only reason. So it has nothing to do with the compilation or anything. Just that if you see the parameters here, there is one that is the base that has a default value of 10. Okay, makes sense. You see the closure in the sum command I have here. If I use closure in... For making sum command line application? I've never made any command line application in closure, no. Yeah, that's why I say that this is not something that I'm using or that I have created anything. I thought it could be interesting and I thought it would be good if I did this research and could expose so you don't have to do research by yourself. And let's see if there was something else. Yeah, that was it. Yeah, and now this is just a list of the references like every library, every tool that I have mentioned. I'll put the reference, the link if you want to read more about it. Okay, questions, comments? Okay, so that's it. Thanks.