The Go Language è un nuovo entusiasmante linguaggio che guadagna molta popolarità per una buona ragione. In questo tutorial imparerai come scrivere programmi da riga di comando con Go. Il programma di esempio è chiamato multi-git e consente di eseguire comandi git su più repository contemporaneamente.
Go è un linguaggio C-like open source creato su Google da alcuni degli hacker C e Unix originali, motivati dalla loro avversione per il C ++. Mostra nella progettazione di Go, che ha fatto diverse scelte non ortodosse come l'eliminazione dell'ereditarietà dell'implementazione, i modelli e le eccezioni. Go è semplice, affidabile ed efficiente. La sua caratteristica più distintiva è il supporto esplicito per la programmazione concorrente tramite le cosiddette goroutine e canali.
Prima di iniziare a analizzare il programma di esempio, segui la guida ufficiale per prepararti allo sviluppo di Go.
Go è un linguaggio di programmazione incredibilmente potente, impara tutto da scrivere semplici utility a costruire server web scalabili e flessibili nel nostro corso completo.
Il programma multi-git è un semplice ma utile programma Go. Se lavori su un team in cui il codebase è suddiviso su più repository git, spesso devi eseguire modifiche su più repository. Questo è un problema perché git non ha alcun concetto di repository multipli. Tutto ruota intorno a un singolo repository.
Questo diventa particolarmente fastidioso se si usano i rami. Se lavori su una funzione che tocca tre repository, dovrai creare un branch di funzionalità in ognuno di questi repository e quindi ricordarti di estrarre, tirare, spingere e unirli tutti contemporaneamente. Questo non è banale. Multi-git gestisce un insieme di repository e ti consente di operare sull'intero insieme in una sola volta. Nota che la versione corrente di multi-git richiede che tu crei i rami individualmente, ma potrei aggiungere questa funzionalità in un secondo momento.
Esplorando il modo in cui è implementato il multi-git, imparerai molto sulla scrittura di programmi da riga di comando in Go.
I programmi Go sono organizzati in pacchetti. Il programma multi-git consiste in un singolo file chiamato main.go. Nella parte superiore del file, viene specificato il nome del pacchetto 'main', seguito da un elenco di importazioni. Le importazioni sono altri pacchetti che vengono utilizzati da multi-git.
pacchetto principale import ("flag" "fmt" "log" "os" "stringhe" "os / exec")
Ad esempio, il pacchetto fmt viene utilizzato per I / O formattati simili a quelli di printf e scanf di C. Go supporta l'installazione di pacchetti da una varietà di fonti tramite il vai a prendere
comando. Quando installi i pacchetti, finiscono in uno spazio dei nomi sotto il $ GOPATH variabile d'ambiente. Puoi installare pacchetti da una varietà di fonti come GitHub, Bitbucket, codice Google, Launchpad e persino i servizi IBM DevOps tramite diversi formati di controllo delle versioni comuni come git, subversion, mercurial e bazaar.
Gli argomenti della riga di comando sono una delle forme più comuni di fornire input ai programmi. Sono facili da usare, ti permettono di eseguire e configurare il programma su un'unica riga e hanno un ottimo supporto per l'analisi in molte lingue. Go li chiama "flag" da riga di comando e ha il pacchetto flag per specificare e analizzare gli argomenti (o le bandiere) della riga di comando.
In genere, si analizzano gli argomenti della riga di comando all'inizio del programma e il multi-git segue questa convenzione. Il punto di ingresso è il principale()
funzione. Le prime due linee definiscono due flag chiamati "command" e "ignoreErrors". Ogni flag ha un nome, un tipo di dati, un valore predefinito e una stringa di aiuto. Il flag.Parse ()
call analizzerà l'effettiva riga di comando passata al programma e popolerà i flag definiti.
func main () command: = flag.String ("command", "", "Il comando git") ignoreErrors: = flag.Bool ("ignore-errors", false, "Keep running after error if true") flag .Parse ()
È anche possibile accedere agli argomenti non definiti tramite flag.Args ()
funzione. Quindi, i flag stanno per argomenti predefiniti e "args" sono argomenti non elaborati. Gli argomenti non elaborati sono indicizzati su base 0.
Un'altra forma comune di configurazione del programma è le variabili di ambiente. Quando si utilizzano variabili di ambiente, è possibile eseguire lo stesso programma più volte nello stesso ambiente e tutte le esecuzioni utilizzeranno le stesse variabili di ambiente.
Multi-git utilizza due variabili di ambiente: "MG_ROOT" e "MG_REPOS". Multi-git è progettato per gestire un gruppo di repository git che hanno una directory madre comune. Quello è "MG_ROOT". I nomi dei repository sono specificati in "MG_REPOS" come una stringa separata da virgole. Per leggere il valore di una variabile d'ambiente puoi usare il os.getenv ()
funzione.
// Ottieni repository gestiti da variabili di ambiente root: = os.Getenv ("MG_ROOT") se root [len (root) - 1]! = '/' Root + = "/" repo_names: = strings.Split (os .Getenv ("MG_REPOS"), ",")
Ora che ha trovato la directory root e i nomi di tutti i repository, multi-git verifica che ogni repository esista sotto root e che sia davvero un repository git. Il controllo è semplice come cercare una sottodirectory .git per ogni directory di repository.
Innanzitutto, viene definita una serie di stringhe denominate "repos". Quindi itera su tutti i nomi dei repository e costruisce un percorso repository concatenando la directory root e il nome del repository. Se la [Os.stat ()] ()
la chiamata non riesce per la sottodirectory .git, registra l'errore ed esce. In caso contrario, il percorso del repository viene aggiunto all'array repos.
var repos [] stringa // Verificare che esistano tutti i repository e che in realtà siano repos di git (avere sub-dir .git) per _, r: = range repo_names percorso: = root + r _, err: = os.Stat (percorso + "/.git") se err! = nil log.Fatal (err) repos = append (repos, path)
Go ha una funzione unica di gestione degli errori in cui le funzioni spesso restituiscono sia un valore di ritorno che un oggetto di errore. Scopri come os.stat ()
restituisce due valori. In questo caso, il segnaposto "_" viene utilizzato per contenere il risultato effettivo poiché si preoccupa solo dell'errore. Go è molto severo e richiede l'utilizzo di variabili denominate. Se non si prevede di utilizzare un valore, è necessario assegnarlo a "_" per evitare errori di compilazione.
A questo punto, hai l'elenco dei percorsi del repository in cui vogliamo eseguire il comando git. Come ricordi, abbiamo ricevuto la riga di comando git come un singolo argomento da riga di comando (flag) chiamato "comando". Questo deve essere suddiviso in una serie di componenti (comando git, sottocomando e opzioni). Anche l'intero comando come stringa viene memorizzato per scopi di visualizzazione.
// Spezza il comando git in componenti (necessari per l'esecuzione) var git_components [] stringa per _, componente: = range strings.Split (* command, "") git_components = append (git_components, component) command_string: = "git "comando + *
Ora, siete tutti programmati per iterare su ogni repository ed eseguire il comando git in ognuno di essi. Il costrutto del ciclo "for ... range" viene riutilizzato. Innanzitutto, multi-git cambia la sua directory di lavoro nel repository di destinazione corrente "r" e stampa il comando git. Quindi esegue il comando usando il exec.Command ()
funzione e stampa l'output combinato (sia standard output che standard error).
Infine, controlla se c'è stato un errore durante l'esecuzione. Se c'è stato un errore e il IgnoreErrors
il flag è falso, quindi il multi-git salta fuori. La ragione per ignorare facoltativamente gli errori è che a volte è OK se i comandi falliscono su alcuni repository. Ad esempio, se vuoi controllare un ramo chiamato "cool feature" su tutti i repository che hanno questo ramo, non ti interessa se il checkout fallisce su repository che non hanno questo ramo.
per _, r: = range repos // Vai alla directory del repository os.Chdir (r); // Stampa il comando fmt.Printf ("[% s]% s \ n", r, command_string) // Esegui il comando out, err: = exec.Command ("git", git_components ...) .CombinedOutput () / / Stampa il risultato fmt.Println (stringa (fuori)) // Esci da un errore se c'è un errore e NON ignori gli errori se err! = Nil &&! * IgnoreErrors os.Exit (1) fmt.Println ("Fatto . ")
Go è un linguaggio semplice ma potente. È progettato per la programmazione di sistemi su larga scala, ma funziona anche per piccoli programmi da riga di comando. Il design minimal di Go è in netto contrasto con altri linguaggi moderni come Scale e Rust che sono molto potenti e ben progettati, ma hanno una curva di apprendimento molto ripida. Ti incoraggio a provare Go e sperimentare. È molto divertente.