Tentang Perintah Go

Distribusi Go mengikutkan sebuah perintah, bernama go, yang mengotomasi pengunduhan, pembangunan, pemasangan, dan pengujian dari paket-paket dan perintah-perintah Go. Dokumen ini membahas tentang kenapa kita menulis sebuah perintah baru, bentuk perintah tersebut, apa yang tidak bisa dilakukan perintah tersebut, dan bagaimana cara menggunakannya.

Motivasi

Anda mungkin pernah melihat wicara awal tentang Go yang mana Rob Pike bercanda bahwa ide dari Go muncul saat menunggu kompilasi dari sebuah program server yang besar untuk Google. Hal ini adalah motivasi dari Go: untuk membangun sebuah bahasa pemrograman yang bekerja baik untuk membangun perangkat lunak yang besar yang dibuat dan dijalankan oleh Google. Sangat jelas dari awal bahwa bahasa tersebut harus menyediakan sebuah cara untuk mengekspresikan dependensi antara pustaka-pustaka kode secara jelas, oleh karena itu perlu adanya pengelompokan paket dan blok impor yang eksplisit. Dan juga cukup jelas dari awal bahwa Anda mungkin ingin sintaksis yang dinamis untuk mendeskripsikan kode yang sedang diimpor; inilah kenapa path impor merupakan sebuah literal string.

Tujuan eksplisit dari Go sejak mulanya adalah untuk mampu membangun kode dengan hanya menggunakan informasi yang ditemukan di dalam sumber kode itu sendiri, tidak perlu menulis sebuah makefile atau salah satu pengganti terbaru dari makefile. Jika Go membutuhkan sebuah berkas konfigurasi untuk menjelaskan bagaimana membangun sebuah program, maka Go telah gagal.

Pada awalnya, tidak ada compiler Go, dan pengembangan awal berfokus pada pembangunan compiler dan membangun pustaka-pustaka untuk digunakan. Demi kenyamanan, kami menunda otomatisasi pembangunan kode Go dengan menggunakan make dan menulis berkas makefile. Saat mengompilasi sebuah paket yang mengikutkan beragam pemanggilan compiler Go, kami bahkan menggunakan sebuah program untuk menulis makefile. Anda akan menemukan makefile tersebut jika menggali sejarah repositori Go.

Tujuan dari perintah go yang baru adalah untuk kembali ke idealisme ini; bahwa program Go seharusnya bisa di compile tanpa perlu konfigurasi atau usaha tambahan di sisi pengembang selain menulis perintah-perintah impor yang diperlukan.

Konfigurasi lawan konvensi

Salah satu cara untuk mencapai kesederhanaan dari sistem yang bebas konfigurasi yaitu membentuk konvensi. Sistem akan bekerja hanya selama konvensi-konvensi tersebut diikuti. Saat kami meluncurkan Go pertama kali, banyak orang menerbitkan paket-paket yang harus dipasang di tempat tertentu, dengan nama tertentu, menggunakan perkakas tertentu, supaya dapat digunakan. Hal ini dapat dipahami: karena begitulah cara kerja pada umumnya pada bahasa pemrograman lainnya. Selama beberapa tahun terakhir kami secara konsisten mengingatkan orang tentang perintah goinstall (sekarang diganti dengan go get) dan konvensi-konvensinya: pertama, path impor diturunkan dengan cara yang diketahui dari URL sumber kodenya; kedua, tempat penyimpanan sumber kode di dalam sistem berkas lokal diturunkan dari path impor; ketiga, setiap direktori dalam pohon berkas berkorespondensi dengan sebuah paket; dan keempat, paket dibangun hanya dari informasi dalam sumber kode. Sekarang, mayoritas paket mengikuti konvensi-konvensi ini. Hasilnya, ekosistem Go lebih sederhana dan lebih kuat.

Kami menerima banyak permintaan untuk membolehkan sebuah makefile dalam sebuah direktori paket untuk menyediakan konfigurasi tambahan selain apa yang tersedia dalam sumber kode. Namun hal ini akan menimbulkan aturan-aturan baru. Karena kami tidak mengabulkan permintaan tersebut, kami mampu menulis perintah go dan mengeliminasi penggunaan make atau sistem pembangun lainnya.

Hal yang penting untuk dipahami bahwa perintah go bukanlah perkakas pembangun yang umum. Ia tidak bisa dikonfigurasi dan ia tidak membuat apa pun kecuali paket-paket Go. Hal-hal ini adalah asumsi-asumsi penyederhanaan yang penting: ia menyederhanakan tidak hanya implementasi namun juga, lebih penting lagi, penggunaan dari perkakas itu sendiri.

Konvensi dari Go

Perintah go membutuhkan kode yang mematuhi beberapa konvensi-konvensi penting yang telah terbentuk.

Pertama, path impor diturunkan dari URL sumber kode. Untuk Bitbucket, Github, Google Code, dan Launchpad, direktori utama dari repositori diidentifikasi oleh URL repositori, tanpa prefiks "http://". Sub-sub direktori diberi nama sesuai dengan path. Sebagai contohnya, contoh program Go dapat diambil dengan menjalankan

git clone https://github.com/golang/example

maka path impor dari direktori utama dari repositori itu adalah "github.com/golang/example". Paket stringutil di simpan dalam sebuah sub direktori, sehingga path impornya adalah "github.com/golang/example/stringutil".

Path-path ini cukup panjang, namun kita mendapatkan nama yang secara otomatis teratur secara path impor dan kemampuan bagi perkakas seperti perintah go untuk mencari path impor yang tidak biasa dan memproses di mana mendapatkan sumber kodenya.

Kedua, tempat menyimpan sumber kode dalam sistem berkas lokal diturunkan dengan cara tertentu dari path impor, khususnya $GOPATH/src/<import-path>. Jika tidak diset, $GOPATH secara bawaan diset ke subdirektori bernama go di dalam home direktori dari user. Jika $GOPATH diset ke beberapa path, perintah go akan mencoba <dir>/src/<import-path> untuk setiap direktori dalam daftar tersebut.

Setiap path tersebut mengandung, secara konvensi, sebuah direktori bernama "bin", untuk menyimpan hasil kompilasi yang bisa dieksekusi, dan sebuah direktori bernama "pkg", untuk menyimpan paket-paket yang telah dikompilasi sehingga dapat diimpor, dan direktori "src", untuk menyimpan berkas-berkas sumber paket. Dengan menggunakan struktur seperti ini membolehkan kita menjaga setiap pohon direktori tersebut mandiri: hasil kompilasi dan sumber kode selalu saling berdekatan satu sama lain.

Konvensi penamaan ini juga membolehkan kita bekerja dengan arah berlawanan, dari sebuah nama direktori ke path impornya. Pemetaan ini sangat penting bagi banyak sub perintah go, seperti yang akan kita bahas nanti.

Ketiga, setiap direktori dalam struktur pohon sumber berkorespondensi dengan sebuah paket. Dengan membatasi sebuah direktori dengan sebuah paket, kita tidak perlu membuat path impor yang bercampuran yang menspesifikasikan direktori dahulu dan paket dalam direktori. Kebanyakan perkakas manajemen berkas menggunakan direktori sebagai unit-unit dasar. Dengan mengikat unit fundamental Go -- paket -- ke struktur sistem berkas berarti perkakas sistem berkas menjadi perkakas paket Go. Menyalin, memindahkan, atau menghapus sebuah paket berkorespondensi dengan menyalin, memindahkan, atau menghapus sebuah direktori.

Keempat, setiap paket dibangun menggunakan hanya informasi yang tersedia di dalam berkas-berkas sumber. Hal ini membuat perkakas lebih mudah beradaptasi terhadap perubahan kondisi dan lingkungan pembuatan. Sebagai contohnya, jika kita membolehkan konfigurasi tambahan seperti flag-flag compiler atau resep baris perintah, maka konfigurasi tersebut perlu dibuah setiap kali perkakas pembangun berubah; ia juga secara tidak langsung tergantung pada penggunaan toolchain yang khusus.

Belajar menggunakan perintah go

Terakhir, tur singkat tentang bagaimana menggunakan perintah go. Seperti yang telah dijelaskan di atas, nilai standar dari $GOPATH pada Unix adalah $HOME/go. Kita akan menyimpan program kita di sana. Untuk menggunakan lokasi yang berbeda anda dapat menset $GOPATH; Cara Menulis Kode Go untuk lebih jelasnya.

Pertama kita tambahkan beberapa sumber kode. Misalnya kita ingin menggunakan pustaka pengindeksan dari proyek codesearch bersamaan dengan pustaka red-black tree. Kita dapat memasang keduanya dengan sub perintah "go get":

$ go get github.com/google/codesearch/index
$ go get github.com/petar/GoLLRB/llrb
$

Kedua proyek tersebut sekarang telah diunduh dan dipasang ke dalam $HOME/go, yang berisi dua direktori src/github.com/google/codesearch/index dan src/github.com/petar/GoLLRB/llrb/, bersama dengan paket-paket yang telah dikompilasi (dalam pkg/) untuk kedua pustaka dan dependensinya.

Karena kita menggunakan sistem kontrol versi (Mercurial dan Git) untuk mengambil sumber, maka sumber kode juga berisi berkas-berkas lain dalam repositori-repositori tersebut. Sub perintah "go list" menampilkan path impor yang berkorespondensi dengan argumennya, and pola "./…​" berarti mulai dari direktori sekarang ("./") dan cari semua paket di bawah direktori tersebut ("…​"):

$ cd $HOME/go/src
$ go list ./...
github.com/google/codesearch/cmd/cgrep
github.com/google/codesearch/cmd/cindex
github.com/google/codesearch/cmd/csearch
github.com/google/codesearch/index
github.com/google/codesearch/regexp
github.com/google/codesearch/sparse
github.com/petar/GoLLRB/example
github.com/petar/GoLLRB/llrb
$

Kita juga bisa menguji paket-paket tersebut:

$ go test ./...
?   	github.com/google/codesearch/cmd/cgrep	[no test files]
?   	github.com/google/codesearch/cmd/cindex	[no test files]
?   	github.com/google/codesearch/cmd/csearch	[no test files]
ok  	github.com/google/codesearch/index	0.203s
ok  	github.com/google/codesearch/regexp	0.017s
?   	github.com/google/codesearch/sparse	[no test files]
?       github.com/petar/GoLLRB/example          [no test files]
ok      github.com/petar/GoLLRB/llrb             0.231s
$

Jika sebuah sub perintah go dipanggil tanpa path, ia beroperasi pada direktori sekarang:

$ cd github.com/google/codesearch/regexp
$ go list
github.com/google/codesearch/regexp
$ go test -v
=== RUN   TestNstateEnc
--- PASS: TestNstateEnc (0.00s)
=== RUN   TestMatch
--- PASS: TestMatch (0.00s)
=== RUN   TestGrep
--- PASS: TestGrep (0.00s)
PASS
ok  	github.com/google/codesearch/regexp	0.018s
$ go install
$

Sub perintah "go install" memasang salinan terbaru dari paket ke dalam direktori pkg/. Karena perintah go dapat menganalisis grafik dependensi, "go install" juga memasang semua paket-paket yang diimpor oleh paket yang telah usang, secara rekursif.

Perhatikan bahwa "go install" bisa menentukan nama path impor dari paket dalam direktori yang sekarang, karena konvensi dari penamaan direktori. Akan lebih mudah bila kita dapat mengambil nama direktori tempat kita menyimpan sumber kode, dan mungkin kita tidak perlu nama yang panjang, namun kemampuan tersebut akan membutuhkan konfigurasi dan kompleksitas tambahan bagi perkakas. Menulis satu atau dua buah nama direktori adalah harga yang harus dibayar demi meningkatkan kesederhanaan dan kekuatan.

Batasan

Seperti yang telah disebutkan juga di atas, perintah go bukanlah perkakas pembangun yang umum. Ia tidak memiliki fasilitas untuk menghasilkan berkas sumber Go selama pembangunan, walaupun ia menyediakan go generate, yang dapat mengotomasi pembuatan berkas Go sebelum dibangun. Untuk pembangunan lebih lanjut, Anda mungkin perlu menulis sebuah makefile (atau berkas konfigurasi untuk perkakas pembangun yang Anda pilih) untuk menjalankan perkakas apa pun yang membuat berkas-berkas Go dan mengambil berkas-berkas tersebut ke dalam repositori Anda. Hal ini berarti lebih banyak kerja bagi Anda, penulis paket, namun secara signifikan sedikit kerja bagi pengguna paket Anda, yang dapat menggunakan "go get" tanpa perlu mendapatkan dan membangun perkakas tambahan.

Informasi lebih lanjut

Untuk informasi lebih lanjut, baca Cara Menulis Kode Go dan lihat perintah go.