การเผยแพร่ Crate ไปยัง Crates.io
เราได้ใช้แพ็กเกจจาก crates.io เป็นทรัพยากรภายนอก (dependencies) ในโปรเจกต์ของเรา แต่นอกจากนี้คุณยังสามารถแบ่งปันโค้ดของคุณให้กับผู้อื่นได้โดยการเผยแพร่แพ็กเกจของคุณเอง คลังเก็บ crate (crate registry) ที่ crates.io จะแจกจ่ายซอร์สโค้ดของแพ็กเกจของคุณ ดังนั้นมันจึงโฮสต์โค้ดที่เป็นโอเพนซอร์สเป็นหลัก
Rust และ Cargo มีฟีเจอร์ที่ช่วยให้แพ็กเกจที่คุณเผยแพร่ถูกค้นหาและใช้งานได้ง่ายขึ้นสำหรับผู้อื่น เราจะพูดถึงฟีเจอร์เหล่านี้ในหัวข้อถัดไป จากนั้นจะอธิบายวิธีเผยแพร่แพ็กเกจ
การเขียนคอมเมนต์เอกสารที่เป็นประโยชน์
การเขียนเอกสารอธิบายแพ็กเกจของคุณอย่างถูกต้องจะช่วยให้ผู้ใช้คนอื่น ๆ ทราบวิธีและเวลาที่ควรนำไปใช้งาน ดังนั้นจึงคุ้มค่าที่จะลงทุนเวลาในการเขียนเอกสาร ในบทที่ 3 เราได้พูดถึงการคอมเมนต์โค้ด Rust โดยใช้เครื่องหมายทับสองอัน // นอกจากนี้ Rust ยังมีคอมเมนต์ชนิดพิเศษสำหรับการทำเอกสารประกอบ ซึ่งรู้จักกันในชื่อ คอมเมนต์เอกสาร (documentation comment) ซึ่งจะสร้างเอกสารในรูปแบบ HTML ออกมา โดย HTML จะแสดงเนื้อหาของคอมเมนต์เอกสารสำหรับรายการ Public API ที่มีไว้สำหรับโปรแกรมเมอร์ที่สนใจต้องการทราบวิธีใช้งาน crate ของคุณ ซึ่งต่างจากวิธีที่ crate ของคุณถูกประยุกต์ใช้งาน (implemented) ภายใน
คอมเมนต์เอกสารจะใช้เครื่องหมายทับสามอัน /// แทนที่จะเป็นสองอัน และรองรับไวยากรณ์ Markdown สำหรับการจัดรูปแบบข้อความ โดยวางคอมเมนต์เอกสารไว้หน้ารายการที่ต้องการทำเอกสารประกอบทันที โค้ดตัวอย่างที่ 14-1 แสดงคอมเมนต์เอกสารสำหรับฟังก์ชัน add_one ใน crate ที่ชื่อว่า my_crate
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
ในที่นี้ เราให้คำอธิบายว่าฟังก์ชัน add_one ทำหน้าที่อะไร เริ่มต้นหัวข้อด้วยหัวเรื่อง Examples แล้วจัดเตรียมโค้ดที่สาธิตวิธีใช้งานฟังก์ชัน add_one เราสามารถสร้างเอกสาร HTML จากคอมเมนต์เอกสารนี้ได้โดยการรันคำสั่ง cargo doc คำสั่งนี้จะรันเครื่องมือ rustdoc ที่แจกจ่ายมาพร้อมกับ Rust และวางเอกสาร HTML ที่สร้างขึ้นไว้ในไดเรกทอรี target/doc
เพื่อความสะดวก การรันคำสั่ง cargo doc --open จะบิลด์ HTML สำหรับเอกสารประกอบของ crate ปัจจุบันของคุณ (รวมถึงเอกสารประกอบสำหรับไลบรารีภายนอกทั้งหมดของ crate คุณ) และเปิดผลลัพธ์ในเว็บเบราว์เซอร์ เมื่อนำทางไปยังฟังก์ชัน add_one คุณจะเห็นว่าข้อความในคอมเมนต์เอกสารนั้นถูกแสดงผลอย่างไร ดังแสดงในรูปภาพที่ 14-1
รูปภาพที่ 14-1: เอกสาร HTML สำหรับฟังก์ชัน add_one
หัวข้อที่นิยมใช้งานบ่อย
เราใช้หัวเรื่อง Markdown # Examples ในโค้ดตัวอย่างที่ 14-1 เพื่อสร้างหัวข้อใน HTML ที่มีชื่อว่า “Examples” นี่คือหัวข้ออื่น ๆ ที่ผู้เขียน crate นิยมใช้กันบ่อยในเอกสารประกอบ:
- Panics: สถานการณ์ที่ฟังก์ชันซึ่งถูกเขียนเอกสารประกอบไว้อาจเกิดตื่นตระหนก (panic) ขึ้นได้ ผู้เรียกใช้ฟังก์ชันที่ไม่ต้องการให้โปรแกรมของตนตื่นตระหนกควรตรวจสอบให้แน่ใจว่าตนเองไม่ได้เรียกใช้ฟังก์ชันในสถานการณ์เหล่านี้
- Errors: หากฟังก์ชันคืนค่าเป็น
Resultการอธิบายชนิดของข้อผิดพลาดที่อาจเกิดขึ้น และเงื่อนไขใดที่อาจทำให้เกิดข้อผิดพลาดเหล่านั้น คืนกลับไป จะมีประโยชน์ต่อผู้เรียกใช้เพื่อให้พวกเขาสามารถเขียนโค้ดจัดการข้อผิดพลาดประเภทต่าง ๆ ในรูปแบบที่แตกต่างกันได้ - Safety: หากฟังก์ชันนั้นเป็นแบบ
unsafeที่จะเรียกใช้ (เราจะพูดถึงความไม่ปลอดภัยในบทที่ 20) ควรมีหัวข้อที่อธิบายว่าเหตุใดฟังก์ชันจึงไม่ปลอดภัย และครอบคลุมถึงเงื่อนไขคงที่ (invariants) ที่ฟังก์ชันคาดหวังให้ผู้เรียกปฏิบัติตาม
คอมเมนต์เอกสารส่วนใหญ่ไม่จำเป็นต้องมีหัวข้อเหล่านี้ทั้งหมด แต่เป็นรายการตรวจสอบที่ดีที่จะเตือนคุณถึงแง่มุมของโค้ดที่ผู้ใช้จะสนใจอยากรู้
คอมเมนต์เอกสารทำหน้าที่เป็นแบบทดสอบ
การเพิ่มบล็อกโค้ดตัวอย่างในคอมเมนต์เอกสารของคุณจะช่วยสาธิตวิธีใช้งานไลบรารีของคุณ และมีโบนัสเพิ่มเติมคือ: การรัน cargo test จะรันโค้ดตัวอย่างในเอกสารประกอบของคุณเป็นการทดสอบด้วย! ไม่มีอะไรดีไปกว่าเอกสารที่มีตัวอย่าง แต่ก็ไม่มีอะไรแย่ไปกว่าตัวอย่างที่ไม่ทำงานเพราะโค้ดเปลี่ยนไปนับตั้งแต่เขียนเอกสาร หากเรารัน cargo test กับเอกสารประกอบสำหรับฟังก์ชัน add_one จากโค้ดตัวอย่างที่ 14-1 เราจะเห็นส่วนในผลลัพธ์การทดสอบที่ดูเป็นดังนี้:
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
ตอนนี้ หากเราเปลี่ยนฟังก์ชัน หรือเปลี่ยนตัวอย่างจนกระทั่ง assert_eq! ในตัวอย่างเกิด panic ขึ้น และรัน cargo test อีกครั้ง เราจะเห็นว่าการทดสอบ doc tests ช่วยตรวจจับได้ว่าตัวอย่างและโค้ดนั้นไม่ตรงกันแล้ว!
คอมเมนต์ครอบคลุมรายการภายใน
รูปแบบคอมเมนต์เอกสาร //! จะเพิ่มเอกสารประกอบให้กับรายการที่บรรจุคอมเมนต์นั้นไว้ แทนที่จะเป็นรายการที่ตามหลังคอมเมนต์ โดยทั่วไปเราจะใช้คอมเมนต์เอกสารชนิดนี้ภายในไฟล์รากของ crate (โดยธรรมเนียมคือ src/lib.rs) หรือภายในมอดูลเพื่อทำเอกสารประกอบให้กับ crate หรือมอดูลโดยรวม
ตัวอย่างเช่น หากต้องการเพิ่มเอกสารที่อธิบายวัตถุประสงค์ของ crate my_crate ที่บรรจุฟังก์ชัน add_one เราจะเพิ่มคอมเมนต์เอกสารที่เริ่มต้นด้วย //! ไว้ที่จุดเริ่มต้นของไฟล์ src/lib.rs ดังแสดงในโค้ดตัวอย่างที่ 14-2
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
/// Adds one to the number given.
// --snip--
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
สังเกตว่าไม่มีโค้ดใด ๆ ตามหลังบรรทัดสุดท้ายที่เริ่มต้นด้วย //! เนื่องจากเราเริ่มต้นคอมเมนต์ด้วย //! แทนที่จะเป็น /// เราจึงกำลังเขียนเอกสารอธิบายรายการที่บรรจุคอมเมนต์นี้ไว้ แทนที่จะเป็นรายการที่ตามหลังคอมเมนต์นี้ ซึ่งในกรณีนี้ รายการนั้นคือไฟล์ src/lib.rs ซึ่งเป็นรากของ crate (crate root) คอมเมนต์เหล่านี้จึงอธิบายทั้ง crate โดยรวม
เมื่อเรารัน cargo doc --open คอมเมนต์เหล่านี้จะแสดงผลในหน้าแรกของเอกสารประกอบสำหรับ my_crate เหนือรายการที่เป็น public ใน crate ดังแสดงในรูปภาพที่ 14-2
คอมเมนต์เอกสารภายในรายการมีประโยชน์อย่างยิ่งสำหรับการอธิบาย crate และมอดูล ใช้พวกมันเพื่ออธิบายวัตถุประสงค์โดยรวมของตัวบรรจุ (container) เพื่อช่วยให้ผู้ใช้ของคุณเข้าใจการจัดระเบียบของ crate
รูปภาพที่ 14-2: เอกสารที่ถูกแสดงผลสำหรับ my_crate รวมถึงคอมเมนต์อธิบาย crate โดยรวม
การส่งออก Public API ที่สะดวกต่อการใช้งาน
โครงสร้างของ Public API ของคุณคือข้อพิจารณาที่สำคัญเมื่อจะเผยแพร่ crate ผู้ที่ใช้งาน crate ของคุณจะคุ้นเคยกับโครงสร้างน้อยกว่าคุณ และอาจมีปัญหาในการค้นหาส่วนประกอบที่ตนเองต้องการใช้หาก crate ของคุณมีลำดับชั้นมอดูลขนาดใหญ่
ในบทที่ 7 เราได้พูดถึงการทำรายการให้เป็น public โดยใช้คีย์เวิร์ด pub และการนำรายการเข้ามาใน scope โดยใช้คีย์เวิร์ด use อย่างไรก็ตาม โครงสร้างที่ดูสมเหตุสมผลสำหรับคุณในขณะพัฒนา crate อาจจะไม่ค่อยสะดวกสำหรับผู้ใช้งานของคุณ คุณอาจต้องการจัดระเบียบ struct ไว้ในลำดับชั้นที่มีหลายระดับ แต่ผู้ที่ต้องการใช้ชนิดข้อมูลที่คุณนิยามไว้ลึกลงไปในลำดับชั้นอาจจะพบลำบากว่าชนิดข้อมูลนั้นมีอยู่ นอกจากนี้ พวกเขาอาจจะรู้สึกรำคาญใจที่ต้องพิมพ์ use my_crate::some_module::another_module::UsefulType; แทนที่จะเป็น use my_crate::UsefulType;
ข่าวดีก็คือหากโครงสร้างไม่ได้สะดวกสำหรับผู้อื่นในการใช้งานจากไลบรารีอื่น คุณไม่จำเป็นต้องจัดระเบียบโครงสร้างภายในใหม่ แต่คุณสามารถส่งออกรายการใหม่อีกครั้ง (re-export) เพื่อสร้างโครงสร้าง public ที่แตกต่างจากโครงสร้าง private ภายในของคุณได้โดยใช้ pub use การส่งออกใหม่อีกครั้ง (re-exporting) จะนำรายการที่เป็น public ในตำแหน่งหนึ่ง มาทำให้เป็น public ในอีกตำแหน่งหนึ่ง เสมือนว่ามันถูกนิยามไว้ในอีกตำแหน่งนั้นแทน
ตัวอย่างเช่น สมมติว่าเราสร้างไลบรารีชื่อ art สำหรับจำลองแนวคิดทางศิลปะ ภายในไลบรารีนี้มี 2 มอดูล ได้แก่ มอดูล kinds ซึ่งบรรจุ enum 2 ตัวชื่อ PrimaryColor และ SecondaryColor และมอดูล utils ซึ่งบรรจุฟังก์ชันชื่อ mix ดังแสดงในโค้ดตัวอย่างที่ 14-3
//! # Art
//!
//! A library for modeling artistic concepts.
pub mod kinds {
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
unimplemented!();
}
}
รูปภาพที่ 14-3 แสดงว่าหน้าแรกของเอกสารสำหรับ crate นี้ที่สร้างโดย cargo doc จะมีลักษณะอย่างไร
รูปภาพที่ 14-3: หน้าแรกของเอกสารสำหรับ art ที่แสดงมอดูล kinds และ utils
สังเกตว่าชนิดข้อมูล PrimaryColor และ SecondaryColor ไม่ได้แสดงอยู่ในหน้าแรก และฟังก์ชัน mix ก็เช่นกัน เราต้องคลิก kinds และ utils เพื่อเข้าไปดูพวกมัน
อีก crate หนึ่งที่พึ่งพาไลบรารีนี้จะต้องมีคำสั่ง use ที่นำรายการจาก art เข้ามาใน scope โดยระบุโครงสร้างมอดูลตามที่ถูกนิยามไว้ในปัจจุบัน โค้ดตัวอย่างที่ 14-4 แสดงตัวอย่าง crate ที่ใช้รายการ PrimaryColor และ mix จาก crate art
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
ผู้เขียนโค้ดในโค้ดตัวอย่างที่ 14-4 ซึ่งใช้ crate art ต้องค้นหาว่า PrimaryColor อยู่ในมอดูล kinds และ mix อยู่ในมอดูล utils โครงสร้างมอดูลของ crate art นั้นมีความเกี่ยวข้องกับนักพัฒนาที่ทำงานพัฒนา crate art มากกว่าผู้ที่นำไปใช้งาน โครงสร้างภายในไม่ได้บรรจุข้อมูลที่มีประโยชน์สำหรับผู้ที่พยายามทำความเข้าใจวิธีใช้งาน crate art แต่มักจะสร้างความสับสนเนื่องจากนักพัฒนาที่นำไปใช้ต้องค้นหาว่าจะดูได้ที่ไหน และต้องระบุชื่อมอดูลในคำสั่ง use
ในการถอดการจัดระเบียบภายในออกจาก Public API เราสามารถแก้ไขโค้ด crate art ในโค้ดตัวอย่างที่ 14-3 โดยเพิ่มคำสั่ง pub use เพื่อส่งออกรายการใหม่อีกครั้งที่ระดับบนสุด ดังแสดงในโค้ดตัวอย่างที่ 14-5
//! # Art
//!
//! A library for modeling artistic concepts.
pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;
pub mod kinds {
// --snip--
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
// --snip--
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
SecondaryColor::Orange
}
}
เอกสาร API ที่ cargo doc สร้างขึ้นสำหรับ crate นี้จะแสดงรายการและลิงก์การส่งออกใหม่อีกครั้งบนหน้าแรกแล้ว ดังแสดงในรูปภาพที่ 14-4 ซึ่งช่วยให้ชนิดข้อมูล PrimaryColor และ SecondaryColor รวมถึงฟังก์ชัน mix ค้นหาได้ง่ายขึ้นมาก
รูปภาพที่ 14-4: หน้าแรกของเอกสารสำหรับ art ที่แสดงรายการที่ถูกส่งออกใหม่อีกครั้ง
ผู้ใช้ crate art ยังคงสามารถมองเห็นและใช้โครงสร้างภายในจากโค้ดตัวอย่างที่ 14-3 ตามที่สาธิตในโค้ดตัวอย่างที่ 14-4 ได้ หรือสามารถใช้โครงสร้างที่สะดวกกว่าในโค้ดตัวอย่างที่ 14-5 ดังแสดงในโค้ดตัวอย่างที่ 14-6
use art::PrimaryColor;
use art::mix;
fn main() {
// --snip--
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
ในกรณีที่มีมอดูลซ้อนกันหลายระดับ การส่งออกชนิดข้อมูลใหม่อีกครั้งที่ระดับบนสุดด้วย pub use สามารถสร้างความแตกต่างอย่างมีนัยสำคัญต่อประสบการณ์ของผู้ใช้งาน crate อีกการใช้งานทั่วไปของ pub use คือการส่งออกนิยามของทรัพยากรภายนอกใน crate ปัจจุบันใหม่อีกครั้ง เพื่อทำให้นิยามของ crate นั้นกลายเป็นส่วนหนึ่งของ Public API ของ crate คุณ
การสร้างโครงสร้าง Public API ที่มีประโยชน์ถือเป็นศิลปะมากกว่าวิทยาศาสตร์ และคุณสามารถปรับเปลี่ยนวนซ้ำเพื่อหา API ที่ทำงานได้ดีที่สุดสำหรับผู้ใช้ของคุณ การเลือกใช้ pub use จะมอบความยืดหยุ่นในวิธีที่คุณจัดโครงสร้าง crate ภายใน และตัดความเชื่อมโยงระหว่างโครงสร้างภายในกับสิ่งที่เสนอต่อผู้ใช้ ให้ลองดูโค้ดของ crate บางส่วนที่คุณติดตั้งไว้ เพื่อดูว่าโครงสร้างภายในของพวกมันแตกต่างจาก Public API หรือไม่
การตั้งค่าบัญชี Crates.io
ก่อนที่คุณจะสามารถเผยแพร่ crate ใด ๆ ได้ คุณจะต้องสร้างบัญชีบน crates.io และรับโทเค็น API ก่อน ในการทำเช่นนั้น ให้เยี่ยมชมหน้าแรกที่ crates.io แล้วเข้าสู่ระบบผ่านบัญชี GitHub (ขณะนี้จำเป็นต้องมีบัญชี GitHub แต่ในอนาคตเว็บไซต์อาจรองรับวิธีสร้างบัญชีแบบอื่น) เมื่อเข้าสู่ระบบเรียบร้อยแล้ว ให้ไปที่การตั้งค่าบัญชีของคุณที่ https://crates.io/me/ แล้วคัดลอกคีย์ API ของคุณ จากนั้น รันคำสั่ง cargo login แล้ววางคีย์ API เมื่อได้รับแจ้ง ดังนี้:
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
คำสั่งนี้จะแจ้ง Cargo ถึงโทเค็น API ของคุณและจัดเก็บไว้ในเครื่องที่ ~/.cargo/credentials.toml โปรดจำไว้ว่าโทเค็นนี้เป็นความลับ: ห้ามแบ่งปันให้ผู้อื่นเด็ดขาด หากคุณแบ่งปันให้ใครด้วยเหตุผลใดก็ตาม คุณควรรีบยกเลิกโทเค็นนั้นและสร้างโทเค็นใหม่บน crates.io
การเพิ่มข้อมูลอธิบาย (Metadata) ลงใน Crate ใหม่
สมมติว่าคุณมี crate ที่ต้องการเผยแพร่ ก่อนที่จะเผยแพร่ คุณจะต้องเพิ่มข้อมูลอธิบาย (metadata) บางอย่างลงในส่วน [package] ของไฟล์ Cargo.toml ใน crate นั้น
crate ของคุณจะต้องมีชื่อที่ไม่ซ้ำใคร ขณะที่คุณทำงานกับ crate ในเครื่อง คุณสามารถตั้งชื่อ crate เป็นอะไรก็ได้ตามต้องการ อย่างไรก็ตาม ชื่อ crate บน crates.io จะถูกจัดสรรตามลำดับมาก่อนได้ก่อน (first-come, first-served) เมื่อมีผู้ใช้ชื่อ crate ใดไปแล้ว จะไม่มีใครสามารถเผยแพร่ crate ด้วยชื่อนั้นได้อีก ก่อนที่จะพยายามเผยแพร่ crate ให้ค้นหาชื่อที่คุณต้องการใช้ หากชื่อนั้นถูกใช้ไปแล้ว คุณจะต้องหาชื่ออื่นและแก้ไขฟิลด์ name ในไฟล์ Cargo.toml ภายใต้ส่วน [package] เพื่อใช้ชื่อใหม่สำหรับการเผยแพร่ ดังนี้:
ชื่อไฟล์: Cargo.toml
[package]
name = "guessing_game"
แม้ว่าคุณจะเลือกชื่อที่ไม่ซ้ำใครแล้ว แต่เมื่อคุณรัน cargo publish เพื่อเผยแพร่ crate ในจุดนี้ คุณจะได้คำเตือนแล้วตามด้วยข้อผิดพลาด:
$ 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
ผลลัพธ์นี้ทำให้เกิดข้อผิดพลาดเพราะคุณขาดข้อมูลสำคัญบางประการ: จำเป็นต้องมีคำอธิบาย (description) และใบอนุญาต (license) เพื่อให้ผู้ใช้ทราบว่า crate ของคุณทำอะไรและอยู่ภายใต้เงื่อนไขใดที่พวกเขาสามารถนำไปใช้ได้ ใน Cargo.toml ให้เพิ่มคำอธิบายสั้น ๆ แค่ประโยคสองประโยค เพราะมันจะปรากฏร่วมกับ crate ของคุณในผลการค้นหา สำหรับฟิลด์ license คุณจะต้องให้ค่าระบุใบอนุญาต (license identifier value) โดยรายการ Software Package Data Exchange (SPDX) ของ Linux Foundation จะระบุค่านำทางที่คุณสามารถใช้ได้ สำหรับค่านี้ ตัวอย่างเช่น หากต้องการระบุว่าคุณให้ใบอนุญาต crate ของคุณโดยใช้ใบอนุญาต MIT ให้เพิ่มตัวระบุ MIT:
ชื่อไฟล์: Cargo.toml
[package]
name = "guessing_game"
license = "MIT"
หากคุณต้องการใช้ใบอนุญาตที่ไม่ปรากฏใน SPDX คุณต้องวางข้อความของใบอนุญาตนั้นไว้ในไฟล์ รวมไฟล์นั้นไว้ในโปรเจกต์ของคุณ แล้วใช้ license-file เพื่อระบุชื่อไฟล์นั้นแทนการใช้คีย์ license
คำแนะนำเกี่ยวกับใบอนุญาตใดที่เหมาะสมกับโปรเจกต์ของคุณอยู่นอกเหนือขอบเขตของหนังสือเล่มนี้ หลายคนในชุมชน Rust ให้ใบอนุญาตโปรเจกต์ของตนในลักษณะเดียวกับ Rust โดยใช้ใบอนุญาตแบบคู่คือ MIT OR Apache-2.0 การปฏิบัตินี้แสดงให้เห็นว่าคุณสามารถระบุตัวระบุใบอนุญาตหลายตัวแยกกันด้วย OR เพื่อมีหลายใบอนุญาตสำหรับโปรเจกต์ของคุณได้เช่นกัน
เมื่อมีชื่อที่ไม่ซ้ำกัน เวอร์ชัน คำอธิบายของคุณ และใบอนุญาตถูกเพิ่มเข้ามาแล้ว ไฟล์ Cargo.toml สำหรับโปรเจกต์ที่พร้อมเผยแพร่อาจดูเป็นดังนี้:
ชื่อไฟล์: Cargo.toml
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2024"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
เอกสารของ Cargo ได้อธิบายเกี่ยวกับข้อมูลอธิบายอื่น ๆ ที่คุณสามารถระบุเพื่อให้ผู้อื่นค้นพบและใช้ crate ของคุณได้ง่ายยิ่งขึ้น
การเผยแพร่ไปยัง Crates.io
ตอนนี้เมื่อคุณสร้างบัญชี บันทึกโทเค็น API เลือกชื่อสำหรับ crate ของคุณ และระบุข้อมูลอธิบายที่จำเป็นเรียบร้อยแล้ว คุณก็พร้อมที่จะเผยแพร่แล้ว! การเผยแพร่ crate จะอัปโหลดเวอร์ชันเฉพาะไปยัง crates.io เพื่อให้ผู้อื่นนำไปใช้งาน
โปรดใช้ความระมัดระวัง เพราะการเผยแพร่นั้นเป็นแบบถาวร (permanent) เวอร์ชันนั้นจะไม่สามารถถูกเขียนทับได้ และโค้ดไม่สามารถลบออกได้ เว้นแต่ในสถานการณ์บางอย่าง เป้าหมายหลักประการหนึ่งของ Crates.io คือการทำหน้าที่เป็นคลังจัดเก็บโค้ดแบบถาวร เพื่อให้การบิลด์ของทุกโปรเจกต์ที่พึ่งพา crate จาก crates.io ยังคงทำงานต่อไปได้ การอนุญาตให้ลบเวอร์ชันออกจะทำให้ไม่สามารถบรรลุเป้าหมายนั้นได้ อย่างไรก็ตาม ไม่มีข้อจำกัดเกี่ยวกับจำนวนเวอร์ชันของ crate ที่คุณสามารถเผยแพร่ได้
รันคำสั่ง cargo publish อีกครั้ง ครั้งนี้น่าจะสำเร็จแล้ว:
$ cargo publish
Updating crates.io index
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Packaged 6 files, 1.2KiB (895.0B compressed)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
Uploaded guessing_game v0.1.0 to registry `crates-io`
note: waiting for `guessing_game 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 guessing_game v0.1.0 at registry `crates-io`
ยินดีด้วย! ตอนนี้คุณได้แบ่งปันโค้ดของคุณกับชุมชน Rust เรียบร้อยแล้ว และทุกคนสามารถเพิ่ม crate ของคุณเป็นทรัพยากรภายนอกของโปรเจกต์ของตนได้อย่างง่ายดาย
การเผยแพร่เวอร์ชันใหม่ของ Crate ที่มีอยู่แล้ว
เมื่อคุณทำการเปลี่ยนแปลงใน crate ของคุณและพร้อมที่จะออกเวอร์ชันใหม่ คุณสามารถเปลี่ยนค่า version ที่ระบุไว้ในไฟล์ Cargo.toml ของคุณ แล้วทำการเผยแพร่อีกครั้ง ใช้ กฎการกำหนดเวอร์ชันตามความหมาย (Semantic Versioning rules) เพื่อตัดสินใจว่าหมายเลขเวอร์ชันถัดไปที่เหมาะสมคืออะไร โดยพิจารณาจากชนิดของการเปลี่ยนแปลงที่คุณได้ทำ จากนั้น รันคำสั่ง cargo publish เพื่ออัปโหลดเวอร์ชันใหม่
การยกเลิกใช้งานเวอร์ชัน (Yanking) บน Crates.io
แม้ว่าคุณจะไม่สามารถลบเวอร์ชันก่อนหน้าของ crate ออกได้ แต่คุณสามารถป้องกันไม่ให้โปรเจกต์ในอนาคตเพิ่มเวอร์ชันนั้นเป็นทรัพยากรภายนอกใหม่ได้ สิ่งนี้มีประโยชน์เมื่อเวอร์ชันของ crate เกิดปัญหาด้วยเหตุผลใดก็ตาม ในสถานการณ์เช่นนี้ Cargo รองรับการปลดดึงเวอร์ชัน (yanking) ของ crate
การปลดดึง (yanking) เวอร์ชัน จะป้องกันไม่ให้โปรเจกต์ใหม่ ๆ พึ่งพาเวอร์ชันนั้น ในขณะที่ยังคงอนุญาตให้โปรเจกต์เดิมทั้งหมดที่พึ่งพาเวอร์ชันนั้นสามารถทำงานต่อไปได้ โดยพื้นฐานแล้ว การปลดดึงหมายความว่าโปรเจกต์ทั้งหมดที่มีไฟล์ Cargo.lock จะไม่พัง และไฟล์ Cargo.lock ใด ๆ ที่สร้างขึ้นในอนาคตจะไม่ใช้เวอร์ชันที่ถูกปลดดึงไปแล้ว
ในการปลดดึงเวอร์ชันของ crate ให้ไปที่ไดเรกทอรีของ crate ที่คุณเคยเผยแพร่ไว้ก่อนหน้านี้ แล้วรันคำสั่ง cargo yank โดยระบุเวอร์ชันที่คุณต้องการปลดดึง ตัวอย่างเช่น หากเราเผยแพร่ crate ชื่อ guessing_game เวอร์ชัน 1.0.1 แล้วเราต้องการปลดดึงมันออก เราจะรันคำสั่งต่อไปนี้ในไดเรกทอรีโปรเจกต์สำหรับ guessing_game:
$ cargo yank --vers 1.0.1
Updating crates.io index
Yank guessing_game@1.0.1
การเพิ่ม --undo ลงในคำสั่ง คุณยังสามารถยกเลิกการปลดดึง (unyank) และอนุญาตให้โปรเจกต์ต่าง ๆ เริ่มพึ่งพาเวอร์ชันนั้นได้อีกครั้ง:
$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank guessing_game@1.0.1
การปลดดึง (yank) ไม่ได้ลบโค้ดใด ๆ ออก ตัวอย่างเช่น มันไม่สามารถลบความลับ (secrets) ที่อัปโหลดโดยบังเอิญออกได้ หากเกิดเหตุการณ์เช่นนั้นขึ้น คุณต้องรีเซ็ตความลับเหล่านั้นทันที