Bir Crate’i Crates.io’da Yayımlamak
Projelerimizde bağımlılık olarak crates.io üzerindeki paketleri kullandık; ama kendi paketlerinizi yayımlayarak kodunuzu başka insanlarla da paylaşabilirsiniz. crates.io üzerindeki crate kayıt sistemi, paketlerinizin kaynak kodunu dağıtır; yani ağırlıklı olarak açık kaynak kod barındırır.
Rust ve Cargo, yayımladığınız paketin başkaları tarafından daha kolay bulunmasını ve kullanılmasını sağlayan özellikler sunar. Önce bu özelliklerden bazılarına bakacağız, ardından bir paketin nasıl yayımlanacağını anlatacağız.
Yararlı Belgelendirme Yorumları Yazmak
Paketlerinizi doğru biçimde belgelendirmek, başka kullanıcıların onları ne zaman
ve nasıl kullanacağını anlamasını kolaylaştırır; bu yüzden iyi belgelere zaman
ayırmaya değer. 3. bölümde Rust koduna iki eğik çizgiyle, yani // ile yorum
eklemeyi görmüştük. Rust’ta ayrıca, HTML belgesi üreten özel bir yorum türü
olan belgelendirme yorumu (documentation comment) da vardır. Bu HTML,
crate’inizin nasıl kullanıldığını öğrenmek isteyen programcılar için tasarlanmış
açık API öğelerine ait belgelendirme yorumlarının içeriğini gösterir; crate’in
nasıl gerçeklendiğini değil.
Belgelendirme yorumları iki değil üç eğik çizgi, yani /// kullanır ve metni
biçimlendirmek için Markdown sözdizimini destekler. Belgelendirme yorumlarını,
belgelendirdikleri öğenin hemen üstüne yazın. Liste 14-1, benim_crate
adındaki bir crate içinde yer alan bir_ekle fonksiyonu için yazılmış bir
belgelendirme yorumunu gösteriyor.
/// Verilen sayıya bir ekler.
///
/// # Ornekler
///
/// ```
/// let girdi = 5;
/// let yanit = benim_crate::bir_ekle(girdi);
///
/// assert_eq!(6, yanit);
/// ```
pub fn bir_ekle(x: i32) -> i32 {
x + 1
}
Burada bir_ekle fonksiyonunun ne yaptığını açıklıyoruz, ardından # Ornekler
başlığıyla bir bölüm açıyor ve fonksiyonun nasıl kullanılacağını gösteren bir
kod örneği veriyoruz. Bu belgelendirme yorumundan HTML belge üretmek için
cargo doc çalıştırabiliriz. Bu komut, Rust ile birlikte gelen rustdoc
aracını çalıştırır ve üretilen HTML belgeleri target/doc dizinine koyar.
Kolaylık olsun diye cargo doc --open, mevcut crate’inizin belgeleri için HTML
çıktısını derler; ayrıca tüm bağımlılıkların belgelerini de üretir ve sonucu
tarayıcıda açar. bir_ekle fonksiyonuna giderseniz, belgelendirme yorumundaki
metnin Şekil 14-1’deki gibi işlendiğini görürsünüz.
Şekil 14-1: bir_ekle fonksiyonu için HTML belgesi
Sık Kullanılan Bölümler
Liste 14-1’de HTML içinde “Ornekler” başlıklı bir bölüm oluşturmak için Markdown
başlığı olan # Ornekleri kullandık. Crate yazarlarının belgelerde sık kullandığı
başka bölümler de vardır:
- Panics: Belgelenen fonksiyonun hangi durumlarda panikleyebileceğini açıklar. Programlarının paniklemesini istemeyen çağıranlar, bu durumlarda fonksiyonu çağırmadığından emin olabilir.
- Errors: Fonksiyon bir
Resultdöndürüyorsa, hangi tür hataların oluşabileceğini ve bunların hangi koşullarda dönebileceğini anlatmak, çağıranların farklı hataları farklı biçimlerde ele alan kodlar yazmasını kolaylaştırır. - Safety: Fonksiyonu çağırmak
unsafeise, 20. bölümde ayrıntılandıracağımız gibi, nedenunsafeolduğunu ve çağıranların koruması gereken değişmezleri açıklayan bir bölüm bulunmalıdır.
Belgelendirme yorumlarının çoğunda bu bölümlerin hepsi gerekmez. Yine de bu liste, kullanıcıların kodunuz hakkında bilmek isteyeceği noktaları hatırlatan iyi bir denetim listesidir.
Belgelendirme Yorumlarını Test Olarak Kullanmak
Belgelendirme yorumlarının içine örnek kod blokları eklemek, kütüphanenizin
nasıl kullanılacağını göstermeye yardımcı olur ve güzel bir yan kazanç da sağlar:
cargo test çalıştırıldığında, belgelerdeki kod örnekleri de test olarak
çalıştırılır! Örnekli belge kadar iyi bir şey yoktur. Ama belge yazıldıktan
sonra kod değiştiği için artık çalışmayan örnekler kadar kötü bir şey de yok.
Liste 14-1’deki bir_ekle fonksiyonu belgesiyle cargo test çalıştırırsak,
test sonuçlarında şu bölümü görürüz:
Doc-tests benim_crate
running 1 test
test src/lib.rs - bir_ekle (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
Şimdi fonksiyonu ya da örneği değiştirip örnekteki assert_eq! panikletecek
hale getirirsek ve cargo testi yeniden çalıştırırsak, belge testleri örneğin
ve kodun birbirinden koptuğunu hemen yakalar.
Kapsayıcı Öğeye Yazılan Yorumlar
//! biçimindeki doc yorumları, yorumların ardından gelen öğeyi değil,
yorumları içeren öğeyi belgelendirir. Bu yorumları genellikle crate kök
dosyasında (geleneksel olarak src/lib.rs) ya da bir modülün içinde, crate’i
veya modülü bütün olarak belgelendirmek için kullanırız.
Örneğin bir_ekle fonksiyonunu içeren benim_crate crate’inin amacını
açıklamak için, src/lib.rs dosyasının başına //! ile başlayan belge
yorumları ekleriz. Liste 14-2 bunu gösterir.
//! # Benim Crate'im
//!
//! `benim_crate`, belirli hesaplamalari yapmayi daha kullanisli hale getiren
//! yardimci araclarin bir koleksiyonudur.
/// Verilen sayiya bir ekler.
// --snip--
///
/// # Ornekler
///
/// ```
/// let girdi = 5;
/// let yanit = benim_crate::bir_ekle(girdi);
///
/// assert_eq!(6, yanit);
/// ```
pub fn bir_ekle(x: i32) -> i32 {
x + 1
}
benim_crate crate’inin tamami icin yazilan belge//! ile başlayan son satırdan sonra hiç kod olmadığına dikkat edin. Yorumları
/// yerine //! ile başlattığımız için, bu yorumların ardından gelen öğeyi
değil, yorumu içeren öğeyi belgelendiriyoruz. Bu örnekte o öğe, crate kökü
olan src/lib.rs dosyasıdır. Yani bu yorumlar tüm crate’i anlatır.
cargo doc --open çalıştırdığımızda bu yorumlar, benim_crate için üretilen
belgenin ilk sayfasında, crate içindeki açık öğelerin listesinin üstünde
görünür. Şekil 14-2’de bunu görebilirsiniz.
Öğelerin içinde yazılan belgelendirme yorumları özellikle crate’leri ve modülleri anlatmak için kullanışlıdır. Bunları, kapsayıcının genel amacını açıklamak ve kullanıcıların crate’in düzenini anlamasına yardımcı olmak için kullanın.
Şekil 14-2: benim_crate için işlenmiş belge; crate’i bir bütün olarak açıklayan yorum da buna dahil
Kullanışlı Bir Açık API Dışa Aktarmak
Bir crate yayımlarken açık API’nizin yapısı önemli bir tasarım kararıdır. Crate’inizi kullanan insanlar, yapıya sizin kadar hakim olmaz. Modül ağacı büyükse, ihtiyaç duydukları parçaları bulmakta zorlanabilirler.
- bölümde
pubanahtar sözcüğüyle öğeleri nasıl açık hale getirdiğimizi veuseanahtar sözcüğüyle öğeleri nasıl kapsama aldığımızı görmüştük. Ancak bir crate geliştirirken size mantıklı gelen yapı, kullanıcılarınız için o kadar pratik olmayabilir. Struct’ları veya türleri birkaç katmanlı bir hiyerarşide düzenlemek isteyebilirsiniz; ama hiyerarşinin derininde duran bir türü kullanmak isteyenler, önce o türün var olduğunu fark etmekte zorlanabilir. Ayrıcause benim_crate::bir_modul::baska_modul::FaydaliTur;yazmak yerine yalnızcause benim_crate::FaydaliTur;yazabilmek isterler.
Güzel haber şu: Yapı başka bir kütüphaneden kullanacak kişiler için pratik
değilse, iç düzeninizi baştan kurmak zorunda değilsiniz. Bunun yerine pub use
kullanarak, gizli yapınızdan farklı bir açık yapı oluşturacak şekilde öğeleri
yeniden dışa aktarabilirsiniz. Yeniden dışa aktarma (re-exporting), bir yerde
bulunan açık bir öğeyi başka bir yerde de açık hale getirir; sanki öğe doğrudan
orada tanımlanmış gibi davranır.
Örneğin sanatsal kavramları modellemek için sanat adında bir kütüphane
yazdığımızı düşünelim. Bu kütüphanede iki modül olsun: turler modülü
BirincilRenk ve IkincilRenk adlı iki enum içeriyor, yardimcilar modülü de
karistir adlı bir fonksiyon içeriyor. Liste 14-3 bunu gösterir.
//! # Sanat
//!
//! Sanatsal kavramlari modellemek icin bir kutuphane.
pub mod turler {
/// RYB renk modeline gore birincil renkler.
pub enum BirincilRenk {
Kirmizi,
Sari,
Mavi,
}
/// RYB renk modeline gore ikincil renkler.
pub enum IkincilRenk {
Turuncu,
Yesil,
Mor,
}
}
pub mod yardimcilar {
use crate::turler::*;
/// Iki birincil rengi esit miktarda birlestirerek
/// bir ikincil renk olusturur.
pub fn karistir(renk1: BirincilRenk, renk2: BirincilRenk) -> IkincilRenk {
// --snip--
let _ = (renk1, renk2);
unimplemented!();
}
}
turler ve yardimcilar modullerine ayrilmis bir sanat kutuphanesiŞekil 14-3, bu crate için cargo doc ile üretilen belgenin ön sayfasının nasıl
görüneceğini gösterir.
Şekil 14-3: turler ve yardimcilar modüllerini listeleyen sanat belgesinin ön sayfası
Burada BirincilRenk ve IkincilRenk türlerinin ön sayfada listelenmediğine,
aynı şekilde karistir fonksiyonunun da görünmediğine dikkat edin. Bunları
görmek için turler ve yardimcilar bağlantılarına tıklamamız gerekir.
Bu kütüphaneye bağımlı başka bir crate, sanat içindeki öğeleri kullanmak için
şu an tanımlanmış modül yapısını belirten use ifadeleri yazmak zorunda kalır.
Liste 14-4, sanat crate’indeki BirincilRenk ve karistir öğelerini kullanan
bir crate örneğini gösterir.
use sanat::turler::BirincilRenk;
use sanat::yardimcilar::karistir;
fn main() {
let kirmizi = BirincilRenk::Kirmizi;
let sari = BirincilRenk::Sari;
karistir(kirmizi, sari);
}
sanat crate’indeki ogeleri ic yapi disa aktarilmis halde kullanan bir crateListe 14-4’teki kodun yazarı, BirincilRenkin turler modülünde ve
karistirın yardimcilar modülünde olduğunu önce keşfetmek zorundadır.
sanat crate’inin modül yapısı, onu geliştirenler için onu kullananlardan daha
anlamlıdır. İç yapı, sanat crate’ini nasıl kullanacağını anlamaya çalışan biri
için yararlı bilgi sunmaz; tam tersine, nereye bakacağını çözmeye çalışan
geliştiricilerin kafasını karıştırır ve use ifadelerinde modül adlarını
yazmalarını gerektirir.
İç düzeni açık API’den kaldırmak için, Liste 14-3’teki sanat crate’i kodunu
değiştirip öğeleri üst düzeyde yeniden dışa aktaracak pub use ifadeleri
ekleyebiliriz. Liste 14-5 bunu gösterir.
//! # Sanat
//!
//! Sanatsal kavramlari modellemek icin bir kutuphane.
pub use self::turler::BirincilRenk;
pub use self::turler::IkincilRenk;
pub use self::yardimcilar::karistir;
pub mod turler {
// --snip--
/// RYB renk modeline gore birincil renkler.
pub enum BirincilRenk {
Kirmizi,
Sari,
Mavi,
}
/// RYB renk modeline gore ikincil renkler.
pub enum IkincilRenk {
Turuncu,
Yesil,
Mor,
}
}
pub mod yardimcilar {
// --snip--
use crate::turler::*;
/// Iki birincil rengi esit miktarda birlestirerek
/// bir ikincil renk olusturur.
pub fn karistir(renk1: BirincilRenk, renk2: BirincilRenk) -> IkincilRenk {
let _ = (renk1, renk2);
IkincilRenk::Turuncu
}
}
pub use ifadeleri eklemekBu crate için cargo doc tarafından üretilen API belgesi artık yeniden dışa
aktarımları da ön sayfada listeler ve bağlantılar. Böylece BirincilRenk,
IkincilRenk ve karistir çok daha kolay bulunur. Şekil 14-4 bunu gösterir.
Şekil 14-4: Yeniden dışa aktarımları listeleyen sanat belgesinin ön sayfası
sanat crate’ini kullananlar isterlerse Liste 14-4’teki gibi iç yapıyı hâlâ
görüp kullanabilir, isterlerse Liste 14-5’teki daha kullanışlı yapıyı seçebilir.
Liste 14-6 ikinci yaklaşımı gösterir.
use sanat::karistir;
use sanat::BirincilRenk;
fn main() {
// --snip--
let kirmizi = BirincilRenk::Kirmizi;
let sari = BirincilRenk::Sari;
karistir(kirmizi, sari);
}
sanat crate’inden yeniden disa aktarilan ogeleri kullanan bir programİç içe çok sayıda modül olduğunda, türleri üst düzeye pub use ile yeniden dışa
aktarmak, crate’i kullanan kişilerin deneyiminde ciddi fark yaratabilir.
pub use’ün bir başka yaygın kullanım alanı da bir bağımlılıktaki tanımları,
mevcut crate üzerinden yeniden dışa aktarıp onları sizin açık API’nizin bir
parçası haline getirmektir.
Kullanışlı bir açık API tasarlamak, tam anlamıyla bilimden çok biraz sanata
benzer; kullanıcılarınız için en iyi çalışan API’yi bulana kadar yineleme
yapabilirsiniz. pub use seçimi, iç yapınızı nasıl kuracağınız konusunda size
esneklik sağlar ve iç yapıyla kullanıcılara sunduğunuz yüzeyi birbirinden
ayırır. Kurduğunuz bazı crate’lerin koduna bakın; çoğunda iç yapının açık API’den
farklı olduğunu görürsünüz.
Crates.io Hesabı Açmak
Herhangi bir crate yayımlayabilmek için önce crates.io üzerinde bir hesap açmalı ve bir API belirteci almalısınız. Bunun
için crates.io ana sayfasına gidip GitHub
hesabınızla oturum açın. Şu anda GitHub hesabı zorunlu, ama ileride site başka
yöntemleri de destekleyebilir. Giriş yaptıktan sonra
https://crates.io/me/ adresindeki hesap
ayarlarınıza gidip API anahtarınızı alın. Sonra cargo login komutunu
çalıştırıp istendiğinde API anahtarınızı yapıştırın:
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
Bu komut Cargo’ya API belirtecinizi bildirir ve onu yerel olarak ~/.cargo/credentials.toml içine kaydeder. Bu belirtecin gizli olduğunu unutmayın: Kimseyle paylaşmayın. Herhangi bir nedenle paylaşırsanız derhal iptal edip yenisini üretin.
Yeni Bir Crate’e Meta Veri Eklemek
Yayımlamak istediğiniz bir crate’iniz olduğunu düşünelim. Yayımlamadan önce,
crate’in Cargo.toml dosyasındaki [package] bölümüne bazı meta veriler
eklemeniz gerekir.
Crate’inizin benzersiz bir adı olmalıdır. Yerelde çalışırken crate’e istediğiniz
adı verebilirsiniz. Ama crates.io üzerindeki
crate adları “ilk gelen alır” mantığıyla ayrılır. Bir ad alındığında, artık
başka hiç kimse o adla crate yayımlayamaz. Yayımlamayı denemeden önce
kullanmak istediğiniz adı arayın. Ad alınmışsa başka bir ad bulmalı ve
Cargo.toml içindeki [package] bölümündeki name alanını buna göre
güncellemelisiniz:
Dosya Adı: Cargo.toml
[package]
name = "tahmin_oyunu"
Benzersiz bir ad seçmiş olsanız bile, bu noktada cargo publish
çalıştırırsanız önce bir uyarı, ardından bir hata alırsınız:
$ cargo publish
Updating crates.io index
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
--snip--
error: failed to publish to registry at https://crates.io
Caused by:
the remote server responded with an error (status 400 Bad Request): missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for more information on configuring these fields
Bu hatanın nedeni, bazı kritik bilgilerin eksik olmasıdır: bir açıklama ve bir
lisans zorunludur. Böylece insanlar crate’inizin ne yaptığını ve hangi
koşullarda kullanabileceklerini bilir. Cargo.toml içine, arama sonuçlarında da
görüneceği için bir iki cümlelik kısa bir açıklama ekleyin. license alanı
içinse bir lisans tanımlayıcısı değeri yazmanız gerekir. Linux Foundation’ın
Software Package Data Exchange (SPDX) listesi, bu alanda
kullanabileceğiniz tanımlayıcıları içerir. Örneğin crate’inizi MIT lisansıyla
lisansladığınızı belirtmek için MIT tanımlayıcısını ekleyebilirsiniz:
Dosya Adı: Cargo.toml
[package]
name = "tahmin_oyunu"
license = "MIT"
Kullanmak istediğiniz lisans SPDX listesinde yer almıyorsa, lisans metnini bir
dosyaya koymalı, o dosyayı projenize eklemeli ve license yerine license-file
anahtarını kullanarak dosya adını belirtmelisiniz.
Hangi lisansın projeniz için uygun olduğuna karar vermek bu kitabın kapsamı
dışında. Rust topluluğunda pek çok kişi projelerini, Rust’ın yaptığı gibi
MIT OR Apache-2.0 çift lisansıyla lisanslar. Bu kullanım, projeniz için
birden fazla lisansı OR ile ayırarak yazabileceğinizi de gösterir.
Benzersiz bir ad, sürüm, açıklama ve lisans eklendiğinde, yayımlanmaya hazır bir projenin Cargo.toml dosyası şöyle görünebilir:
Dosya Adı: Cargo.toml
[package]
name = "tahmin_oyunu"
version = "0.1.0"
edition = "2024"
description = "Bilgisayarin sectigi sayiyi tahmin ettiginiz eglenceli bir oyun."
license = "MIT OR Apache-2.0"
[dependencies]
Cargo belgeleri başka hangi meta verileri ekleyebileceğinizi de anlatır; böylece başkalarının crate’inizi daha kolay keşfetmesini ve kullanmasını sağlayabilirsiniz.
Crates.io’ya Yayımlamak
Hesabınızı oluşturduğunuza, API belirtecinizi kaydettiğinize, crate’inize ad verdiğinize ve gerekli meta verileri eklediğinize göre artık yayıma hazırsınız. Bir crate yayımlamak, belirli bir sürümü başkalarının kullanabilmesi için crates.io üzerine yükler.
Dikkatli olun; yayımlama kalıcıdır. Bir sürümün üstüne asla yazılamaz ve kod yalnızca bazı özel durumlarda silinebilir. Crates.io’nun temel amaçlarından biri, crates.io üzerindeki crate’lere bağlı tüm projelerin derlemelerinin gelecekte de çalışmasını sağlayan kalıcı bir arşiv olmasıdır. Sürümleri silmeye izin vermek bu amacı imkânsız hale getirirdi. Öte yandan yayımlayabileceğiniz sürüm sayısında herhangi bir sınır yoktur.
cargo publish komutunu yeniden çalıştırın. Bu kez başarılı olmalıdır:
$ cargo publish
Updating crates.io index
Packaging tahmin_oyunu v0.1.0 (file:///projects/tahmin_oyunu)
Packaged 6 files, 1.2KiB (895.0B compressed)
Verifying tahmin_oyunu v0.1.0 (file:///projects/tahmin_oyunu)
Compiling tahmin_oyunu v0.1.0
(file:///projects/tahmin_oyunu/target/package/tahmin_oyunu-0.1.0)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Uploading tahmin_oyunu v0.1.0 (file:///projects/tahmin_oyunu)
Uploaded tahmin_oyunu v0.1.0 to registry `crates-io`
note: waiting for `tahmin_oyunu v0.1.0` to be available at registry
`crates-io`.
You may press ctrl-c to skip waiting; the crate should be available shortly.
Published tahmin_oyunu v0.1.0 at registry `crates-io`
Tebrikler! Kodunuzu artık Rust topluluğuyla paylaştınız; isteyen herkes sizin crate’inizi projesine bağımlılık olarak kolayca ekleyebilir.
Var Olan Bir Crate’in Yeni Sürümünü Yayımlamak
Crate’inizde değişiklik yapıp yeni bir sürüm yayımlamaya hazır olduğunuzda,
Cargo.toml dosyasındaki version değerini değiştirir ve yeniden yayımlarsınız.
Yaptığınız değişikliğin türüne göre uygun sonraki sürüm numarasını seçmek için
Semantik Sürümleme kurallarını kullanın. Sonra cargo publish
çalıştırarak yeni sürümü yükleyin.
Crates.io’da Sürümleri Kullanımdan Kaldırmak
Bir crate’in önceki sürümlerini silemezsiniz; ama yeni projelerin onları yeni bir bağımlılık olarak eklemesini engelleyebilirsiniz. Bu, bir crate sürümü bir sebeple bozuk çıktığında işe yarar. Böyle durumlar için Cargo, bir sürümü yank etmeyi destekler.
Bir sürümü yank etmek, mevcut projelerin çalışmasını bozmadan yeni projelerin o sürüme bağımlı olmasını engeller. Pratikte bu, elinde Cargo.lock bulunan projelerin bozulmaması, ama gelecekte üretilecek yeni Cargo.lock dosyalarının yank edilen sürümü seçmemesi demektir.
Daha önce yayımladığınız bir crate’in belirli bir sürümünü yank etmek için,
crate dizininde cargo yank çalıştırır ve istediğiniz sürümü belirtirsiniz.
Örneğin tahmin_oyunu adlı crate’in 1.0.1 sürümünü yayımladıysak ve şimdi
yank etmek istiyorsak, proje dizininde şu komutu çalıştırırız:
$ cargo yank --vers 1.0.1
Updating crates.io index
Yank tahmin_oyunu@1.0.1
Komuta --undo ekleyerek yapılan yank işlemini geri de alabilirsiniz:
$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank tahmin_oyunu@1.0.1
Bir yank işlemi hiçbir kodu silmez. Örneğin yanlışlıkla yüklenmiş gizli bilgileri ortadan kaldırmaz. Böyle bir şey olduysa o gizli bilgileri hemen sıfırlamanız gerekir.