Shipping a Brew CLI in one week17 Mar 2024
TLDR:
User enters typo command -> User says fuckoff -> command from terminal history goes boom!
# Installation via brew
brew tap Imgkl/fuckoff && brew install fuckoff
# Available Commands
fuckoff # deletes the last command.
fuckoff -a # deletes all history
fuckoff -i # interactive deletion mode
Have time to read? let's go.
The most annoying thing in terminal is, getting a typo in the command. The issue is now the typo command is stored in .zsh_history
or .bash_history
. Terminal autocompletion will suggest the typo command. I wanted to fix this.
There's a CLI called The Fuck, which you can enter to get proper suggestions on the previously entered typo command. but the problem is the typo command is still in history.
I want to write a CLI which can either clear the entire history or clear a specific command, including the CLI invoked command, becasue why not?
Introducing Fuckoff.
Day 1: Requirement Design
Click to view image in full screen
Day 2: Scripting
Looks like the easy way to get a CLI is through python scripting.
import argparse
def parse_args():
parser = argparse.ArgumentParser(description="Manage your terminal history")
group = parser.add_mutually_exclusive_group()
group.add_argument("-a", "--all", action="store_true", help="Delete all history")
group.add_argument("-i", "--interactive", action="store_true", help="Selectively delete history items")
return parser.parse_args()
def main():
args = parse_args()
if args.all:
delete_all_history()
elif args.interactive:
interactive_delete()
else:
delete_last_command()
delete_all_history() - Get the .zsh_history file and remove all of it's contents in write mode.
interactive_delete() - Read all the entries from the .zsh_history and using some library give a interactive space so the user can select the entries to be deleted.
Looks like the delete_all_history() method looks easy to implement, so let's work on that.
def delete_all_history():
history_path = os.path.expanduser('~/.zsh_history')
confirm = input("Are you sure you want to delete all history? This action cannot be undone. (y/n): ")
if confirm.lower() != 'y':
print("Operation cancelled.")
return
if os.path.exists(history_path):
with open(history_path, 'w'):
pass
print("All history has been deleted.")
else:
print("History file not found.")
pass
Note that this only works for .zsh_history, I will have to add support for .bash_history as well in the future.
Day 3: Interactive Delete
I will be using the questionary
library to create an interactive CLI. The history entries will be read from the .zsh_history file and displayed as a checkbox list. The user can select the entries to be deleted and the selected entries will be removed from the history file.
def interactive_delete():
history_path = os.path.expanduser('~/.zsh_history')
if not os.path.exists(history_path):
print("History file not found.")
return
with open(history_path, 'r', encoding='utf-8') as file:
history_entries = [line.strip() for line in file.readlines()]
selected_entries = questionary.checkbox(
"Select history entries to delete:",
choices=[{"name": entry} for entry in history_entries]
).ask()
updated_history = [entry for entry in history_entries if entry not in selected_entries]
with open(history_path, 'w', encoding='utf-8') as file:
file.write("n".join(updated_history))
if selected_entries.__len__() == 0:
print("No entries selected.")
else:
print("Selected entries have been deleted.")
Now I have everything I need. Let's move to testing both methods.
Click to view image in full screen
Click to view image in full screen
Day 4: Pack it and ship it.
I will create a brew formula for the CLI and push it to a seperate GitHub repository. The formula will be added to the HomeBrew tap and the CLI can be installed using the brew install fuckoff
command.
So I had to create a new repo for formula with a ruby file pointing to my python script repo.
class Fuckoff < Formula
include Language::Python::Virtualenv
desc "CLI tool to manage and clear Zsh history"
homepage "https://github.com/Imgkl/fuckoff"
url "URL TO MY RELEASE"
sha256 "SHA256 of my release"
depends_on "python@3.9"
def install
virtualenv_install_with_resources
end
test do
system "#{bin}/fuckoff", "--version"
end
end
And we are done. The Fuckoff brew package is now available for the public to use.
Yay.🥂
< Back