Welcome to the third part of our File Organizer journey! So far, we’ve built a tool that organizes files into categories and made it flexible enough for users to modify those categories—without writing code! But what’s the fun in a tool that’s not interactive? Let’s take it up a notch by adding a command-line interface (CLI) so users can interact with it directly! 🎯
How do we do that? Enter Cobra—a powerful library used by tools like Docker and Kubernetes. If you’re ready to make your Go project interactive and shareable, buckle up! 🚀
Step 1: Installing Cobra
First, open your terminal and install Cobra with:
go get -u github.com/spf13/cobra@latest
With that, Cobra is locked and loaded! Now, let’s organize our project structure.
Step 2: Setting Up Project Structure
Create a folder named cmd
inside your project directory. This is where we’ll define commands and their handlers. Inside cmd
, create two files:
-
root.go
– Defines the CLI commands -
handlers.go
– Calls the right functions based on the commands
Step 3: Displaying Categories with handlers.go
In handlers.go
, our first mission is to display the saved categories beautifully using Go's built-in text/tabwriter
package. Think of it as adding that little touch of elegance to the terminal output. 💅
// handlers.go
package cmd
import (
"your-project-path/models"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"text/tabwriter"
)
var store = models.NewFileDataStore("")
// DisplayCategories lists all categories in a pretty format
func DisplayCategories(verbose bool) {
categories, err := store.GetCategories()
if err != nil {
fmt.Println(err)
}
const padding = 3
w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, ' ', tabwriter.Debug)
defer w.Flush()
if verbose {
_, _ = fmt.Fprintln(w, "Category\t Folder Name\t Extensions\t")
for _, category := range categories {
_, _ = fmt.Fprintln(
w,
fmt.Sprintf("%s\t %s\t %s\t",
category.FileType,
category.FolderName,
strings.Join(category.Extensions, ","),
),
)
}
} else {
_, _ = fmt.Fprintln(w, "Category\t Folder Name\t")
for _, category := range categories {
_, _ = fmt.Fprintln(w, fmt.Sprintf("%s\t %s\t", category.FileType, category.FolderName))
}
}
}
Next, we’ll add functions for adding and removing categories to keep things dynamic and easy to manage. 🛠️
func addCategory(fileType, folderName string, extensions []string) {
if fileType == "" {
fmt.Println(errors.New("category name not supplied"))
return
}
var extensionsToAdd []string
var extensionsToRemove []string
for _, extension := range extensions {
if strings.HasPrefix(extension, "-") {
rawExtension := strings.ReplaceAll(extension, "-", "")
if strings.HasPrefix(rawExtension, ".") {
extensionsToRemove = append(extensionsToRemove, rawExtension)
} else {
extensionsToRemove = append(extensionsToRemove, "."+extension)
}
} else {
if strings.HasPrefix(extension, ".") {
extensionsToAdd = append(extensionsToAdd, extension)
} else {
extensionsToAdd = append(extensionsToAdd, "."+extension)
}
}
}
err := store.AddCategory(fileType, folderName, extensionsToAdd)
if err != nil {
fmt.Println(err)
return
}
err = store.RemoveExtensionsFromCategory(fileType, extensionsToRemove)
if err != nil {
fmt.Println(err)
return
}
DisplayCategories(true)
}
func removeCategory(fileType string) {
err := store.RemoveCategory(fileType)
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully removed")
DisplayCategories(false)
}
func organizeFiles(dir string) {
files, err := os.ReadDir(dir)
if err != nil {
fmt.Println(err)
}
for _, file := range files {
if file.IsDir() {
continue
}
fileName := file.Name()
category, err := store.GetType(fileName)
if err != nil {
fmt.Println(err)
continue
}
err = category.MoveToFolder(filepath.Join(dir, fileName))
if err != nil {
fmt.Println(err)
continue
}
fmt.Printf("%s moved to %s\n", fileName, filepath.Join(dir, category.FolderName, fileName))
}
}
Step 4: Setting Up Commands with root.go
Now comes the fun part! Let’s define our interactive commands in root.go
. For example, here’s how you can set up the display command:
// root.go
package cmd
import (
"github.com/spf13/cobra"
)
// RootCmd is the base command
var rootCmd = &cobra.Command{
Use: "org",
Short: "Org is a file organizer",
Long: `Org is a file organizer that categorizes and moves files into folders based on their extensions.`,
Version: "0.1",
}
// Initialize the CLI commands
func init() {
categoryListCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Displays the extensions associated with each category")
rootCmd.AddCommand(categoryListCmd)
}
// Execute the CLI tool
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// categoryListCmd prints all categories
var categoryListCmd = &cobra.Command{
Use: "category",
Short: "Lists all file categories",
Long: "Displays a list of all categories used for organizing files, optionally with extensions.",
Example: `org category
org category --verbose`,
Run: func(cmd *cobra.Command, args []string) {
DisplayCategories(verbose)
},
}
Step 5: Bringing It All Together with main.go
Here’s how everything ties together in main.go
:
// main.go
package main
import (
"your-project-path/cmd"
)
func main() {
cmd.Execute()
}
Step 6: Running Your Tool and Testing Commands
Let’s give our tool a test drive! 🏎️ Open your terminal and run:
go run main.go display
If everything is set up correctly, you’ll see your categories displayed in a neat table. Now, you can easily add, remove, and display categories with just a few terminal commands. 🎉
Step 7: Building an Executable
Ready to share your creation with others? Let’s make it shareable by building an executable:
go build -o build/main
This command builds an executable that works on your device type. But what if you want your tool to run on multiple platforms? 🌐 Check out this DigitalOcean guide for instructions on cross-platform builds.
Bonus: Explore the Full Command Set
I’ve walked you through the first command, but there’s so much more you can do! 🧑💻 For the full set of commands, check out the GitHub repository here.
Conclusion
With Cobra powering our CLI, our File Organizer tool is now fully interactive and ready to take on the world! 🌍 Whether you’re organizing files for personal use or sharing the tool with friends, it’s now easier than ever to manage file categories.
So, what are you waiting for? Try it out, explore the commands, and build something awesome!
Let me know what you think in the comments or hit me up with feedback. Stay tuned for more cool projects with Golang! 🚀
Top comments (0)