백엔드 개발 Golang 기술 심층 분석: Go 및 Cobra를 사용하여 Pizza CLI를 구축한 방법

기술 심층 분석: Go 및 Cobra를 사용하여 Pizza CLI를 구축한 방법

Sep 24, 2024 am 06:18 AM

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

지난주 OpenSauced 엔지니어링 팀은 CODEOWNER 파일을 생성하고 OpenSauced 플랫폼과 통합하기 위한 강력하고 구성 가능한 명령줄 도구인 Pizza CLI를 출시했습니다. 강력한 명령줄 도구를 구축하는 것은 간단해 보일 수 있지만 신중한 계획과 사려 깊은 패러다임이 없으면 CLI는 유지 관리가 어렵고 버그로 가득 찬 엉킨 코드가 될 수 있습니다. 이 블로그 게시물에서는 Go를 사용하여 이 CLI를 구축한 방법, Cobra를 사용하여 명령을 구성하는 방법, 린 엔지니어링 팀이 강력한 기능을 구축하기 위해 빠르게 반복하는 방법에 대해 자세히 살펴보겠습니다.

Go와 Cobra 사용

Pizza CLI는 여러 표준 라이브러리를 활용하는 Go 명령줄 도구입니다. Go의 단순성, 속도 및 시스템 프로그래밍 초점은 CLI 구축에 이상적인 선택입니다. 기본적으로 Pizza-CLI는 Go의 CLI 부트스트래핑 라이브러리인 spf13/cobra를 사용하여 전체 명령 트리를 구성하고 관리합니다.

Cobra는 명령줄 인터페이스 자체를 작동시키고, 모든 플래그가 일관되게 작동하도록 하며, 도움말 메시지와 자동화된 문서를 통해 사용자와의 통신을 처리하는 스캐폴딩이라고 생각할 수 있습니다.

코드베이스 구조화

Cobra 기반 Go CLI를 구축할 때 가장 먼저(그리고 가장 큰) 과제 중 하나는 모든 코드와 파일을 구조화하는 방법입니다. 대중적인 믿음과는 달리, Go에는 이를 수행하는 규정된 방법이 없습니다. go build 명령이나 gofmt 유틸리티는 패키지 이름 지정이나 디렉터리 구성 방법에 대해 불평하지 않습니다. 이것이 Go의 가장 좋은 부분 중 하나입니다. Go의 단순성과 강력함 덕분에 귀하와 귀하의 엔지니어링 팀에 적합한 구조를 쉽게 정의할 수 있습니다!

결국 내 생각에는 Cobra 기반 Go 코드베이스를 명령 트리로 생각하고 구성하는 것이 가장 좋습니다.

├── Root command
│   ├── Child command
│   ├── Child command
│   │   └── Grandchild command
로그인 후 복사

트리의 기본에는 루트 명령이 있습니다. 이는 전체 CLI 애플리케이션의 앵커이며 CLI 이름을 가져옵니다. 하위 명령으로 연결하면 전체 CLI 흐름이 작동하는 방식의 구조를 알려주는 분기 논리 트리가 제공됩니다.

CLI를 구축할 때 놓치기 쉬운 것 중 하나는 사용자 경험입니다. 나는 일반적으로 명령과 하위 명령 구조를 작성할 때 "루트 동사 명사" 패러다임을 따르는 것이 논리적으로 흐르고 뛰어난 사용자 경험으로 이어지기 때문에 권장합니다.

예를 들어 Kubectl에서는 "kubectl get pods", "kubectl apply …" 또는 "kubectl label pods …"와 같은 패러다임을 어디에서나 볼 수 있습니다. 이는 사용자가 명령줄과 상호 작용하는 방식에 대한 감각적인 흐름을 보장합니다. 응용 프로그램을 사용하면 다른 사람들과 명령에 대해 이야기할 때 많은 도움이 됩니다.

결국 이 구조와 제안은 파일과 디렉터리를 구성하는 방법을 알려줄 수 있지만 CLI를 구성하고 최종 사용자에게 흐름을 제시하는 방법을 결정하는 것은 궁극적으로 사용자에게 달려 있습니다.

Pizza CLI에는 하위 명령(및 해당 하위 명령의 후속 손자)이 존재하는 잘 정의된 구조가 있습니다. 자체 패키지의 cmd 디렉터리 아래에서 각 명령은 자체적으로 구현됩니다. 루트 명령 스캐폴딩은 pkg/utils 디렉토리에 존재합니다. 왜냐하면 루트 명령을 유지 관리가 많이 필요한 명령이 아니라 main.go에서 사용하는 최상위 유틸리티로 생각하는 것이 유용하기 때문입니다. 일반적으로 루트 명령 Go 구현에는 많이 건드리지 않는 상용구 설정 항목이 많이 있으므로 해당 항목을 방해하지 않는 것이 좋습니다.

다음은 디렉토리 구조를 간략하게 나타낸 것입니다.

├── main.go
├── pkg/
│   ├── utils/
│   │   └── root.go
├── cmd/
│   ├── Child command dir
│   ├── Child command dir
│   │   └── Grandchild command dir
로그인 후 복사

이 구조를 사용하면 문제를 명확하게 분리할 수 있으며 CLI가 성장하고 더 많은 명령을 추가함에 따라 CLI를 더 쉽게 유지 관리하고 확장할 수 있습니다.

go-git 사용하기

우리가 Pizza-CLI에서 사용하는 주요 라이브러리 중 하나는 확장성이 뛰어난 Go의 순수 git 구현인 go-git 라이브러리입니다. CODEOWNERS 생성 중에 이 라이브러리를 사용하면 git ref 로그를 반복하고, 코드 차이점을 확인하고, 사용자가 정의한 구성된 특성과 연결된 git 작성자를 확인할 수 있습니다.

로컬 git 저장소의 git ref 로그를 반복하는 것은 실제로 매우 간단합니다.

// 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")
}
로그인 후 복사

Git 기반 애플리케이션을 구축하는 경우 go-git을 사용하는 것이 좋습니다. 속도가 빠르고 Go 생태계 내에서 잘 통합되며 모든 종류의 작업에 사용할 수 있습니다!

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
}
로그인 후 복사

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
}
로그인 후 복사

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()
로그인 후 복사

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)
로그인 후 복사

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
로그인 후 복사

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
로그인 후 복사

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}
로그인 후 복사

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!

위 내용은 기술 심층 분석: Go 및 Cobra를 사용하여 Pizza CLI를 구축한 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

<gum> : Bubble Gum Simulator Infinity- 로얄 키를 얻고 사용하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
Nordhold : Fusion System, 설명
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora : 마녀 트리의 속삭임 - Grappling Hook 잠금 해제 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Golang vs. Python : 성능 및 확장 성 Golang vs. Python : 성능 및 확장 성 Apr 19, 2025 am 12:18 AM

Golang은 성능과 확장 성 측면에서 Python보다 낫습니다. 1) Golang의 컴파일 유형 특성과 효율적인 동시성 모델은 높은 동시성 시나리오에서 잘 수행합니다. 2) 해석 된 언어로서 파이썬은 천천히 실행되지만 Cython과 같은 도구를 통해 성능을 최적화 할 수 있습니다.

Golang 및 C : 동시성 대 원시 속도 Golang 및 C : 동시성 대 원시 속도 Apr 21, 2025 am 12:16 AM

Golang은 동시성에서 C보다 낫고 C는 원시 속도에서 Golang보다 낫습니다. 1) Golang은 Goroutine 및 Channel을 통해 효율적인 동시성을 달성하며, 이는 많은 동시 작업을 처리하는 데 적합합니다. 2) C 컴파일러 최적화 및 표준 라이브러리를 통해 하드웨어에 가까운 고성능을 제공하며 극도의 최적화가 필요한 애플리케이션에 적합합니다.

GOT GO로 시작 : 초보자 가이드 GOT GO로 시작 : 초보자 가이드 Apr 26, 2025 am 12:21 AM

goisidealforbeginnersandsuitableforcloudandnetworkservicesduetoitssimplicity, 효율성, 및 콘크리 론 피처

Golang vs. C : 성능 및 속도 비교 Golang vs. C : 성능 및 속도 비교 Apr 21, 2025 am 12:13 AM

Golang은 빠른 개발 및 동시 시나리오에 적합하며 C는 극도의 성능 및 저수준 제어가 필요한 시나리오에 적합합니다. 1) Golang은 쓰레기 수집 및 동시성 메커니즘을 통해 성능을 향상시키고, 고전성 웹 서비스 개발에 적합합니다. 2) C는 수동 메모리 관리 및 컴파일러 최적화를 통해 궁극적 인 성능을 달성하며 임베디드 시스템 개발에 적합합니다.

Golang vs. Python : 주요 차이점과 유사성 Golang vs. Python : 주요 차이점과 유사성 Apr 17, 2025 am 12:15 AM

Golang과 Python은 각각 고유 한 장점이 있습니다. Golang은 고성능 및 동시 프로그래밍에 적합하지만 Python은 데이터 과학 및 웹 개발에 적합합니다. Golang은 동시성 모델과 효율적인 성능으로 유명하며 Python은 간결한 구문 및 풍부한 라이브러리 생태계로 유명합니다.

Golang 및 C : 성능 상충 Golang 및 C : 성능 상충 Apr 17, 2025 am 12:18 AM

Golang과 C의 성능 차이는 주로 메모리 관리, 컴파일 최적화 및 런타임 효율에 반영됩니다. 1) Golang의 쓰레기 수집 메커니즘은 편리하지만 성능에 영향을 줄 수 있습니다. 2) C의 수동 메모리 관리 및 컴파일러 최적화는 재귀 컴퓨팅에서 더 효율적입니다.

공연 경주 : 골랑 대 c 공연 경주 : 골랑 대 c Apr 16, 2025 am 12:07 AM

Golang과 C는 각각 공연 경쟁에서 고유 한 장점을 가지고 있습니다. 1) Golang은 높은 동시성과 빠른 발전에 적합하며 2) C는 더 높은 성능과 세밀한 제어를 제공합니다. 선택은 프로젝트 요구 사항 및 팀 기술 스택을 기반으로해야합니다.

Golang vs. Python : 장단점 Golang vs. Python : 장단점 Apr 21, 2025 am 12:17 AM

golangisidealforbuildingscalablesystemsdueToitsefficiencyandconcurrency

See all articles