Heim Backend-Entwicklung Golang Technischer Deep Dive: Wie wir die Pizza-CLI mit Go und Cobra erstellt haben

Technischer Deep Dive: Wie wir die Pizza-CLI mit Go und Cobra erstellt haben

Sep 24, 2024 am 06:18 AM

Technical Deep Dive: How We Built the Pizza CLI Using Go and Cobra

Letzte Woche veröffentlichte das OpenSauced-Engineering-Team die Pizza CLI, ein leistungsstarkes und zusammensetzbares Befehlszeilentool zum Generieren von CODEOWNER-Dateien und zur Integration in die OpenSauced-Plattform. Die Entwicklung robuster Befehlszeilentools mag einfach erscheinen, aber ohne sorgfältige Planung und durchdachte Paradigmen können CLIs schnell zu einem Code-Wirrwarr werden, der schwer zu warten und voller Fehler ist. In diesem Blog-Beitrag werden wir uns eingehend damit befassen, wie wir diese CLI mit Go erstellt haben, wie wir unsere Befehle mit Cobra organisieren und wie unser Lean-Engineering-Team schnell iteriert, um leistungsstarke Funktionen zu erstellen.

Mit Go und Cobra

Die Pizza CLI ist ein Go-Befehlszeilentool, das mehrere Standardbibliotheken nutzt. Die Einfachheit, Geschwindigkeit und der Fokus auf Systemprogrammierung machen Go zur idealen Wahl für die Erstellung von CLIs. Im Kern verwendet die Pizza-CLI spf13/cobra, eine CLI-Bootstrapping-Bibliothek in Go, um den gesamten Befehlsbaum zu organisieren und zu verwalten.

Sie können sich Cobra als das Gerüst vorstellen, das dafür sorgt, dass eine Befehlszeilenschnittstelle selbst funktioniert, die konsistente Funktion aller Flags ermöglicht und die Kommunikation mit Benutzern über Hilfenachrichten und automatisierte Dokumentation übernimmt.

Strukturierung der Codebasis

Eine der ersten (und größten) Herausforderungen beim Aufbau einer Cobra-basierten Go-CLI ist die Strukturierung Ihres gesamten Codes und Ihrer Dateien. Entgegen der landläufigen Meinung gibt es in Go keine vorgeschriebene Methode, dies zu tun. Weder der Befehl go build noch das Dienstprogramm gofmt werden sich darüber beschweren, wie Sie Ihre Pakete benennen oder Ihre Verzeichnisse organisieren. Dies ist einer der besten Aspekte von Go: Seine Einfachheit und Leistungsfähigkeit machen es einfach, Strukturen zu definieren, die für Sie und Ihr Ingenieurteam funktionieren!

Letztendlich ist es meiner Meinung nach am besten, sich eine Cobra-basierte Go-Codebasis als einen Befehlsbaum vorzustellen und zu strukturieren:

├── Root command
│   ├── Child command
│   ├── Child command
│   │   └── Grandchild command
Nach dem Login kopieren

An der Basis des Baums befindet sich der Root-Befehl: Dies ist der Anker für Ihre gesamte CLI-Anwendung und erhält den Namen Ihrer CLI. Als untergeordnete Befehle angehängt, verfügen Sie über einen Baum mit Verzweigungslogik, der die Struktur Ihres gesamten CLI-Ablaufs bestimmt.

Eines der Dinge, die beim Erstellen von CLIs unglaublich leicht übersehen werden, ist die Benutzererfahrung. Normalerweise empfehle ich Leuten, beim Erstellen von Befehlen und untergeordneten Befehlsstrukturen einem „Wurzelverb-Substantiv“-Paradigma zu folgen, da es logisch abläuft und zu hervorragenden Benutzererlebnissen führt.

Zum Beispiel sehen Sie in Kubectl überall dieses Paradigma: „kubectl get pods“, „kubectl apply …“ oder „kubectl label pods …“ Dies gewährleistet einen sinnvollen Ablauf bei der Art und Weise, wie Benutzer mit Ihrer Befehlszeile interagieren Anwendung und hilft sehr, wenn man mit anderen Leuten über Befehle spricht.

Letztendlich können diese Struktur und dieser Vorschlag Aufschluss darüber geben, wie Sie Ihre Dateien und Verzeichnisse organisieren, aber letztendlich liegt es auch hier an Ihnen, zu bestimmen, wie Sie Ihre CLI strukturieren und den Ablauf den Endbenutzern präsentieren.

In der Pizza-CLI haben wir eine klar definierte Struktur, in der untergeordnete Befehle (und nachfolgende Enkel dieser untergeordneten Befehle) leben. Unter dem cmd-Verzeichnis in seinen eigenen Paketen erhält jeder Befehl seine eigene Implementierung. Das Root-Befehlsgerüst befindet sich in einem pkg/utils-Verzeichnis, da es sinnvoll ist, sich den Root-Befehl als ein Dienstprogramm der obersten Ebene vorzustellen, das von main.go verwendet wird, und nicht als einen Befehl, der möglicherweise viel Wartung erfordert. In der Regel werden Sie in Ihrer Root-Command-Go-Implementierung viele vorgefertigte Dinge einrichten, die Sie nicht oft anfassen, daher ist es schön, diese Dinge aus dem Weg zu räumen.

Hier ist eine vereinfachte Ansicht unserer Verzeichnisstruktur:

├── main.go
├── pkg/
│   ├── utils/
│   │   └── root.go
├── cmd/
│   ├── Child command dir
│   ├── Child command dir
│   │   └── Grandchild command dir
Nach dem Login kopieren

Diese Struktur ermöglicht eine klare Trennung der Anliegen und erleichtert die Pflege und Erweiterung der CLI, wenn sie wächst und wir weitere Befehle hinzufügen.

Go-git verwenden

Eine der Hauptbibliotheken, die wir in der Pizza-CLI verwenden, ist die Go-Git-Bibliothek, eine reine Git-Implementierung in Go, die hoch erweiterbar ist. Während der CODEOWNERS-Generierung ermöglicht uns diese Bibliothek, das Git-Ref-Protokoll zu iterieren, Codeunterschiede zu betrachten und zu bestimmen, welche Git-Autoren mit den von einem Benutzer definierten konfigurierten Attributionen verknüpft sind.

Das Iterieren des Git-Ref-Protokolls eines lokalen Git-Repos ist eigentlich ziemlich einfach:

// 1. Open the local git repository
repo, err := git.PlainOpen("/path/to/your/repo")
if err != nil {
        panic("could not open git repository")
}

// 2. Get the HEAD reference for the local git repo
head, err := repo.Head()
if err != nil {
        panic("could not get repo head")
}

// 3. Create a git ref log iterator based on some options
commitIter, err := repo.Log(&git.LogOptions{
        From:  head.Hash(),
})
if err != nil {
        panic("could not get repo log iterator")
}

defer commitIter.Close()

// 4. Iterate through the commit history
err = commitIter.ForEach(func(commit *object.Commit) error {
        // process each commit as the iterator iterates them
        return nil
})
if err != nil {
        panic("could not process commit iterator")
}
Nach dem Login kopieren

Wenn Sie eine Git-basierte Anwendung erstellen, empfehle ich auf jeden Fall die Verwendung von go-git: Es ist schnell, lässt sich gut in das Go-Ökosystem integrieren und kann für alle möglichen Dinge verwendet werden!

Integrating Posthog telemetry

Our engineering and product team is deeply invested in bringing the best possible command line experience to our end users: this means we’ve taken steps to integrate anonymized telemetry that can report to Posthog on usage and errors out in the wild. This has allowed us to fix the most important bugs first, iterate quickly on popular feature requests, and understand how our users are using the CLI.

Posthog has a first party library in Go that supports this exact functionality. First, we define a Posthog client:

import "github.com/posthog/posthog-go"

// PosthogCliClient is a wrapper around the posthog-go client and is used as a
// API entrypoint for sending OpenSauced telemetry data for CLI commands
type PosthogCliClient struct {
    // client is the Posthog Go client
    client posthog.Client

    // activated denotes if the user has enabled or disabled telemetry
    activated bool

    // uniqueID is the user's unique, anonymous identifier
    uniqueID string
}
Nach dem Login kopieren

Then, after initializing a new client, we can use it through the various struct methods we’ve defined. For example, when logging into the OpenSauced platform, we capture specific information on a successful login:

// CaptureLogin gathers telemetry on users who log into OpenSauced via the CLI
func (p *PosthogCliClient) CaptureLogin(username string) error {
    if p.activated {
        return p.client.Enqueue(posthog.Capture{
            DistinctId: username,
            Event:      "pizza_cli_user_logged_in",
        })
    }

    return nil
}
Nach dem Login kopieren

During command execution, the various “capture” functions get called to capture error paths, happy paths, etc.

For the anonymized IDs, we use Google’s excellent UUID Go library:

newUUID := uuid.New().String()
Nach dem Login kopieren

These UUIDs get stored locally on end users machines as JSON under their home directory: ~/.pizza-cli/telemtry.json. This gives the end user complete authority and autonomy to delete this telemetry data if they want (or disable telemetry altogether through configuration options!) to ensure they’re staying anonymous when using the CLI.

Iterative Development and Testing

Our lean engineering team follows an iterative development process, focusing on delivering small, testable features rapidly. Typically, we do this through GitHub issues, pull requests, milestones, and projects. We use Go's built-in testing framework extensively, writing unit tests for individual functions and integration tests for entire commands.

Unfortunately, Go’s standard testing library doesn’t have great assertion functionality out of the box. It’s easy enough to use “==” or other operands, but most of the time, when going back and reading through tests, it’s nice to be able to eyeball what’s going on with assertions like “assert.Equal” or “assert.Nil”.

We’ve integrated the excellent testify library with its “assert” functionality to allow for smoother test implementation:

config, _, err := LoadConfig(nonExistentPath)
require.Error(t, err)
assert.Nil(t, config)
Nach dem Login kopieren

Using Just

We heavily use Just at OpenSauced, a command runner utility, much like GNU’s “make”, for easily executing small scripts. This has enabled us to quickly onramp new team members or community members to our Go ecosystem since building and testing is as simple as “just build” or “just test”!

For example, to create a simple build utility in Just, within a justfile, we can have:

build:
  go build main.go -o build/pizza
Nach dem Login kopieren

Which will build a Go binary into the build/ directory. Now, building locally is as simple as executing a “just” command.

But we’ve been able to integrate more functionality into using Just and have made it a cornerstone of how our entire build, test, and development framework is executed. For example, to build a binary for the local architecture with injected build time variables (like the sha the binary was built against, the version, the date time, etc.), we can use the local environment and run extra steps in the script before executing the “go build”:

build:
    #!/usr/bin/env sh
  echo "Building for local arch"

  export VERSION="${RELEASE_TAG_VERSION:-dev}"
  export DATETIME=$(date -u +"%Y-%m-%d-%H:%M:%S")
  export SHA=$(git rev-parse HEAD)

  go build \
    -ldflags="-s -w \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.Version=${VERSION}' \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.Sha=${SHA}' \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.Datetime=${DATETIME}' \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.writeOnlyPublicPosthogKey=${POSTHOG_PUBLIC_API_KEY}'" \
    -o build/pizza
Nach dem Login kopieren

We’ve even extended this to enable cross architecture and OS build: Go uses the GOARCH and GOOS env vars to know which CPU architecture and operating system to build against. To build other variants, we can create specific Just commands for that:

# Builds for Darwin linux (i.e., MacOS) on arm64 architecture (i.e. Apple silicon)
build-darwin-arm64:
  #!/usr/bin/env sh

  echo "Building darwin arm64"

  export VERSION="${RELEASE_TAG_VERSION:-dev}"
  export DATETIME=$(date -u +"%Y-%m-%d-%H:%M:%S")
  export SHA=$(git rev-parse HEAD)
  export CGO_ENABLED=0
  export GOOS="darwin"
  export GOARCH="arm64"

  go build \
    -ldflags="-s -w \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.Version=${VERSION}' \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.Sha=${SHA}' \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.Datetime=${DATETIME}' \
    -X 'github.com/open-sauced/pizza-cli/pkg/utils.writeOnlyPublicPosthogKey=${POSTHOG_PUBLIC_API_KEY}'" \
    -o build/pizza-${GOOS}-${GOARCH}
Nach dem Login kopieren

Conclusion

Building the Pizza CLI using Go and Cobra has been an exciting journey and we’re thrilled to share it with you. The combination of Go's performance and simplicity with Cobra's powerful command structuring has allowed us to create a tool that's not only robust and powerful, but also user-friendly and maintainable.

We invite you to explore the Pizza CLI GitHub repository, try out the tool, and let us know your thoughts. Your feedback and contributions are invaluable as we work to make code ownership management easier for development teams everywhere!

Das obige ist der detaillierte Inhalt vonTechnischer Deep Dive: Wie wir die Pizza-CLI mit Go und Cobra erstellt haben. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

Video Face Swap

Video Face Swap

Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

<🎜>: Bubble Gum Simulator Infinity - So erhalten und verwenden Sie Royal Keys
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusionssystem, erklärt
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
Mandragora: Flüstern des Hexenbaum
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

Java-Tutorial
1671
14
PHP-Tutorial
1276
29
C#-Tutorial
1256
24
Golang gegen Python: Leistung und Skalierbarkeit Golang gegen Python: Leistung und Skalierbarkeit Apr 19, 2025 am 12:18 AM

Golang ist in Bezug auf Leistung und Skalierbarkeit besser als Python. 1) Golangs Kompilierungseigenschaften und effizientes Parallelitätsmodell machen es in hohen Parallelitätsszenarien gut ab. 2) Python wird als interpretierte Sprache langsam ausgeführt, kann aber die Leistung durch Tools wie Cython optimieren.

Golang und C: Parallelität gegen Rohgeschwindigkeit Golang und C: Parallelität gegen Rohgeschwindigkeit Apr 21, 2025 am 12:16 AM

Golang ist in Gleichzeitigkeit besser als C, während C bei Rohgeschwindigkeit besser als Golang ist. 1) Golang erreicht durch Goroutine und Kanal eine effiziente Parallelität, die zum Umgang mit einer großen Anzahl von gleichzeitigen Aufgaben geeignet ist. 2) C über Compiler -Optimierung und Standardbibliothek bietet es eine hohe Leistung in der Nähe der Hardware, die für Anwendungen geeignet ist, die eine extreme Optimierung erfordern.

Erste Schritte mit Go: Ein Anfängerführer Erste Schritte mit Go: Ein Anfängerführer Apr 26, 2025 am 12:21 AM

GoisidealforBeginersandSuitableforCloudandNetWorkServicesDuetoitsSimplicity, Effizienz und Konsumfeaturen.1) InstallgoFromTheofficialwebSiteAnDverifyWith'goversion'.2) CreateAneDrunyourFirstProgramwith'gorunhello.go.go.go.

Golang gegen C: Leistung und Geschwindigkeitsvergleich Golang gegen C: Leistung und Geschwindigkeitsvergleich Apr 21, 2025 am 12:13 AM

Golang ist für schnelle Entwicklung und gleichzeitige Szenarien geeignet, und C ist für Szenarien geeignet, in denen extreme Leistung und Kontrolle auf niedriger Ebene erforderlich sind. 1) Golang verbessert die Leistung durch Müllsammlung und Parallelitätsmechanismen und eignet sich für die Entwicklung von Webdiensten mit hoher Konsequenz. 2) C erreicht die endgültige Leistung durch das manuelle Speicherverwaltung und die Compiler -Optimierung und eignet sich für eingebettete Systementwicklung.

Golangs Auswirkungen: Geschwindigkeit, Effizienz und Einfachheit Golangs Auswirkungen: Geschwindigkeit, Effizienz und Einfachheit Apr 14, 2025 am 12:11 AM

GoimpactsDevelopmentPositivyThroughSpeed, Effizienz und DiasMlitication.1) Geschwindigkeit: Gocompilesquickandrunseffiction, idealforlargeProjects

Golang gegen Python: Schlüsselunterschiede und Ähnlichkeiten Golang gegen Python: Schlüsselunterschiede und Ähnlichkeiten Apr 17, 2025 am 12:15 AM

Golang und Python haben jeweils ihre eigenen Vorteile: Golang ist für hohe Leistung und gleichzeitige Programmierung geeignet, während Python für Datenwissenschaft und Webentwicklung geeignet ist. Golang ist bekannt für sein Parallelitätsmodell und seine effiziente Leistung, während Python für sein Ökosystem für die kurze Syntax und sein reiches Bibliothek bekannt ist.

Golang und C: Die Kompromisse bei der Leistung Golang und C: Die Kompromisse bei der Leistung Apr 17, 2025 am 12:18 AM

Die Leistungsunterschiede zwischen Golang und C spiegeln sich hauptsächlich in der Speicherverwaltung, der Kompilierungsoptimierung und der Laufzeiteffizienz wider. 1) Golangs Müllsammlung Mechanismus ist praktisch, kann jedoch die Leistung beeinflussen.

Das Performance -Rennen: Golang gegen C. Das Performance -Rennen: Golang gegen C. Apr 16, 2025 am 12:07 AM

Golang und C haben jeweils ihre eigenen Vorteile bei Leistungswettbewerben: 1) Golang ist für eine hohe Parallelität und schnelle Entwicklung geeignet, und 2) C bietet eine höhere Leistung und eine feinkörnige Kontrolle. Die Auswahl sollte auf Projektanforderungen und Teamtechnologie -Stack basieren.

See all articles