| Blog |

Free PNGs

Go modullariga kirish

Tarjima qilingan maqola - Introduction to Go Modules

Muallif(lar) - Roberto Selbach

Maqolaning manbasi:

https://roberto.selbach.ca/intro-to-go-modules/

Go dasturlash tilining yaqinlashib kelayotgan 1.11 versiyasi  modullarni eksperimental qo'llab-quvvatlaydi , Go uchun yangi qaramlikni boshqarish tizimi. Bir necha kun oldin men bu haqda tezkor post yozdim. Ushbu post jonli efirga chiqqani sababli, vaziyat biroz o'zgardi va biz yangi nashrga juda yaqin bo'lganimiz sababli, men ko'proq amaliy yondashuvga ega bo'lgan boshqa post uchun yaxshi vaqt deb o'yladim. Shunday qilib, biz nima qilamiz: biz yangi paket yaratamiz va keyin bu qanday ishlashini ko'rish uchun bir nechta nashrlarni chiqaramiz.

Modul yaratish

Shunday qilib, birinchi narsa. Keling, paketimizni yarataylik. Biz buni “testmod” deb ataymiz. Bu erda muhim tafsilot: bu katalog $GOPATH dan tashqarida bo'lishi kerak, chunki sukut bo'yicha uning ichida modullarni qo'llab-quvvatlash o'chirib qo'yilgan. Go modullari bir nuqtada butunlay $GOPATH yo'q qilishning birinchi qadamidir.

$ mkdir testmod 
$ cd testmod

Bizning paketimiz juda oddiy:

package testmod

import "fmt" 

// Hi returns a friendly greeting
func Hi(name string) string {
   return fmt.Sprintf("Hi, %s", name)
}

Paket bajarildi, lekin u hali ham modul emas. Keling, buni o'zgartiraylik.

$ go mod init github.com/robteix/testmod
go: creating new go.mod: module github.com/robteix/testmod

go.mod Bu quyidagi tarkibga ega bo'lgan paketlar katalogida nomlangan yangi faylni yaratadi :

module github.com/robteix/testmod

Bu erda unchalik ko'p emas, lekin bu bizning paketimizni modulga samarali aylantiradi. Endi biz ushbu kodni omborga surishimiz mumkin:

$ git init 
$ git add * 
$ git commit -am "First commit" 
$ git push -u origin master

Hozirgacha ushbu paketdan foydalanishni istagan har bir kishi go get:

$ go get github.com/robteix/testmod

Va bu so'nggi kodni oladi master. Bu hali ham ishlaydi, lekin bizda Better Way™ mavjud bo'lganidan keyin buni to'xtatishimiz kerak. Yuklab olish o‘z mohiyatiga master ko‘ra xavflidir, chunki paket mualliflari foydalanishimizni buzadigan o‘zgartirishlar kiritmaganligini hech qachon aniq bilmaymiz. Modullar buni tuzatishga qaratilgan.

Modul versiyasiga tezkor kirish

Go modullari  versiyalashtirilgan va ma'lum versiyalarga nisbatan ba'zi xususiyatlar mavjud. Semantik versiyalash ortidagi tushunchalar bilan tanishishingiz kerak bo'ladi .

Eng muhimi, Go versiyalarni qidirishda ombor teglaridan foydalanadi va ba'zi versiyalar boshqalardan farq qiladi: masalan, 2 va undan yuqori versiyalar 0 va 1 versiyalarga qaraganda boshqa import yo'liga ega bo'lishi kerak (biz bunga erishamiz.) Shuningdek, sukut bo'yicha Go omborda mavjud bo'lgan eng so'nggi teglangan versiyani oladi. Bu muhim narsa, chunki siz asosiy filial bilan ishlashga odatlangan bo'lishingiz mumkin. Hozir yodda tutishingiz kerak bo'lgan narsa shuki, paketimizni chiqarish uchun biz o'z omborimizni versiya bilan belgilashimiz kerak. Shunday qilib, buni qilaylik.

Bizning birinchi nashrimiz

Endi paketimiz tayyor, biz uni dunyoga chiqarishimiz mumkin. Buni versiya teglari yordamida qilamiz. Keling, 1.0.0 versiyamizni chiqaraylik:

$ git tag v1.0.0
$ git push --tags

Bu mening Github omborimda 1.0.0 versiyasi sifatida joriy majburiyatni belgilovchi teg yaratadi.

Go buni hech qanday tarzda tatbiq etmaydi, lekin xatoliklar tuzatilishi uchun yangi filial (“v1”) yaratish ham yaxshi fikrdir.

$ git checkout -b v1
$ git push -u origin v1

Endi biz master relizimizni buzish haqida tashvishlanmasdan ishlashimiz mumkin.

Bizning modulimizdan foydalanish

Endi biz moduldan foydalanishga tayyormiz. Biz yangi paketimizdan foydalanadigan oddiy dastur yaratamiz:

package main

import (
     "fmt"

     "github.com/robteix/testmod"
)

func main() {
     fmt.Println(testmod.Hi("roberto"))
}

Hozirgacha siz go get github.com/robteix/testmod paketni yuklab olish uchun qilgan edingiz, ammo modullar bilan bu yanada qiziqarli bo'ladi. Avval yangi dasturimizda modullarni yoqishimiz kerak.

$ go mod init mod

Yuqorida ko'rganimizdan kutganingizdek, bu go.mod modul nomi bilan yangi faylni yaratadi:

module mod

Yangi dasturimizni yaratishga harakat qilganimizda, narsalar yanada qiziqarli bo'ladi:

$ go build
go: finding github.com/robteix/testmod v1.0.0
go: downloading github.com/robteix/testmod v1.0.0

Ko'rib turganimizdek, go buyruq avtomatik ravishda ketadi va dastur tomonidan import qilingan paketlarni oladi. Agar biz faylimizni tekshirsak go.mod, narsalar o'zgarganini ko'ramiz:

module mod
require github.com/robteix/testmod v1.0.0

Endi bizda go.sumtoʻgʻri versiya va fayllar mavjudligini taʼminlash uchun paketlar xeshlarini oʻz ichiga olgan yangi fayl ham bor.

github.com/robteix/testmod v1.0.0 h1:9EdH0EArQ/rkpss9Tj8gUnwx3w5p0jkzJrd5tRAhxnA=
github.com/robteix/testmod v1.0.0/go.mod h1:UVhi5McON9ZLc5kl5iN2bTXlL6ylcxE9VInV71RrlO8=

Xatolarni tuzatish versiyasi yaratilmoqda

Aytaylik, paketimiz bilan bog'liq muammoni tushundik: salomlashishda ponktuatsiya yo'q! Odamlar aqldan ozgan, chunki bizning do'stona salomlashishimiz etarli darajada do'stona emas. Shunday qilib, biz uni tuzatamiz va yangi versiyani chiqaramiz:

// Hi returns a friendly greeting
func Hi(name string) string {
-       return fmt.Sprintf("Hi, %s", name)
+       return fmt.Sprintf("Hi, %s!", name)
}

Biz bu o‘zgarishlarni v1 bo‘limida qildik, chunki bu v2 uchun keyinroq qiladigan ishimizga taalluqli emas, lekin real hayotda, ehtimol siz buni o‘zingizga kiritib, master keyin uni qayta portga o‘tkazgan bo‘lardingiz. Qanday bo'lmasin, biz v1 filialimizda tuzatishga ega bo'lishimiz va uni yangi versiya sifatida belgilashimiz kerak.

$ git commit -m "Emphasize our friendliness" testmod.go
$ git tag v1.0.1
$ git push --tags origin v1

Modullarni yangilash

Odatiy bo'lib, Go modullarni so'ramasdan yangilamaydi. Bu yaxshi narsa ™, chunki biz tuzilmalarimizda oldindan aytib bo'lishni xohlaymiz. Agar Go modullari har safar yangi versiya chiqqanda avtomatik ravishda yangilansa, biz Go1.11 dan oldingi madaniyatsiz davrga qaytamiz. Yo'q, biz  modullarni yangilash uchun Go'ga aytishimiz kerak.

Biz buni eski do'stimiz yordamida qilamiz go get:

Yuqoridagi roʻyxatda eng soʻnggi  asosiy versiyaga yangilashning hech qanday usuli yoʻqdek. Buning yaxshi sababi bor, buni birozdan keyin ko'rib chiqamiz.

Dasturimiz paketimizning 1.0.0 versiyasidan foydalanganligi va biz hozirgina 1.0.1 versiyasini yaratganimiz  sababli , quyidagi buyruqlardan biri bizni 1.0.1 ga yangilaydi:

$ go get -u
$ go get -u=patch
$ go get github.com/robteix/testmod@v1.0.1

Yugurishdan so'ng, aytaylik, go get -u bizning holatimiz go.mod quyidagicha o'zgaradi:

module mod
require github.com/robteix/testmod v1.0.1

Asosiy versiyalar

Semantik versiya semantikasiga ko'ra, asosiy versiya  kichiklardan farq qiladi . Asosiy versiyalar orqaga qarab muvofiqlikni buzishi mumkin. Go modullari nuqtai nazaridan, asosiy versiya  butunlay boshqa paketdir . Avvaliga bu g'alati tuyulishi mumkin, ammo bu mantiqiy: kutubxonaning bir-biriga mos kelmaydigan ikkita versiyasi ikki xil kutubxonadir.

Keling, paketimizga katta o'zgartirish kiritaylik, shundaymi? Vaqt oʻtishi bilan biz API’miz juda sodda va foydalanuvchilarimiz foydalanish holatlari uchun juda cheklanganligini angladik, shuning Hi() uchun salomlashish tili uchun yangi parametr olish funksiyasini oʻzgartirishimiz kerak:

package testmod

import (
     "errors"
     "fmt" 
) 

// Hi returns a friendly greeting in language lang
func Hi(name, lang string) (string, error) {
     switch lang {
     case "en":
         return fmt.Sprintf("Hi, %s!", name), nil
     case "pt":
         return fmt.Sprintf("Oi, %s!", name), nil
     case "es":
         return fmt.Sprintf("¡Hola, %s!", name), nil
     case "fr":
         return fmt.Sprintf("Bonjour, %s!", name), nil
     default:
         return "", errors.New("unknown language")
     }
}

Bizning API-dan foydalanadigan mavjud dasturiy ta'minot buziladi, chunki ular (a) til parametrini o'tkazmaydi va (b) xato qaytarilishini kutmaydi. Bizning yangi API endi 1.x versiyasiga mos kelmaydi, shuning uchun versiyani 2.0.0 ga oshirish vaqti keldi.

Men ilgari aytib o'tganman, ba'zi versiyalarning o'ziga xos xususiyatlari bor va hozir ham shunday. 2 va undan yuqori versiyalar import yo'lini o'zgartirishi kerak. Ular endi turli kutubxonalar.

Biz buni  modul nomining oxiriga yangi versiya yo'lini qo'shish orqali qilamiz.

module github.com/robteix/testmod/v2

Qolganlari avvalgidek, biz uni bosamiz, v2.0.0 sifatida belgilaymiz (va ixtiyoriy ravishda v2 filialini yaratamiz.)

$ git commit testmod.go -m "Change Hi to allow multilang"
$ git checkout -b v2 # optional but recommended
$ echo "module github.com/robteix/testmod/v2" > go.mod
$ git commit go.mod -m "Bump version to v2"
$ git tag v2.0.0
$ git push --tags origin v2 # or master if we don't have a branch

Asosiy versiyaga yangilash

Kutubxonamizning yangi mos kelmaydigan versiyasini chiqargan bo'lsak ham, mavjud dasturiy ta'minot  buzilmaydi , chunki u mavjud 1.0.1 versiyasidan foydalanishda davom etadi. 2.0.0 versiyasini go get -u olmaydi .

Biroq, bir nuqtada, men kutubxona foydalanuvchisi sifatida 2.0.0 versiyasiga yangilashni xohlashim mumkin, chunki men ko'p tilli yordamga muhtoj bo'lgan foydalanuvchilardan biri edim.

Men buni qilaman, lekin dasturimni shunga mos ravishda o'zgartiraman:

package main

import (
     "fmt"
     "github.com/robteix/testmod/v2" 
)

func main() {
     g, err := testmod.Hi("Roberto", "pt")
     if err != nil {
         panic(err)
     }
     fmt.Println(g)
}

Va keyin men ishga tushganimda go build, u ketadi va men uchun 2.0.0 versiyasini oladi. Eʼtibor bering, import yoʻli “v2” bilan tugasa ham, Go modulga oʻzining tegishli nomi (“testmod”) bilan murojaat qiladi.

Yuqorida aytib o'tganimdek, asosiy versiya barcha maqsadlar va maqsadlar uchun butunlay boshqacha paketdir. Go modullari ikkalasini umuman bog'lamaydi. Bu shuni anglatadiki, biz bir xil ikkilikda ikkita mos kelmaydigan versiyadan foydalanishimiz mumkin:

package main
import (
     "fmt"
     "github.com/robteix/testmod"
     testmodML "github.com/robteix/testmod/v2"
)

func main() {
     fmt.Println(testmod.Hi("Roberto"))
     g, err := testmodML.Hi("Roberto", "pt")
     if err != nil {
         panic(err)
     }
     fmt.Println(g)
}

Bu qaramlikni boshqarish bilan bog'liq umumiy muammoni bartaraf qiladi: agar bog'liqliklar bir xil kutubxonaning turli versiyalariga bog'liq bo'lsa.

Uni tartibga solish

Faqat testmod 2.0.0 dan foydalanadigan oldingi versiyaga qaytsak, agar biz go.mod hozirgi tarkibni tekshirsak, biz nimanidir ko'ramiz:

module mod
require github.com/robteix/testmod v1.0.1
require github.com/robteix/testmod/v2 v2.0.0

Odatiy bo'lib, Go go.mod siz so'ramaguningizcha bog'liqlikni olib tashlamaydi. Agar sizda endi foydalanmaydigan va tozalashni xohlaydigan bog'liqliklar bo'lsa, yangi tidy buyruqdan foydalanishingiz mumkin:

$ go mod tidy

Endi bizda faqat haqiqatda ishlatilayotgan bog'liqliklar qoldi.

Sotuvchilik

Go modullari vendor/ sukut bo'yicha katalogni e'tiborsiz qoldiradi. Oxir- oqibat , sotuvchidan voz kechish kerak[^0]. Ammo, agar biz hali ham versiya boshqaruviga sotuvchi bog'liqliklarini qo'shmoqchi bo'lsak, biz buni baribir qila olamiz:

$ go mod vendor

Bu vendor/ sizning loyihangizning ildizi ostida barcha bog'liqliklaringiz uchun manba kodini o'z ichiga olgan katalog yaratadi.

Shunga qaramay, go build sukut bo'yicha ushbu katalog tarkibini e'tiborsiz qoldiradi. Agar siz katalogdan bog'liqliklar yaratmoqchi vendor/ bo'lsangiz, buni so'rashingiz kerak bo'ladi.

$ go build -mod vendor

Men sotuvchilardan foydalanishga tayyor bo'lgan ko'plab ishlab chiquvchilar go buildo'zlarining ishlab chiqish mashinalarida normal ishlaydi va -mod vendor o'zlarining CI-larida foydalanishadi deb umid qilaman.

Shunga qaramay, Go modullari sotuvchilik g'oyasidan uzoqlashmoqda va to'g'ridan-to'g'ri yuqori versiyani boshqarish xizmatlariga bog'liq bo'lishni istamaydiganlar uchun Go moduli proksi-serveridan foydalanishga o'tmoqda.

go Tarmoqqa umuman kirmasligini kafolatlash usullari mavjud (masalan GOPROXY=off), lekin bular kelajakdagi blog posti uchun mavzu.

Xulosa

Bu post biroz qo'rqinchli tuyulishi mumkin, lekin men ko'p narsalarni birgalikda tushuntirishga harakat qildim. Haqiqat shundaki, endi Go modullari asosan shaffof. Biz har doimgidek kodimizdagi kabi paketni import qilamiz va goqolganlari bilan buyruq hal qilinadi.

Biz biror narsani qurganimizda, bog'liqliklar avtomatik ravishda olinadi. Shuningdek, u $GOPATHnima uchun narsalar ma'lum bir katalogga kirishi kerakligini tushunishda qiynalayotgan yangi Go dasturchilari uchun to'siq bo'lgan foydalanish zaruratini yo'q qiladi.

Vendoring (norasmiy ravishda) proksi-serverlardan foydalanish foydasiga bekor qilinmoqda.[^0] Go moduli proksi-serveri haqida alohida post yozishim mumkin. (Yangilanish: jonli.) [^0]: Menimcha, bu juda kuchli chiqdi va odamlar hozirda sotuvchilik o‘chirilayotgandek taassurot qoldirdi. Bu emas. Oldindan biroz farq qilsa ham, sotuvchilar hali ham ishlaydi. Sotuvchini proksi bo'lishi yoki bo'lmasligi mumkin bo'lgan yaxshiroq narsa bilan almashtirish istagi borga o'xshaydi . Ammo hozircha bu shunchaki: yaxshiroq yechim topish istagi. Yaxshi o'rinbosar topilmaguncha sotuvchilik to'xtamaydi (agar mavjud bo'lsa).