మాడ్యూల్ పాఠాలు (4/5)
మినీ-ప్రాజెక్ట్: ఫ్లాగ్లతో కూడిన CLI
ఒక చిన్న ఇడియోమాటిక్ CLIని రూపొందించడానికి మునుపటి మాడ్యూల్ల బిల్డింగ్ బ్లాక్లను కలిపి ఉంచుదాం: flag ప్యాకేజీతో ఫ్లాగ్ పార్సింగ్, స్థాన ఆర్గ్యుమెంట్లను నిర్వహించడం, os.Stderrలో లోపాలు మరియు కుడి నిష్క్రమణ కోడ్.
flag ప్యాకేజీ
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, _AGYTOK_INLINE_INLINEflag.Parse()విలువలను చదవడానికి ముందు మరియుflag.Args()కి ముందు తప్పనిసరిగా ఒకసారి కాల్ చేయాలి.flag.Args()స్థాన ఆర్గ్యుమెంట్లను (--తర్వాత లేదా చివరి ఫ్లాగ్ తర్వాత) అందిస్తుంది.- ఆమోదించబడిన ఫారమ్లు:
-n 3,-n=3,--n=3. బూలియన్లు:-u(నిజం),-u=false.
సాంప్రదాయ నిష్క్రమణ కోడ్లు
os.Exit(0) // success
os.Exit(1) // generic error
os.Exit(2) // usage error (incorrect flag usage)షెల్లు మరియు స్క్రిప్ట్లు ఈ కోడ్లను ఆశించాయి: వాటిని స్థిరంగా ఉపయోగించండి. ఎప్పటికీ os.Exitతో నాన్-మెయిన్ గోరౌటిన్ నుండి నిష్క్రమించండి: ఇది log ఫ్లషింగ్తో సహా ప్రతి deferని దాటవేస్తుంది.
Stderr vs Stdout
పాత మరియు పవిత్రమైన Unix నియమం:
os.Stdout→ ఉపయోగకరమైన అవుట్పుట్, పైపు సామర్థ్యం (cli | grep ...).os.Stderr→ విశ్లేషణలు, లోపాలు, పురోగతి పట్టీలు, వినియోగం.
fmt.Println("result: 42") // stdout
fmt.Fprintln(os.Stderr, "error: ...") // stderrఈ విధంగా cli 2>/dev/null ఫలితాలను మాత్రమే చూపుతుంది, cli >out.txt ఫలితాన్ని మాత్రమే దారి మళ్లిస్తుంది మరియు లోపాలు కనిపిస్తాయి.
log vs fmt
fmtవినియోగదారు అవుట్పుట్ కోసం.logడయాగ్నస్టిక్స్ కోసం: టైమ్స్టాంప్ని జోడిస్తుంది, డిఫాల్ట్గాos.Stderrకి వ్రాస్తుంది,log.Fatal(లాగ్లు +os.Exit(1)) మరియు AGYTOK_34INLINEINLINE
log.SetFlags(log.LstdFlags | log.Lshortfile) // timestamp + file:line
log.Fatal("boom") // prints and exits with 1ఆధునిక యాప్ల కోసం (1.21+ వెళ్లండి) నిర్మాణాత్మక లాగింగ్ కోసం **log/slog**ని ఉపయోగించండి (JSON లేదా టెక్స్ట్, లెవెల్లు, టైప్ చేసిన ఫీల్డ్లు).
ఆర్కిటెక్చర్: లాజిక్ నుండి mainని వేరు చేయండి
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 + డెలిగేట్లను సిద్ధం చేస్తుంది.
ఉపకమాండ్లు
సబ్కమాండ్లతో కూడిన CLIల కోసం (mycli serve, mycli migrate), బాహ్య డిపెండెన్సీలు లేని పథకం:
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 వంటి లైబ్రరీలు ఈ పథకాన్ని స్వయంచాలకంగా రూపొందించిన సహాయంతో రూపొందించాయి.
వ్యాయామాలు
Definisci il flag -n di tipo int con valore di default 1 e descrizione 'ripetizioni', Poi chiama flag.Parse() e Stampa il valore.
3 ప్రయత్నాల తర్వాత పరిష్కారం లభిస్తుంది
Se non c'è almeno un argomento posizionale dopo flag.parse, stamp 'manca argomento' su Stderr e termina con os.Exit(1).
3 ప్రయత్నాల తర్వాత పరిష్కారం లభిస్తుంది
CLI యూనిక్స్-ఫ్రెండ్లీలో క్వలే స్ట్రీమ్ స్టాంపి మెస్సాగి డి తప్పు మరియు యూసేజ్?
fmt.Fprintln(???, "uso: prog ...")