مرکزی مواد پر جائیں
ماڈیول 10 · سبق 4 از 5کورس میں 49/50~18 min
ماڈیول اسباق (4/5)

منی پروجیکٹ: جھنڈوں کے ساتھ ایک CLI

آئیے ایک چھوٹا محاورہ CLI بنانے کے لیے پچھلے ماڈیولز کے بلڈنگ بلاکس کو ایک ساتھ ڈالتے ہیں: flag پیکیج کے ساتھ جھنڈا پارس کرنا، پوزیشنی دلیلوں کو سنبھالنا، os.Stderr پر غلطیاں، اور صحیح ایگزٹ کوڈ۔

flag پیکیج

Go
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    n := flag.Int("n", 1, "number of repetitions")
    upper := flag.Bool("u", false, "print in uppercase")
    flag.Parse()

    args := flag.Args() // remaining positional arguments
    if len(args) < 1 {
        fmt.Fprintln(os.Stderr, "usage: echo [-n N] [-u] <text>")
        os.Exit(2)
    }

    text := args[0]
    if *upper {
        text = strings.ToUpper(text)
    }
    for i := 0; i < *n; i++ {
        fmt.Println(text)
    }
}

اہم نکات:

  • flag.Int, flag.String, flag.Bool, flag.Duration (وغیرہ) ایک پوائنٹر واپس کریں: آپ *n، ​​*upper استعمال کرتے ہیں۔
  • flag.Parse() کو ایک بار کال کرنا ضروری ہے، اقدار کو پڑھنے سے پہلے اور flag.Args() سے پہلے۔
  • flag.Args() پوزیشنل دلائل واپس کرتا ہے (جو -- کے بعد یا آخری جھنڈے کے بعد)۔
  • قبول شدہ فارمز: -n 3, -n=3, --n=3۔ بولین: -u (سچ)، -u=false۔

روایتی ایگزٹ کوڈز

Go
os.Exit(0) // success
os.Exit(1) // generic error
os.Exit(2) // usage error (incorrect flag usage)

شیلز اور اسکرپٹ ان کوڈز کی توقع کرتے ہیں: انہیں مستقل طور پر استعمال کریں۔ کبھی بھی os.Exit کے ساتھ غیر اہم گوروٹین سے باہر نہ نکلیں: یہ ہر defer کو چھوڑ دیتا ہے، بشمول log فلشنگ۔

Stderr بمقابلہ Stdout

پرانا اور مقدس یونکس اصول:

  • os.Stdout → مفید آؤٹ پٹ، پائپ کے قابل (cli | grep ...)۔
  • os.Stderr → تشخیص، غلطیاں، پیش رفت بار، استعمال۔
Go
fmt.Println("result: 42")                   // stdout
fmt.Fprintln(os.Stderr, "error: ...")       // stderr

اس طرح cli 2>/dev/null صرف نتائج دکھاتا ہے، cli >out.txt صرف نتیجہ کو ری ڈائریکٹ کرتا ہے اور غلطیاں نظر آتی رہتی ہیں۔

log بمقابلہ fmt

  • fmt صارف کے آؤٹ پٹ کے لیے۔
  • log تشخیص کے لیے: ٹائم اسٹیمپ جوڑتا ہے، os.Stderr کو بطور ڈیفالٹ لکھتا ہے، اس میں log.Fatal (لاگز + os.Exit(1)) اور log.Panic ہوتے ہیں۔
Go
log.SetFlags(log.LstdFlags | log.Lshortfile) // timestamp + file:line
log.Fatal("boom") // prints and exits with 1

جدید ایپس (Go 1.21+) کے لیے log/slog کا استعمال کریں سٹرکچرڈ لاگنگ (JSON یا ٹیکسٹ، لیولز، ٹائپ شدہ فیلڈز)

فن تعمیر: main کو منطق سے الگ کریں۔

Go
func main() {
    if err := run(os.Args[1:], os.Stdout, os.Stderr); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

func run(args []string, stdout, stderr io.Writer) error {
    // here use a new flag.FlagSet instead of the global flag.CommandLine
    fs := flag.NewFlagSet("echo", flag.ContinueOnError)
    fs.SetOutput(stderr)
    n := fs.Int("n", 1, "repetitions")
    if err := fs.Parse(args); err != nil {
        return err
    }
    // ...
    return nil
}

فوائد:

  • ٹیسٹ ایبل: آپ bytes.Buffer کو بطور stdout/stderr پاس کرتے ہیں اور آؤٹ پٹ کی تصدیق کرتے ہیں۔
  • کوئی عالمی ریاست نہیں: ہر ایک FlagSet الگ تھلگ ہے۔
  • main چھوٹا رہتا ہے: یہ IO + مندوبین کو تیار کرتا ہے۔

ذیلی کمانڈز

ذیلی کمانڈ کے ساتھ CLIs کے لیے (mycli serve, mycli migrate)، ایک اسکیم جس میں کوئی بیرونی انحصار نہیں ہے:

Go
func main() {
    if len(os.Args) < 2 {
        usage()
        os.Exit(2)
    }
    switch os.Args[1] {
    case "serve":
        serveCmd(os.Args[2:])
    case "migrate":
        migrateCmd(os.Args[2:])
    default:
        usage()
        os.Exit(2)
    }
}

ہر ذیلی کمانڈ کی اپنی flag.NewFlagSet ہوتی ہے۔ بڑے پروجیکٹس کے لیے، لائبریریاں جیسے cobra یا urfave/cli اس اسکیم کو خود کار طریقے سے تیار کردہ مدد سے ڈھانچہ دیتی ہیں۔

مشقیں

ورزش#go.m10.l4.e1
کوششیں: 0لوڈ ہو رہا ہے…

Definisci il flag -n di tipo int con valore di default 1 e descrizione 'ripetizioni', poi chiama flag.Parse() e stampa il valore.

ایڈیٹر لوڈ ہو رہا ہے…

3 کوششوں کے بعد حل دستیاب ہے۔

ورزش#go.m10.l4.e2
کوششیں: 0لوڈ ہو رہا ہے…

Se non c'è almeno un argomento positionale dopo flag.Parse, stampa 'manca argomento' su Stderr e termina con os.Exit(1)۔

ایڈیٹر لوڈ ہو رہا ہے…

3 کوششوں کے بعد حل دستیاب ہے۔

Quiz#go.m10.l4.e3
تیار

سی ایل آئی یونکس فرینڈلی میں اس کا استعمال کیا گیا ہے؟

Go
fmt.Fprintln(???, "uso: prog ...")
جواب کے اختیارات