Mengelola Paket dengan Modul Go: A Pragmatic Guide

Halo semuanya. Untuk mengantisipasi dimulainya kursus Pengembang Golang, kami telah menyiapkan terjemahan lain yang menarik untuk Anda.



Modul adalah cara untuk menangani dependensi di Go. Awalnya disajikan sebagai percobaan, modul seharusnya diperkenalkan ke lapangan sebagai standar baru untuk mengelola paket dari versi 1.13.

Saya menemukan topik ini cukup tidak biasa bagi pemula yang berasal dari bahasa lain, jadi saya memutuskan untuk mengumpulkan beberapa pemikiran dan tips di sini untuk membantu orang lain seperti saya mendapatkan ide manajemen paket di Go. Kami akan mulai dengan pengenalan umum, dan kemudian beralih ke aspek yang kurang jelas, termasuk menggunakan folder vendor, menggunakan modul dengan Docker dalam pengembangan, dependensi alat, dll.

Jika Anda sudah terbiasa dengan modul Go dan mengetahui Wiki, seperti punggung tangan Anda, artikel ini mungkin tidak akan sangat membantu Anda. Tetapi untuk sisanya, bagaimanapun, ini dapat menghemat beberapa jam coba-coba.

Jadi, jika Anda sedang dalam perjalanan, melompatlah dan nikmati perjalanannya.



Mulai cepat


Jika kontrol versi sudah terintegrasi dalam proyek Anda, Anda bisa menjalankannya

go mod init

Atau tentukan jalur ke modul secara manual. Ini adalah sesuatu seperti nama, URL, dan jalur impor untuk paket Anda:

go mod init github.com/you/hello

Ini akan membuat file go.mod, yang juga mendefinisikan persyaratan dan lochit proyek tergantung pada versi yang benar (sebagai analogi untuk Anda, seperti package.json, dan package-lock.jsondigabungkan menjadi satu file):

module github.com/you/hello
go 1.12

Jalankan go getuntuk menambahkan dependensi baru ke proyek Anda:

Perhatikan bahwa meskipun Anda tidak dapat menentukan rentang versi dengan get get, apa yang Anda tetapkan di sini bukanlah versi spesifik, tetapi versi minimum. Seperti yang akan kita lihat nanti, ada cara untuk memperbarui dependensi dengan anggun menurut semver.

# use Git tags
go get github.com/go-chi/chi@v4.0.1
# or Git branch name
go get github.com/go-chi/chi@master
# or Git commit hash
go get github.com/go-chi/chi@08c92af

Sekarang file kami adalah go.modsebagai berikut:

module github.com/you/hello
go 1.12
require github.com/go-chi/chi v4.0.2+incompatible // indirect

Sufiks +incompatibleditambahkan ke semua paket yang belum dikonfigurasi untuk modul Go atau melanggar aturan kontrol versinya.

Karena kami belum mengimpor paket ini di mana pun di proyek kami, itu ditandai sebagai // indirect. Kita dapat merapikan ini dengan perintah berikut:

go mod tidy

Bergantung pada kondisi repositori Anda saat ini, ia akan menghapus modul yang tidak digunakan atau menghapus komentar // indirect.

Jika ada dependensi dengan sendirinya tidak memiliki go.mod(misalnya, itu belum dikonfigurasi untuk modul), maka semua dependensinya akan ditulis ke file induk go.mod(sebagai opsi, file Anda go.mod)bersama dengan komentar // indirectuntuk menunjukkan bahwa mereka bukan dari impor langsung Dalam

rencana global Anda , tujuannya go mod tidyadalah untuk menambahkan dependensi yang diperlukan untuk kombinasi OS, arsitektur, dan tag build lainnya. Pastikan untuk menjalankannya sebelum setiap rilis.

Pastikan juga file dibuat setelah menambahkan dependensigo.sum. Anda mungkin berpikir bahwa ini adalah file kunci. Tetapi sebenarnya itu go.modsudah memberikan informasi yang cukup untuk membangun 100% direproduksi. File go.sumini dibuat untuk keperluan verifikasi: itu berisi checksum kriptografi yang diharapkan dari isi masing-masing versi modul.

Sebagian karena ini go.sumbukan file kunci, ini menyimpan checksum tertulis untuk versi modul bahkan setelah Anda berhenti menggunakan modul ini. Ini memungkinkan Anda untuk memeriksa checksum jika Anda melanjutkan menggunakannya nanti, yang menyediakan keamanan tambahan.


Mkcert baru saja bermigrasi ke modul (dengan vendor / untuk kompatibilitas mundur) dan semuanya berjalan lancar
https://github.com/FiloSottile/mkcert/commit/26ac5f35395fb9cba3805faf1a5a04d260271291

$ GO111MODULE=on go1.11rc1 mod init
$ GO111MODULE=on go1.11rc1 mod vendor
$ git add go.mod go.sum vendor
$ git rm Gopkg.lock Gopkg.toml Makefile



FAQ: Haruskah saya komit go.sumdi git?
A: Jelas ya. Dengan itu, pemilik sumber Anda tidak perlu mempercayai repositori GitHub lain dan pemilik jalur impor khusus. Sudah dalam perjalanan ke kami, sesuatu yang lebih baik, tetapi untuk sekarang ini adalah model yang sama dengan hash dalam file kunci.

Perintah go builddan go testakan secara otomatis memuat semua dependensi yang hilang, meskipun Anda dapat melakukan ini secara eksplisit dengan bantuan go mod downloadcache lokal pra-populasi yang mungkin berguna untuk CI.

Secara default, semua paket kami dari semua proyek dimuat ke direktori $GOPATH/pkg/mod. Kami akan membahas ini secara lebih rinci nanti.

Memutakhirkan Versi Paket


Anda dapat menggunakan go get -umasing go get -u=patch- masing untuk memperbarui dependensi ke versi minor terbaru atau tambalan.

Tetapi Anda tidak dapat memutakhirkan ke versi utama seperti itu. Kode yang termasuk dalam modul Go harus secara teknis mematuhi aturan berikut:

  • Cocokkan semver (contoh tag VCS v1.2.3).
  • Jika modul adalah versi v2 atau lebih tinggi, versi utama modul harus dimasukkan /vNdi akhir lintasan modul yang digunakan dalam file go.moddan di lintasan impor paket:

import "github.com/you/hello/v2"

Rupanya, ini dilakukan agar berbagai versi paket dapat diimpor dalam satu rakitan (lihat masalah ketergantungan berlian ).

Singkatnya, Go mengharapkan Anda untuk sangat berhati-hati saat memperkenalkan versi utama.

Mengganti modul yang diimpor


Anda dapat menentukan modul yang diperlukan untuk garpu Anda sendiri atau bahkan jalur lokal ke file menggunakan arahan replace:

go mod edit -replace github.com/go-chi/chi=./packages/chi

Hasil:

module github.com/you/hello
go 1.12
require github.com/go-chi/chi v4.0.2+incompatible
replace github.com/go-chi/chi => ./packages/chi

Anda dapat menghapus garis secara manual atau menjalankan:

go mod edit -dropreplace github.com/go-chi/chi

Manajemen Ketergantungan Proyek


Secara historis, semua kode Go disimpan dalam satu mono-repositori raksasa, karena itulah cara Google mengatur basis kodenya, dan ini memengaruhi desain bahasa.

Modul Go adalah titik berangkat dari pendekatan ini. Anda tidak perlu lagi menyimpan semua proyek Anda $GOPATH.

Namun, secara teknis semua dependensi yang Anda unduh masih ditempatkan $GOPATH/pkg/mod. Jika Anda menggunakan wadah Docker untuk pengembangan lokal, ini bisa menjadi masalah, karena dependensi disimpan di luar proyek. Secara default, mereka tidak terlihat di IDE Anda.



Ini biasanya bukan masalah untuk bahasa lain, tapi inilah yang pertama kali saya temui ketika bekerja dengan basis kode Go.

Untungnya, ada beberapa cara (tidak berdokumen) untuk menyelesaikan masalah ini.

Opsi 1. Instal GOPATH di dalam direktori proyek Anda.


Pada pandangan pertama, ini mungkin tampak berlawanan dengan intuisi, tetapi jika Anda menjalankan Go from a container , Anda dapat mengesampingkan GOPATH sehingga menunjuk ke direktori proyek sehingga paket-paket dapat diakses dari host:

version: '3.7'

services:
  app:
    command: tail -f /dev/null
    image: golang:1.12.6-stretch
    environment:
      #        - /code/.go/pkg/mod
      - GOPATH=/code/.go
    ports:
      - 8000:8000
    volumes:
      - ./:/code:cached
    working_dir: /code

IDE populer harus dapat menginstal GOPATH di tingkat proyek (ruang kerja):



Satu-satunya kelemahan dari pendekatan ini adalah kurangnya interaksi dengan runtime Go pada komputer host. Anda harus menjalankan semua perintah Go di dalam wadah.

Opsi 2: Penjual Otomatis Ketergantungan Anda


Cara lain adalah dengan menyalin dependensi proyek Anda ke folder vendor:

go mod vendor

Ini harus segera dicatat: kami TIDAK mengizinkan Pergi untuk langsung mengunggah materi ke folder vendor: ini tidak mungkin dengan modul. Kami cukup menyalin paket yang sudah diunduh.

Selain itu, jika Anda melepaskan dependensi Anda, seperti dalam contoh di atas, lalu hapus $GOPATH/pkg/modlalu coba tambahkan beberapa dependensi baru ke proyek Anda, Anda akan melihat yang berikut:

  1. Go akan membangun kembali cache unduhan untuk semua paket perangkat lunak $GOPATH/pkg/mod/cache.
  2. Semua modul yang dimuat akan disalin ke $GOPATH/pkg/mod.
  3. Dan akhirnya, Go akan menyalin modul-modul ini ke vendorfolder, menghapus contoh, tes, dan beberapa file lain yang tidak Anda andalkan secara langsung.

Selain itu, ada banyak hal yang hilang di folder vendor yang baru dibuat ini:



File penulisan Docker khas terlihat seperti ini (perhatikan binding volume):

version: '3.7'

services:
  app:
    command: tail -f /dev/null
    image: golang:1.12.6-stretch
    ports:
      - 8000:8000
    volumes:
     #    go,           
      - modules:/go/pkg/mod/cache
      - ./:/code:cached
    working_dir: /code 

volumes:
  modules:
    driver: local

Harap dicatat bahwa saya TIDAK komik folder vendor ini dalam sistem kontrol versi atau saya tidak akan menggunakannya dalam produksi. Ini adalah skrip pengembangan yang sepenuhnya lokal, yang biasanya dapat ditemukan dalam beberapa bahasa lain.

Namun, ketika saya membaca komentar dari beberapa pengelola Go dan beberapa penawaran terkait dengan vending parsial (?), Saya mendapat kesan bahwa fitur ini pada awalnya dimaksudkan bukan untuk kasus pengguna ini.

Salah satu komentator di reddit membantu saya menjelaskan hal ini:

Biasanya orang-orang menjual dependensi mereka untuk alasan-alasan seperti keinginan untuk memiliki perangkat ketat tanpa akses ke jaringan, serta salinan dependensi siap pakai jika terjadi kegagalan github atau menghilangnya repositori, dan kemungkinan audit yang lebih mudah terhadap perubahan dependensi menggunakan alat VCS standar, dll. .

Ya, itu tidak terlihat seperti sesuatu dari kenyataan bahwa aku mungkin akan tertarik.

Menurut perintah Go, Anda dapat dengan mudah mengaktifkan vending dengan mengatur variabel lingkungan GOFLAGS=-mod=vendor. Saya tidak merekomendasikan melakukan ini. Menggunakan flag hanya akan pecah go gettanpa memberikan manfaat lain untuk alur kerja harian Anda:



Faktanya, satu-satunya tempat yang Anda butuhkan untuk mengaktifkan vending adalah IDE Anda:



Setelah beberapa percobaan dan kesalahan, saya datang dengan prosedur berikut untuk menambahkan dependensi vendor dalam pendekatan ini.

Langkah 1. Persyaratan


Anda dapat memerlukan ketergantungan dengan go get:

go get github.com/rs/zerolog@v1.14.3

Langkah 2. Impor


Kemudian impor di suatu tempat di kode Anda:

import (
   _ "github.com/rs/zerolog"
)

Langkah 3. Penjual


Terakhir, buka kembali dependensi Anda:

go mod vendor

Ada proposal yang tertunda untuk memungkinkan vendor mod untuk menerima templat modul tertentu yang mungkin (atau mungkin tidak) menyelesaikan beberapa masalah yang terkait dengan alur kerja ini.

go mod vendorsudah secara otomatis membutuhkan impor yang terlewat, jadi langkah 1 adalah opsional dalam alur kerja ini (jika Anda tidak ingin menentukan batasan versi). Namun, tanpa langkah 2, itu tidak akan mengambil paket yang diunduh.

Pendekatan ini berfungsi lebih baik dengan sistem host, tetapi agak membingungkan ketika harus mengedit dependensi Anda.



Secara pribadi, saya pikir mendefinisikan ulang GOPATH adalah pendekatan yang lebih bersih karena tidak mengorbankan fungsionalitas go get. Namun demikian, saya ingin menunjukkan kedua strategi tersebut, karena folder vendor mungkin lebih akrab bagi orang-orang yang berasal dari bahasa lain, seperti PHP, Ruby, Javascript, dll. Seperti yang dapat Anda lihat dari penipuan yang dijelaskan dalam artikel ini, ini bukan pilihan yang sangat baik untuk Go.

Ketergantungan alat


Kita mungkin perlu menginstal beberapa alat berbasis-Go yang tidak diimpor, tetapi digunakan sebagai bagian dari lingkungan pengembangan proyek. Contoh sederhana dari alat tersebut adalah CompileDaemon , yang dapat memonitor kode Anda untuk perubahan dan memulai kembali aplikasi Anda. Pendekatan yang

direkomendasikan secara resmi adalah menambahkan tools.gofile (nama tidak masalah) dengan konten berikut:

// +build tools
package tools
import (
_ "github.com/githubnemo/CompileDaemon"
)

  • Batasan // +build toolsmencegah majelis reguler Anda dari benar-benar mengimpor alat Anda.
  • Ekspresi impor memungkinkan perintah go untuk secara akurat menulis informasi versi alat go.modAnda ke file modul Anda.

Jadi itu saja. Saya harap Anda tidak akan bingung seperti ketika saya mulai menggunakan modul Go. Anda dapat mengunjungi wiki Go Modul untuk lebih jelasnya.



Ikuti saja.



All Articles