"यदि कोई कर्मचारी अपना काम अच्छी तरह से करना चाहता है, तो उसे पहले अपने औजारों को तेज करना होगा।" - कन्फ्यूशियस, "द एनालेक्ट्स ऑफ कन्फ्यूशियस। लू लिंगगोंग"
मुखपृष्ठ > प्रोग्रामिंग > टेक्निकल डीप डाइव: हमने गो और कोबरा का उपयोग करके पिज्जा सीएलआई कैसे बनाया

टेक्निकल डीप डाइव: हमने गो और कोबरा का उपयोग करके पिज्जा सीएलआई कैसे बनाया

2024-11-01 को प्रकाशित
ब्राउज़ करें:242

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

पिछले हफ्ते, ओपनसॉस्ड इंजीनियरिंग टीम ने पिज़्ज़ा सीएलआई जारी किया, जो कोडओनर फ़ाइलें बनाने और ओपनसॉस्ड प्लेटफ़ॉर्म के साथ एकीकृत करने के लिए एक शक्तिशाली और कंपोज़ेबल कमांड-लाइन टूल है। मजबूत कमांड-लाइन टूल बनाना सरल लग सकता है, लेकिन सावधानीपूर्वक योजना और विचारशील प्रतिमानों के बिना, सीएलआई जल्दी से कोड की उलझी हुई गड़बड़ी बन सकती हैं जिन्हें बनाए रखना मुश्किल होता है और बग से भरा होता है। इस ब्लॉग पोस्ट में, हम गहराई से जानेंगे कि हमने गो का उपयोग करके इस सीएलआई को कैसे बनाया, हम कोबरा का उपयोग करके अपने कमांड को कैसे व्यवस्थित करते हैं, और हमारी कमजोर इंजीनियरिंग टीम शक्तिशाली कार्यक्षमता बनाने के लिए कैसे तेजी से पुनरावृत्ति करती है।

गो और कोबरा का उपयोग करना

पिज्जा सीएलआई एक गो कमांड-लाइन टूल है जो कई मानक पुस्तकालयों का लाभ उठाता है। गो की सरलता, गति और सिस्टम प्रोग्रामिंग फोकस इसे सीएलआई के निर्माण के लिए एक आदर्श विकल्प बनाता है। इसके मूल में, पिज्जा-सीएलआई कमांड के पूरे पेड़ को व्यवस्थित और प्रबंधित करने के लिए, गो में एक सीएलआई बूटस्ट्रैपिंग लाइब्रेरी एसपीएफ 13/कोबरा का उपयोग करता है।

आप कोबरा को एक मचान के रूप में सोच सकते हैं जो एक कमांड-लाइन इंटरफ़ेस को स्वयं काम करता है, सभी झंडों को लगातार काम करने में सक्षम बनाता है, और सहायता संदेशों और स्वचालित दस्तावेज़ीकरण के माध्यम से उपयोगकर्ताओं से संचार संभालता है।

कोडबेस की संरचना करना

कोबरा-आधारित गो सीएलआई बनाते समय पहली (और सबसे बड़ी) चुनौतियों में से एक यह है कि आपके सभी कोड और फ़ाइलों को कैसे व्यवस्थित किया जाए। आम धारणा के विपरीत, गो में ऐसा करने का कोई कोई निर्धारित तरीका नहीं है। न तो गो बिल्ड कमांड और न ही गोफएमटी उपयोगिता इस बारे में शिकायत करेगी कि आप अपने पैकेजों को कैसे नाम देते हैं या अपनी निर्देशिकाओं को कैसे व्यवस्थित करते हैं। यह गो के सबसे अच्छे हिस्सों में से एक है: इसकी सादगी और शक्ति उन संरचनाओं को परिभाषित करना आसान बनाती है जो आपके और आपकी इंजीनियरिंग टीम के लिए काम करती हैं!

आखिरकार, मेरी राय में, कोबरा-आधारित गो कोडबेस को कमांड के पेड़ के रूप में सोचना और संरचना करना सबसे अच्छा है:

├── Root command
│   ├── Child command
│   ├── Child command
│   │   └── Grandchild command

पेड़ के आधार पर रूट कमांड है: यह आपके संपूर्ण सीएलआई एप्लिकेशन के लिए एंकर है और इसे आपके सीएलआई का नाम मिलेगा। चाइल्ड कमांड के रूप में संलग्न, आपके पास ब्रांचिंग लॉजिक का एक पेड़ होगा जो संरचना को सूचित करता है कि आपका संपूर्ण सीएलआई प्रवाह कैसे काम करता है।

सीएलआई बनाते समय जिन चीजों को नजरअंदाज करना अविश्वसनीय रूप से आसान है उनमें से एक उपयोगकर्ता अनुभव है। मैं आमतौर पर लोगों को कमांड और चाइल्ड-कमांड संरचनाओं का निर्माण करते समय "रूट वर्ब संज्ञा" प्रतिमान का पालन करने की सलाह देता हूं क्योंकि यह तार्किक रूप से प्रवाहित होता है और उत्कृष्ट उपयोगकर्ता अनुभवों की ओर ले जाता है।

उदाहरण के लिए, Kubectl में, आपको यह प्रतिमान हर जगह दिखाई देगा: "kubectl get pods", "kubectl apply...", या "kubectl label pods..." यह एक संवेदनशील प्रवाह सुनिश्चित करता है कि उपयोगकर्ता आपकी कमांड लाइन के साथ कैसे इंटरैक्ट करेंगे एप्लिकेशन और अन्य लोगों के साथ कमांड के बारे में बात करते समय बहुत मदद करता है।

अंत में, यह संरचना और सुझाव यह बता सकता है कि आप अपनी फ़ाइलों और निर्देशिकाओं को कैसे व्यवस्थित करते हैं, लेकिन फिर, अंततः यह आप पर निर्भर करता है कि आप अपने सीएलआई की संरचना कैसे करते हैं और अंतिम उपयोगकर्ताओं के लिए प्रवाह कैसे प्रस्तुत करते हैं।

पिज्जा सीएलआई में, हमारे पास एक अच्छी तरह से परिभाषित संरचना है जहां चाइल्ड कमांड (और उन चाइल्ड कमांड के बाद के पोते) रहते हैं। अपने स्वयं के पैकेज में cmd ​​निर्देशिका के अंतर्गत, प्रत्येक कमांड को अपना स्वयं का कार्यान्वयन मिलता है। रूट कमांड स्कैफोल्डिंग pkg/utils निर्देशिका में मौजूद है क्योंकि रूट कमांड को एक शीर्ष स्तर की उपयोगिता के रूप में सोचना उपयोगी है जो main.go द्वारा उपयोग किया जाता है, न कि एक कमांड जिसे बहुत अधिक रखरखाव की आवश्यकता हो सकती है। आमतौर पर, आपके रूट कमांड गो कार्यान्वयन में, आपके पास बहुत सारी बॉयलरप्लेट सेटिंग वाली चीज़ें होंगी जिन्हें आप ज़्यादा नहीं छू पाएंगे, इसलिए उस चीज़ को रास्ते से हटा देना अच्छा है।

यहां हमारी निर्देशिका संरचना का एक सरलीकृत दृश्य है:

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

यह संरचना चिंताओं को स्पष्ट रूप से अलग करने की अनुमति देती है और जैसे-जैसे सीएलआई बढ़ती है और जैसे-जैसे हम अधिक कमांड जोड़ते हैं, इसे बनाए रखना और विस्तारित करना आसान हो जाता है।

गो-गिट का उपयोग करना

पिज़्ज़ा-सीएलआई में हमारे द्वारा उपयोग की जाने वाली मुख्य लाइब्रेरी में से एक गो-गिट लाइब्रेरी है, जो गो में एक शुद्ध गिट कार्यान्वयन है जो अत्यधिक विस्तार योग्य है। CodeOWNERS जेनरेशन के दौरान, यह लाइब्रेरी हमें git ref लॉग को पुनरावृत्त करने, कोड के अंतर को देखने और यह निर्धारित करने में सक्षम बनाती है कि कौन से git लेखक उपयोगकर्ता द्वारा परिभाषित कॉन्फ़िगर किए गए एट्रिब्यूशन से जुड़े हैं।

स्थानीय गिट रेपो के गिट रेफरी लॉग को पुनरावृत्त करना वास्तव में बहुत सरल है:

// 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 आधारित एप्लिकेशन बना रहे हैं, तो मैं निश्चित रूप से गो-गिट का उपयोग करने की सलाह देता हूं: यह तेज़ है, गो पारिस्थितिकी तंत्र के भीतर अच्छी तरह से एकीकृत है, और इसका उपयोग सभी प्रकार की चीजों को करने के लिए किया जा सकता है!

पोस्टहोग टेलीमेट्री को एकीकृत करना

हमारी इंजीनियरिंग और उत्पाद टीम ने हमारे अंतिम उपयोगकर्ताओं के लिए सर्वोत्तम संभव कमांड लाइन अनुभव लाने में गहराई से निवेश किया है: इसका मतलब है कि हमने अज्ञात टेलीमेट्री को एकीकृत करने के लिए कदम उठाए हैं जो पोस्टहॉग को उपयोग और त्रुटियों के बारे में रिपोर्ट कर सकते हैं। इससे हमें सबसे महत्वपूर्ण बग्स को पहले ठीक करने, लोकप्रिय फीचर अनुरोधों पर तुरंत पुनरावृत्ति करने और यह समझने में मदद मिली है कि हमारे उपयोगकर्ता सीएलआई का उपयोग कैसे कर रहे हैं।

पोस्टहोग के पास गो में एक प्रथम पक्ष लाइब्रेरी है जो इस सटीक कार्यक्षमता का समर्थन करती है। सबसे पहले, हम एक पोस्टहोग क्लाइंट को परिभाषित करते हैं:

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
}

फिर, एक नए क्लाइंट को आरंभ करने के बाद, हम इसे हमारे द्वारा परिभाषित विभिन्न संरचना विधियों के माध्यम से उपयोग कर सकते हैं। उदाहरण के लिए, ओपनसॉस्ड प्लेटफ़ॉर्म में लॉग इन करते समय, हम सफल लॉगिन पर विशिष्ट जानकारी प्राप्त करते हैं:

// 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
}

कमांड निष्पादन के दौरान, त्रुटि पथ, खुश पथ आदि को कैप्चर करने के लिए विभिन्न "कैप्चर" फ़ंक्शन को कॉल किया जाता है।

अज्ञात आईडी के लिए, हम Google की उत्कृष्ट यूयूआईडी गो लाइब्रेरी का उपयोग करते हैं:

newUUID := uuid.New().String()

ये यूयूआईडी स्थानीय रूप से अंतिम उपयोगकर्ताओं की मशीनों पर उनकी होम निर्देशिका के तहत JSON के रूप में संग्रहीत होते हैं: ~/.पिज्जा-सीएलआई/टेलीमेट्री.जेसन। यह अंतिम उपयोगकर्ता को इस टेलीमेट्री डेटा को हटाने का पूरा अधिकार और स्वायत्तता देता है यदि वे चाहें (या कॉन्फ़िगरेशन विकल्पों के माध्यम से टेलीमेट्री को पूरी तरह से अक्षम कर दें!) ताकि यह सुनिश्चित हो सके कि सीएलआई का उपयोग करते समय वे गुमनाम रहें।

पुनरावृत्तीय विकास और परीक्षण

हमारी दुबली इंजीनियरिंग टीम एक पुनरावृत्तीय विकास प्रक्रिया का पालन करती है, जो तेजी से छोटी, परीक्षण योग्य सुविधाओं को वितरित करने पर ध्यान केंद्रित करती है। आमतौर पर, हम इसे GitHub मुद्दों, पुल अनुरोधों, मील के पत्थर और परियोजनाओं के माध्यम से करते हैं। हम गो के अंतर्निर्मित परीक्षण ढांचे का बड़े पैमाने पर उपयोग करते हैं, व्यक्तिगत कार्यों के लिए यूनिट परीक्षण लिखते हैं और संपूर्ण कमांड के लिए एकीकरण परीक्षण लिखते हैं।

दुर्भाग्य से, गो की मानक परीक्षण लाइब्रेरी में बॉक्स से बाहर महान अभिकथन कार्यक्षमता नहीं है। "==" या अन्य ऑपरेंड का उपयोग करना काफी आसान है, लेकिन ज्यादातर समय, जब वापस जाते हैं और परीक्षणों को पढ़ते हैं, तो यह देखना अच्छा होता है कि "assert.Equal" या "assert.Nil" जैसे दावों के साथ क्या हो रहा है। ”.

हमने सुचारू परीक्षण कार्यान्वयन की अनुमति देने के लिए उत्कृष्ट गवाही पुस्तकालय को इसकी "जोरदार" कार्यक्षमता के साथ एकीकृत किया है:

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

जस्ट का उपयोग करना

हम छोटी स्क्रिप्ट को आसानी से निष्पादित करने के लिए जीएनयू के "मेक" की तरह, जस्ट एट ओपनसॉस्ड, एक कमांड रनर उपयोगिता का भारी उपयोग करते हैं। इसने हमें नई टीम के सदस्यों या समुदाय के सदस्यों को हमारे गो इकोसिस्टम में जल्दी से शामिल करने में सक्षम बनाया है क्योंकि निर्माण और परीक्षण "बस निर्माण" या "बस परीक्षण" जितना सरल है!

उदाहरण के लिए, जस्टफाइल के भीतर जस्ट में एक सरल बिल्ड उपयोगिता बनाने के लिए, हम यह कर सकते हैं:

build:
  go build main.go -o build/pizza

जो बिल्ड/डायरेक्टरी में एक गो बाइनरी बनाएगा। अब, स्थानीय स्तर पर निर्माण करना "सिर्फ" कमांड निष्पादित करने जितना आसान है।

लेकिन हम जस्ट का उपयोग करके अधिक कार्यक्षमता को एकीकृत करने में सक्षम हैं और इसे हमारे संपूर्ण निर्माण, परीक्षण और विकास ढांचे को निष्पादित करने की आधारशिला बना दिया है। उदाहरण के लिए, इंजेक्टेड बिल्ड टाइम वैरिएबल के साथ स्थानीय आर्किटेक्चर के लिए बाइनरी बनाने के लिए (जैसे कि बाइनरी को किस शा के खिलाफ बनाया गया था, संस्करण, दिनांक समय इत्यादि), हम स्थानीय वातावरण का उपयोग कर सकते हैं और स्क्रिप्ट में अतिरिक्त चरण चला सकते हैं "गो बिल्ड" निष्पादित करने से पहले:

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

हमने इसे क्रॉस आर्किटेक्चर और ओएस बिल्ड को सक्षम करने के लिए भी बढ़ाया है: गो यह जानने के लिए GOARCH और GOOS env vars का उपयोग करता है कि किस सीपीयू आर्किटेक्चर और ऑपरेटिंग सिस्टम के खिलाफ निर्माण करना है। अन्य वेरिएंट बनाने के लिए, हम उसके लिए विशिष्ट जस्ट कमांड बना सकते हैं:

# 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}

निष्कर्ष

गो और कोबरा का उपयोग करके पिज्जा सीएलआई का निर्माण एक रोमांचक यात्रा रही है और हम इसे आपके साथ साझा करने के लिए रोमांचित हैं। कोबरा की शक्तिशाली कमांड संरचना के साथ गो के प्रदर्शन और सरलता के संयोजन ने हमें एक ऐसा टूल बनाने की अनुमति दी है जो न केवल मजबूत और शक्तिशाली है, बल्कि उपयोगकर्ता के अनुकूल और रखरखाव योग्य भी है।

हम आपको पिज़्ज़ा सीएलआई गिटहब रिपॉजिटरी का पता लगाने, टूल को आज़माने और हमें अपने विचार बताने के लिए आमंत्रित करते हैं। आपकी प्रतिक्रिया और योगदान अमूल्य हैं क्योंकि हम हर जगह विकास टीमों के लिए कोड स्वामित्व प्रबंधन को आसान बनाने के लिए काम करते हैं!

विज्ञप्ति वक्तव्य इस लेख को पुन: प्रस्तुत किया गया है: https://dev.to/opensauced/technical-deep-dive-how-we-built-the-pizza-cli-go-go-and-cobra-oad?1 यदि कोई उल्लंघन है, तो कृपया इसे हटाने के लिए [email protected] पर संपर्क करें।
नवीनतम ट्यूटोरियल अधिक>

चीनी भाषा का अध्ययन करें

अस्वीकरण: उपलब्ध कराए गए सभी संसाधन आंशिक रूप से इंटरनेट से हैं। यदि आपके कॉपीराइट या अन्य अधिकारों और हितों का कोई उल्लंघन होता है, तो कृपया विस्तृत कारण बताएं और कॉपीराइट या अधिकारों और हितों का प्रमाण प्रदान करें और फिर इसे ईमेल पर भेजें: [email protected] हम इसे आपके लिए यथाशीघ्र संभालेंगे।

Copyright© 2022 湘ICP备2022001581号-3