generated from cotes2020/chirpy-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
115 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
--- | ||
title: wc in Golang | ||
date: 2024-03-25 11:05:00 +0530 | ||
categories: [Golang] | ||
tags: [golang, linux, codingchallenges] | ||
--- | ||
|
||
So I recently came across [codingchallenges.fyi](https://codingchallenges.fyi) through some Reddit post - if memory serves me right. As someone with the attention span of a skibidi-toilet kid, I found it to be perfect for me. Rather than being a full walkthrough about how to build something, the author merely provides a little overview, and the increments in which you should develop the project. The minimal handholding leaves it open for you to research on your own and approach the project as you wish without having to follow the author's design. So I decided to dabble into it today, and completed the first project - the `wc` unix command. If you have ever messed around with Linux you'll probably recognize it as one of the coreutils. Enough yapping done I guess, let's move on to the implementation. | ||
|
||
> In case you just want the code, it's available [here](https://github.com/aadi-1024/gowc) on my github. | ||
{: .prompt-info} | ||
|
||
## Step 0 | ||
### Setting up the environment | ||
|
||
I'm going to be using Golang for this project(duh), and also for all my future projects unless I can come over the Rust skill issue or sell my soul to Python. I'm using Go 1.22 (haha arch btw) but any version not built by Jesus himself would work. If you still want a newer version, you can use nix or brew(if you're on mac), or maybe Docker. Or maybe just get the latest version from the website, gah. Also if you're on Windows and not using wsl, just use wsl. | ||
|
||
So, creating the project directory and initializing the go module. | ||
|
||
```sh | ||
~ ❭❭❭ cd Projects/ | ||
Projects ❭❭❭ mkdir gowc && cd gowc | ||
gowc ❭❭❭ go mod init github.com/USERNAME/gowc | ||
``` | ||
|
||
I use Goland but you may as well use VSCode, vim, helix or whatever fits you. | ||
|
||
Create a `.gitignore`. I usually add .idea/ or .vscode/ to it. Download the [sample text](https://www.dropbox.com/scl/fi/d4zs6aoq6hr3oew2b6a9v/test.txt?rlkey=20c9d257pxd5emjjzd1gcbn03&dl=0) provided and place it in the root of your project. Add it to .gitignore if you wish. | ||
|
||
## Step 1 | ||
### Outputting the number of bytes | ||
|
||
So in the first iteration, all our tool needs to do is accept a flag (`-c` just like original wc) and output the number of bytes - easy right! | ||
|
||
Here let's just get this running so you can get a hang of how things work, we'll refactor everything later. | ||
|
||
First thing we need to do is, check the flags and only proceed if -c is provided. | ||
|
||
### Flags - to framework or not? | ||
|
||
Here you have the option to either use something like `cobra` or `ufave/cli` in order to handle the cli flags, or just use `flag` from the stdlib. | ||
|
||
Although the framework approach might be suitable for larger tool, I'd suggest just using the stdlib for our dead simple tool. | ||
|
||
So let's populate the `main.go` file. I usually place it in a directory named `cmd`. You do as you please, you can always reference the repo later on! | ||
|
||
So starting off | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
const ( | ||
SUCCESS = 0 | ||
FAILURE = 1 | ||
) | ||
|
||
func main() { | ||
//filepath check | ||
filePath := os.Args[len(os.Args)-1] | ||
fd, err := os.Open(filePath) | ||
if err != nil { | ||
fmt.Println("Invalid filePath") | ||
os.Exit(FAILURE) | ||
} | ||
|
||
//byte count | ||
c := flag.Bool("c", false, "gowc -c filename") | ||
|
||
flag.Parse() | ||
var bytes int64 | ||
|
||
if *c { | ||
fileinfo, err := fd.Stat() | ||
if err != nil { | ||
fmt.Println(err) | ||
os.Exit(FAILURE) | ||
} | ||
bytes = fileinfo.Size() | ||
} | ||
fmt.Printf("%v %v\n", bytes, filepath.Base(filePath)) | ||
os.Exit(SUCCESS) | ||
} | ||
|
||
``` | ||
{: file="cmd/main.go"} | ||
|
||
That sure's a lot of code! Breaking it down. | ||
|
||
After importing our packages, we declare the exit codes. In the main function: | ||
- First we need to check whether the file provided exists or not. If it doesn't, `os.Open` returns an error and we quit nice and simple. | ||
- `c := flag.Bool("c", false, "gowc -c filename")` here I used the Bool function of the flag package. What does it do? Any half decent text editor with the appropriate plugins should show it nice and clear, but in case yours doesn't, you can always use [the docs](https://pkg.go.dev/flag). But anyways, as the docs describe, the Bool function takes 3 arguments and returns a pointer to a bool. The first argument is the flag, c in our case. The second is the default value, and third is the help message for the flag. The bool returned would be true if the user uses the flag, false otherwise. | ||
> In case you are not comfortable reading documentation, spend some time and make sure you are. It's probably the best decision you'll make! | ||
{: .prompt-tip} | ||
- `flag.Parse()` parses the flags from os.Args. Color me surprised! | ||
- *c dereferences the pointer and returns its value. Using the `fd` we got from `os.Open`, we get the file metadata using `fd.Stat`, check for errors and then get the file content size(in bytes), print it and exit nice and sweet. Easy! | ||
|
||
And that is it! Our app is complete(not really!!)! | ||
|
||
Now to test it | ||
```sh | ||
gowc ❭❭❭ go run cmd/*.go -c test.txt | ||
342190 test.txt | ||
``` | ||
It Works!! | ||
|
||
## Step 2 | ||
##### coming soon! |