Theppitak's blog

My personal blog.

22 พฤษภาคม 2562

Esaan Tones

จาก blog เก่าเรื่อง ไตรยางศ์อยุธยา เมื่อ 7 ปีก่อน ผมทิ้งท้ายไว้ว่าจะเขียนถึงไตรยางศ์อีสานต่อ จนแล้วจนรอดก็หาเวลาเขียนไม่ได้ จนกระทั่งได้ไปร่วม Thailand ICT Camp ที่ชะอำ ซึ่งมีกิจกรรม BarCamp ในวันสุดท้าย ผมไม่เคยร่วม BarCamp มาก่อน แต่ก็ลองเสนอหัวข้อ ไตรยางศ์ไทย-อีสาน ดู พอได้นำเสนอจึงถือโอกาสนำมาเขียนบันทึกต่อเสียเลย

ก่อนอื่นเพื่อเป็นการปูพื้นสำหรับท่านที่ตามมาอ่านจาก BarCamp และไม่เคยอ่าน blog ของผมมาก่อน ผมมีข้อสังเกตถึงความลักลั่นของการสะกดคำของภาษาอีสานอันเนื่องมาจากการขาดหลักไตรยางศ์ที่แน่นอน ทำให้บางคำเขียนรูปวรรณยุกต์เหมือนภาษาไทยกลางแล้วผันเอา ซึ่งมักเป็นคำที่ใช้ร่วมกับไทยกลาง เช่น เขียน หม้อ แล้วผันเป็น [หม่อ] แต่พอเป็นคำที่เป็นคำเฉพาะถิ่น เช่น หม้ำ (ไส้กรอกตับ) ซึ่งออกเสียงว่า [หม่ำ] กลับเขียนแบบแปลงสำเนียงให้คนบางกอกเสร็จสรรพ โดยเขียนเป็น หม่ำ

ปัญหาของการเขียนลักลั่นแบบนี้คือ หลักการอ่านจะไม่แน่นอน เอาหม่ำไปใส่หม้อ ควรอ่านเป็น [เอ่า-มัม^-ไป่-ใซ^-หม่อ] ตามกฎการผันเสียง หรือควรอ่านเป็น [เอ่า-หม่ำ-ไป่-ใซ^-หม่อ] โดยอาศัยความรู้ทางศัพท์แก้เสียงวรรณยุกต์ในระหว่างอ่าน? และเมื่อเด็กอีสานไปเรียนคำใหม่จากหนังสือ เขาจะรู้ได้อย่างไรว่าคำที่เขียนนั้นตั้งใจให้อ่านแบบไทยกลางหรือไทยอีสาน? เช่นคำว่า หล่า ถ้าอ่านแบบไทยกลางเป็น [หล่า] จะหมายถึงคนสุดท้อง แต่ถ้าอ่านแบบไทยอีสานเป็น [ลา^] จะหมายถึงอาการหน้าเจื่อน แล้วเราก็จะกลับไปสู่ยุค หนังสือหนังหา สมัยที่ยังเขียน หนังสือ แบบไม่ใส่วรรณยุกต์ แล้วให้คนอ่านอ่าน หนังหา คือหาเสียงวรรณยุกต์ที่ถูกต้องมาใส่เอาเอง ซึ่งถ้าเป็นเช่นนั้น เราจะใส่วรรณยุกต์ไปทำไมกัน?

รายละเอียดเพิ่มเติมเกี่ยวกับประเด็นการสะกดคำ กรุณาอ่านจาก blog Esaan Language Tidbits

สิ่งที่ควรจะเป็นคือเขียนภาษาเขียนเหมือนไทยกลาง แต่ใช้หลักไตรยางศ์เฉพาะของอีสานในการผันเสียง โดยเขียน หม้ำ แล้วผันเสียงเป็น [หม่ำ] เหมือนที่ผัน หม้อ เป็น [หม่อ] เพื่อที่จะใช้หลักการเดียวในการอ่านข้อความ เอาหม้ำไปใส่หม้อ ตลอดข้อความโดยไม่ต้องมีข้อยกเว้น

ไตรยางศ์ขอนแก่น

หลักไตรยางศ์ที่ว่านั้น ไทยแต่ละถิ่นก็จะมีหลักของตัวเอง ไม่ว่าจะเป็นล้านนา สุพรรณบุรี นครศรีธรรมราช บางกอก ขอนแก่น อุบลฯ เลย ฯลฯ ซึ่งจะทำให้อ่านข้อความเดียวกันที่เขียนด้วยอักษรไทยออกไปได้ตามสำเนียงของถิ่นตน โดยในที่นี้ผมขอพูดถึงสำเนียงขอนแก่นที่เป็นสำเนียงบ้านผมเท่านั้น

สำเนียงขอนแก่น มีวรรณยุกต์ทั้งหมด 5 เสียง

  1. เสียงเอก ตรงกับเสียงเอกในภาษาบางกอก เช่น ในคำว่า กิน ขาด ปาก หม้อ เข้า
  2. เสียงโทต่ำ คล้ายเสียงโทของภาษาบางกอก แต่เสียงต่ำกว่า (ต้นพยางค์เท่า ๆ กับเสียงสามัญของบางกอก แล้วลงต่ำที่ท้ายพยางค์) เช่น ในคำว่า ป้า (น้ำไหล)โจ้ก ค้า เคียด
  3. เสียงสามัญสูง เสียงเป็นระดับเดียวตลอดพยางค์เหมือนเวลาออกเสียงสามัญ แต่เสียงสูงกว่าเสียงสามัญของบางกอก เช่น ในคำว่า เต่า ข่า พ่อ งึด
  4. เสียงโท ตรงกับเสียงโทของภาษาบางกอก เช่น ในคำว่า คา งู มา
  5. เสียงจัตวา ตรงกับเสียงจัตวาของภาษาบางกอก เช่น ในคำว่า ขา กบ เห็ด

การเขียนบรรยายเสียงอ่าน จะมีสองเสียงที่เสียงไม่ตรงกับภาษาบางกอก คือเสียงโทต่ำและสามัญสูง จึงขอเขียนเครื่องหมายพิเศษเพื่อกำกับเสียง โดยเสียงโทต่ำจะเขียนเสียงโทแล้วตามด้วยขีดล่าง (_) เช่น ป้า [ป้า_], โจ้ก [โจ้ก_], ค้า [ค่า_], เคียด [เคียด_] ส่วนเสียงสามัญสูงจะเขียนเสียงสามัญแล้วตามด้วยหมวก (^) เช่น เต่า [เตา^], ข่า [คา^], พ่อ [พอ^] ยกเว้นกรณีที่ไม่สามารถเขียนเสียงสามัญได้ จะเขียนเสียงอื่นโดยอนุโลมแล้วใช้หมวกกำกับเสียง เช่น งึด [งึด^], คัก [คัก^]

หลักการผันวรรณยุกต์

คำเป็น

  • อักษรกลางรูปสามัญ (เช่น กิน) สำเนียงอีสานแต่ละถิ่นจะออกเสียงกันหลากหลาย สำเนียงขอนแก่นผันเป็นเสียงเอก สำเนียงอุบลฯ ผันเป็นเสียงสามัญเหมือนบางกอก (ทำให้สำเนียงอุบลฯ มีเสียงวรรณยุกต์ 6 เสียง เพิ่มเสียงสามัญแบบบางกอกเข้ามาอีกหนึ่ง)
  • อักษรสูงรูปสามัญ (เช่น ขา) ผันเป็นเสียงจัตวาเหมือนบางกอก
  • อักษรต่ำรูปสามัญ (เช่น คา) ผันเป็นเสียงโท
  • รูปเอก (เช่น เต่า ข่า ค่า) ผันเป็นเสียงสามัญสูงทั้งสามหมู่
  • รูปโทสำหรับอักษรกลางและอักษรต่ำ (เช่น ป้า ค้า) ผันเป็นเสียงโทต่ำ
  • รูปโทสำหรับอักษรสูง (เช่น ข้า) ผันเป็นเสียงเอก
  • รูปตรีและจัตวาสำหรับอักษรกลาง (เช่น ป๊า โป๊ ป๋า) ไม่มีในคำอีสาน เป็นการยืมจากภาษาบางกอก จึงใช้วิธีเทียบเสียงกับหมู่อื่น เช่น โป๊ [โป้_] เทียบกับเสียงตรีของอักษรต่ำ (เช่น ค้า) แต่ ป๊า [ปา^] ออกเป็นสามัญสูงเพื่อเลียนเสียงตรีของบางกอก ส่วนรูปจัตวา ผันเป็นเสียงจัตวาตรงตัว เช่น ป๋า [ป๋า]

คำตายสระเสียงยาว

  • รูปสามัญสำหรับอักษรกลางและสูง (เช่น เกิบ ขาด) ผันเป็นเสียงเอกเหมือนบางกอก
  • รูปสามัญสำหรับอักษรต่ำ (เช่น เคียด) และรูปโทสำหรับอักษรกลาง (เช่น โจ้ก) ผันเป็นเสียงโทคล้ายบางกอก แต่ระดับเสียงเป็นโทต่ำ
  • รูปโทสำหรับอักษรสูง ไม่พบคำที่สะกดจริง แต่สามารถเทียบกับการผันเป็นเสียงโทของบางกอกได้ แต่ระดับเสียงเป็นโทต่ำ
  • รูปตรีสำหรับอักษรกลาง (เช่น โจ๊ก) และรูปโทสำหรับอักษรต่ำ (เช่น โค้ก) เป็นคำยืมจากภาษาบางกอก จึงเลียนเสียงตรีของบางกอกด้วยเสียงสามัญสูง
  • รูปจัตวาสำหรับอักษรกลาง ไม่พบคำที่สะกดจริง แต่สามารถเทียบกับการผันเป็นเสียงจัตวาของบางกอกได้ และออกเป็นเสียงจัตวาตรงตัว

คำตายสระเสียงสั้น

  • รูปสามัญสำหรับอักษรกลาง (เช่น จก) และอักษรสูง (เช่น ขัด) ผันเป็นเสียงจัตวา
  • รูปสามัญสำหรับอักษรต่ำ (เช่น งึด) ผันเป็นเสียงตรีคล้ายหลักของบางกอก แต่ออกเสียงเป็นสามัญสูง
  • รูปเอกสำหรับอักษรต่ำ (เช่น ค่ะ) เป็นคำยืมจากภาษาบางกอก และผันเป็นเสียงโทเหมือนบางกอก
  • รูปโทสำหรับอักษรกลาง (เช่น จึ้ก) ผันเป็นเสียงโทคล้ายหลักของบางกอก แต่ระดับเสียงเป็นโทต่ำ
  • รูปโทของอักษรสูง ไม่พบคำที่สะกดจริง แต่สามารถเทียบกับการผันเป็นเสียงโทของบางกอกได้ แต่ระดับเสียงเป็นโทต่ำ
  • รูปตรีของอักษรกลาง (เช่น กั๊ก) เป็นคำยืมจากภาษาบางกอก และเลียนเสียงตรีของบางกอกด้วยเสียงสามัญสูง
  • รูปจัตวาสำหรับอักษรกลาง ถือว่าเสียงซ้ำกับรูปสามัญ ไม่ควรมีรูปเขียน แต่ถ้าให้ออกเสียง ก็ออกเป็นเสียงจัตวา

รูปสะกดที่คลาดกับไทยกลาง

หลักไตรยางศ์ข้างต้นสามารถใช้ได้กับทุกกรณี แต่คนอีสานอาจสังเกตพบบางคำที่เสียงอ่านไม่เป็นไปตามกฎนี้ เช่น น้ำท่วม [น่าม_-ถ่วม ไม่ใช่ น่าม_-ทวม^], คอยท่า [ค่อย-ถ่า ไม่ใช่ ค่อย-ทา^], ฆ่างัว [ข่า-งั่ว ไม่ใช่ คา^-งั่ว] ฯลฯ ทั้งนี้เป็นเพราะวิวัฒนาการของการสะกดคำของบางกอกได้เลือกเอาตัวสะกดที่ไม่ตรงกับอีสานไว้ กล่าวคือ:

  • น้ำท่วม ภาษาลาวปัจจุบันใน สปป. ลาวสะกดคำนี้ว่า ນ້ຳຖ້ວມ (น้ำถ้วม) ซึ่งเมื่อผันตามหลักไตรยางศ์ข้างต้นจะออกเสียงได้เป็น [น่าม_-ถ่วม] ตรงตามความเป็นจริง
  • คอยท่า ภาษาลาวปัจจุบันใน สปป. ลาวสะกดคำนี้ว่า ຄອຍຖ້າ (คอยถ้า) ซึ่งผันเสียงเป็น [ค่อย-ถ่า] ตามภาษาที่พูดกัน
  • ฆ่าวัว ภาษาลาวปัจจุบันใน สปป. ลาวสะกดคำนี้ว่า ຂ້າງົວ (ข้างัว) โดยคำว่า ฆ่า นี้ จารึกสุโขทัยเองก็สะกดว่า ฃ้า (ซึ่งใช้ ฃ ขวด เป็นคนละคำกับ ข้า ที่หมายถึงผู้อยู่ใต้ปกครอง) ต่อมาจึงได้วิวัฒน์การสะกดเป็น ฆ่า ในภายหลัง (อ่านเพิ่มเติมได้ใน blog เก่า)

ยังมีคำอื่น ๆ ในทำนองนี้ เช่น ໜ້າຮັກ (หน้าฮัก = น่ารัก), ຫຼິ້ນ (หลิ้น = เหล้น = เล่น) ซึ่งทำให้เห็นว่าการเสาะหาตัวสะกดที่สูญหายไปของภาษาอีสานอาจหาได้จากแหล่งใกล้เคียงคือภาษาลาวใน สปป. ลาวนั่นเอง

ย ยุง กับ ย ยา

อีกประเด็นหนึ่งที่สร้างความสับสนให้กับผู้ฝึกภาษาอีสานได้ไม่น้อยคือความแตกต่างระหว่าง ຍ ຍຸງ (ย ยุง) กับ ຢ ຢາ (ย ยา) ที่ผันวรรณยุกต์คนละแบบ เพราะ ຍ ຍຸງ นั้นนับเป็นอักษรต่ำ (เดี่ยว, นาสิก) ในขณะที่ ຢ ຢາ จะเทียบเท่ากับ อ นำ ย ในภาษาไทย และผันอย่างอักษรกลาง ซึ่งภาษาไทยปัจจุบันเหลือคำที่ใช้ อ นำ ย อยู่แค่ 4 คำ คือ อย่า อยู่ อย่าง อยาก แต่ในภาษาลาวและอีสานยังคงรักษาคำไว้มากกว่านั้น ตัวอย่างเช่น

  • ຢືນ (อยืน) [หยื่น] หมายถึงอาการตั้งตัวตรงบนพื้น ซึ่งจารึกสุโขทัยก็สะกดว่า อยืน จนต่อมาวิวัฒน์เหลือ ยืน และกลายเป็นคำพ้องรูปกับ ยืน ที่หมายถึงความยาวนาน เช่นในคำว่า ยั่งยืน แต่ในภาษาลาวยังคงสะกดคำหลังนี้ต่างกันเป็น ຍືນ (ยืน) โดยใช้ ຍ ຍຸງ
    ดังนั้น ชื่ออำเภอ พระยืน [พะ^-หยื่น] จึงผันวรรณยุกต์ต่างจากชื่ออำเภอ เชียงยืน [เซี่ยง-ญื่น]
  • ຢາງ (อยาง) [หย่าง] ใน ยางพารา [หย่าง-พ่า-ล่า] และ ยางรถยนต์ [หย่าง-ลด^-ญ่น] ก็ผันวรรณยุกต์ต่างจาก ຍາງ (ยาง) [ญ่าง] ใน ต้นยางนา [ต้น_-ญ่าง-น่า]
  • ຢາຍ (อยาย) [หย่าย] ที่หมายถึงการกระจายข้าวของ ก็ผันวรรณยุกต์ต่างจาก ຍາຍ (ยาย) [ญ่าย] ที่หมายถึงแม่ของแม่

ป้ายกำกับ:

02 มกราคม 2562

New Year Thanks

สวัสดีปีใหม่ 2562 ครับ ขอถือโอกาสนี้ ขอบคุณ ทุกท่านที่ได้ สนับสนุน งานพัฒนาซอฟต์แวร์เสรีของผมในปีที่ผ่านมาครับ

นับจาก ครั้งที่แล้ว ขอขอบคุณผู้สนับสนุนงานพัฒนาของผมในช่วงครึ่งหลังของปี 2561 ดังนี้:

  • เดือนสิงหาคม 2561
    • ผู้ไม่ประสงค์จะออกนาม 2 ท่าน
    • คุณวิทยา ไตรสารวัฒนะ
  • เดือนกันยายน 2561
    • ผู้ไม่ประสงค์จะออกนาม 1 ท่าน
  • เดือนตุลาคม 2561
    • คุณวิทยา ไตรสารวัฒนะ
  • เดือนพฤศจิกายน 2561
    • ผู้ไม่ประสงค์จะออกนาม 1 ท่าน
  • เดือนธันวาคม 2561
    • ผู้ไม่ประสงค์จะออกนาม 1 ท่าน
  • เดือนมกราคม 2562 (นับถึงวันที่ 2)
    • ผู้ไม่ประสงค์จะออกนาม 1 ท่าน

ขอให้ทุกท่านและครอบครัวมีความสุขกายสบายใจ มีพลังอันเต็มเปี่ยมที่จะสร้างสรรค์งานของท่านให้เจริญรุดหน้า และที่สำคัญคือขอให้มีสุขภาพพลานามัยที่สมบูรณ์แข็งแรงครับ

สรุปกิจกรรมซอฟต์แวร์เสรีในครึ่งหลังของปี 2561 ของผม:

  • LibThai:
    • ออกรุ่น 0.1.28
    • อัปเดต TeX hyphenation patterns ตามพจนานุกรมใหม่ของ LibThai
  • swath:
    • อัปเดตพจนานุกรมตัดคำตาม TeX hyphenation patterns ใหม่
    • ตรวจพบและแก้ปัญหาใน RTF filter
    • ออกรุ่น 0.6.1
  • libdatrie (ยังไม่ release):
  • พัฒนาและ release โครงการ thpronun
  • โครงการอักษรอีสาน:
    • ย้ายโครงการ Khottabun จาก SourceForge มายัง GitHub
    • เพิ่มฟอนต์ Viravong สำหรับเขียนบาลี-สันสกฤตด้วยอักษรลาวร่วมสมัย ตามแบบพุทธบัณฑิตสภาจันทบุรี ตามร่างข้อเสนอยูนิโค้ด โดยเป็นส่วนหนึ่งของโครงการ Khottabun (ผ่านการประสานงานจากพระอาจารย์ไชยศิริ)
    • เพิ่ม input method สำหรับป้อนภาษาบาลีอักษรลาวในโครงการ lanxang
  • Fonts-TLWG:
    • ปรับซอร์สเพื่อให้สามารถ build แบบ reproducible
    • แก้ปัญหาใน GSUB
    • จัดเตรียมฟอนต์ OpenType สำหรับ XeTeX
    • automate การ build binary font tarballs
    • ออกรุ่น 0.7.0 และ 0.7.1
  • Fonts-Arundina (ยังไม่ release):
  • Debian package ต่าง ๆ :
    • ทยอยปรับโครงสร้าง Git repository ตาม DEP-14
  • อัปเดตแผนที่ OpenStreetMap ในบริเวณตัวเมืองขอนแก่น, กรุงเทพฯ, และอำเภอวาปีปทุม จังหวัดมหาสารคาม
  • ปรับคำแปล Xfce เป็นระยะ

ป้ายกำกับ:

06 พฤศจิกายน 2561

Fonts-TLWG 0.7.0 and 0.7.1

Fonts-TLWG 0.7.0 ออกไปแล้วเมื่อปลายตุลาที่ผ่านมา หลังจากสะสมงานพัฒนามาได้ครึ่งปี โดยมีการเปลี่ยนแปลงตามลำดับเวลาดังนี้:

  • Issue #7: แก้ที่ผิดใน GSUB rules ของทุกฟอนต์ซึ่งทำให้แสดงข้อความที่มีพินทุตามด้วย Macron Below เป็นพินทุซ้อนกันสองตัว ปัญหาเกิดจากข้อผิดพลาดในกฎจัดการลำดับ คุณ @Richard57 ได้รายงานเข้ามาพร้อมวิเคราะห์สาเหตุให้ด้วย
  • Norasi:
    • แก้ warning จาก Fontforge เกี่ยวกับการอ้างถึง glyph ที่ไม่มีในฟอนต์ในกฎ 'liga'
    • แก้กฎ 'liga' ให้รองรับลำดับ space + combining character ในทุกกรณี
    • ตัดกฎ T + M → ™ เพื่อไม่ให้รบกวนกรณีที่ไม่ใช่ เช่น ATM
  • Issue #6: จัดเตรียมฟอนต์ OpenType ในแพกเกจ LaTeX (fonts-tlwg) ตามคำแนะนำของคุณ Abhabongse Janthong เพื่อให้บริการอย่าง ShareLaTeX และ Overleaf สามารถใช้ฟอนต์ไทยกับ XeLaTeX ได้โดยไม่ต้องอัปโหลดฟอนต์ร่วมกับเอกสาร ซึ่งข้อนี้ผมคิดไม่ถึง เพราะคิดแค่กรณีของผู้ใช้ XeTeX ในเครื่องส่วนตัว ซึ่งสามารถใช้ฟอนต์จากระบบได้อยู่แล้ว แต่สำหรับบริการออนไลน์ หรือแม้แต่เครื่องที่ผู้ใช้ไม่มีสิทธิ์ติดตั้งฟอนต์ในระบบแล้ว การจัดเตรียมฟอนต์ OpenType มากับชุด TeX distribution เลยย่อมอำนวยความสะดวกได้ดีกว่า
  • จัดการเรื่อง reproducibility ของการ build ฟอนต์ หลังจากที่ Debian รายงานมานาน และเขาได้ข้อยุติเรื่องการแก้ปัญหาใน Fontforge กันไปแล้ว โดยที่ Fonts-TLWG ของเราก็ยังไม่ reproducible อยู่ดี จึงคิดว่าควรได้ฤกษ์จัดการในฝั่งของเราเสียที ซึ่งในการแก้ก็ต้องจัดโครงสร้างของซอร์สและการ build ใหม่ จึงได้ขึ้นเลขรุ่นเป็น 0.7.x

หลังจาก อัปโหลด แพกเกจเข้า Debian ไปแล้ว ก็รอตรวจสอบหน้า reproducible build ของ fonts-tlwg ใน unstable ปรากฏว่ายังไม่ผ่าน ยังคงมีประเด็นตกค้างอยู่ ซึ่งเมื่อตรวจสอบ diff ดูแล้ว พบว่ามาจาก date stamp ที่เกิดจากฟิลด์ UniqueID ใน TTF Names ที่ Fontforge เติมให้โดยอัตโนมัติสำหรับฟอนต์ที่ไม่ได้จัดเตรียมไว้

(สังเกตที่คำว่า date stamp ซึ่งเป็นสาเหตุที่ทำให้มันหลุดรอดการทดสอบก่อนออกรุ่น 0.7.0 เพราะผมไม่ได้ทดสอบแบบข้ามวัน ทดสอบกี่รอบ date stamp มันก็ไม่เปลี่ยน)

Fonts-TLWG 0.7.1 จึงเกิดขึ้นตามมาเพื่ออุดช่องโหว่ดังกล่าว โดยเติมฟิลด์ UniqueID ใน TTF Names ให้ครบทุกฟอนต์เสีย

ขณะเดียวกัน เป็นธรรมเนียมของ Fonts-TLWG ที่จะ release พร้อมกับฟอนต์ OTF, TTF, WOFF ที่ build สำเร็จรูปแล้ว นอกเหนือจากซอร์สของฟอนต์ เพื่ออำนวยความสะดวกผู้ใช้ฟอนต์ทั่วไปที่ไม่สะดวกจะ build ฟอนต์เอง ซึ่งในทุกรุ่นที่ผ่านมา ผมสร้าง tarball เหล่านี้แบบ manual ด้วยการ configure และ build สามแบบเพื่อเก็บเข้า tarball ทีละก้อน ซึ่งถ้านาน ๆ ทำทีก็ไม่รู้สึกลำบาก แต่พอออกรุ่นนี้ไล่หลังรุ่นที่แล้วแบบค่อนข้างกระชั้นชิด เลยรู้สึกว่ามันควร automate มาตั้งนานแล้ว

จึงได้เป็น automation สำหรับการ build font tarballs โดยอิงอาศัย make rule ชุดเดิมที่เคยใช้ build ZIP file สำหรับ CTAN upload

พร้อมกันนี้ ในรุ่นนี้ผมเริ่มเผยแพร่ฟอนต์สำเร็จรูปในรูปแบบ ZIP file นอกเหนือจาก tarball ด้วย เพื่อส่งเสริมการใช้งานในวินโดวส์หรือแฟลตฟอร์มอื่นด้วย เพราะที่ผ่านมา Fonts-TLWG ถูกมองจากผู้ใช้ทั่วไปว่าเป็น ฟอนต์สำหรับ LaTeX บ้าง ฟอนต์สำหรับลินุกซ์ บ้าง ทั้งที่มันใช้ได้ในแพลตฟอร์มทั่วไป

upload เข้า Debian แล้ว ต่อไปก็รอดู reproducibility test ต่อไป

ทางด้าน CTAN ก็ได้ upload ไล่หลัง Debian แล้วทั้งสองรุ่น

ป้ายกำกับ: ,

21 ตุลาคม 2561

Reproducible Fonts-TLWG

ความเปลี่ยนแปลงล่าสุดใน Fonts-TLWG คือเรื่อง reproducibility คือการ build ที่ให้ผลลัพธ์เป็น binary file ที่เป็นข้อมูลเดิมทุกบิตทุกครั้งที่ build โดยไม่ขึ้นกับสภาวะที่ใช้ในการ build

สำหรับฟอนต์จากโครงการ Fonts-TLWG มีปัญหา reproducibility ตามที่รายงานโดย Debian คือ modification timestamp ที่เกิดจาก Fontforge script ที่ใช้ build โดยมีการเปลี่ยนแปลงข้อมูลของฟอนต์ระหว่างทาง ทำให้ timestamp ของการเปลี่ยนแปลงถูกปรับเป็นเวลาขณะ script ทำงานนั้น และทำให้ข้อมูลฟอนต์ผลลัพธ์แปรเปลี่ยนไปตามเวลาที่ build

Modification กลางอากาศ

script ที่ใช้ generate ฟอนต์ชนิดต่าง ๆ จะมีการเปลี่ยนแปลงข้อมูลฟอนต์กลางอากาศขณะ build ดังนี้

  • OTF และ WOFF จะมีการตัด PUA glyphs สำหรับสระบน-ล่างและวรรณยุกต์ที่เลื่อนหลบหางพยัญชนะ
  • TTF มีการแปลง cubic spline เป็น quadratic ก่อน apply AutoInstr
  • LaTeX fonts (Postscript + TeX virtual fonts) จะไม่มี modification ใด ๆ

PUA Glyphs

PUA (Unicode Private Use Area) glyphs สำหรับสระบน-ล่างและวรรณยุกต์ที่เลื่อนหลบหางพยัญชนะ เป็นสิ่งจำเป็นสำหรับการ render ข้อความในสภาวะที่ไม่มีเทคโนโลยี OpenType เช่น บน Windows XP และการใช้ virtual font ใน TeX engine เก่า (เช่น pdfTeX) ซึ่งเราได้ตัดสินใจยกเลิกการรองรับ TTF แบบเก่าไปนานแล้ว แต่ยังไม่สามารถตัดการรองรับ TeX engine เก่าได้ จึงยังคง PUA glyphs ไว้ใน source ของฟอนต์ แต่ใช้วิธีลบกลางอากาศขณะ gen OTF และ TTF เอา

แต่การลบ glyph กลางอากาศนี่เองที่เป็นสาเหตุหนึ่งที่ทำให้ modification timestamp ของฟอนต์เปลี่ยน และทำให้ได้ไฟล์ฟอนต์ที่ไม่ reproducible

วิธีแก้ปัญหาก็เป็นไปได้สองทาง:

  1. ไม่ต้องตัด PUA glyphs เลย ใส่เกินไว้ในฟอนต์อย่างนั้นแหละ การมีอยู่ของ OpenType tables ต่าง ๆ จะทำให้ shaping engine อย่าง Harfbuzz ไม่ fallback มาใช้ PUA shaping เมื่อเจอ PUA glyphs ในฟอนต์
  2. ตัด PUA glyphs ออกจาก source ไปเลย ซึ่งจะหมายถึงการตัดการรองรับ shaping ผ่าน TeX virtual font ด้วย ผลคือ ตัดการรองรับ pdfTeX ไปเลย และหยุดอัปเดตแพกเกจ fonts-tlwg บน CTAN ไปเสีย

ทางเลือก 2 ดูจะเป็นเรื่องใหญ่ ผมคิดว่าควรชะลอไปก่อน และเลือกทางเลือก 1 ไว้ก่อน และได้ commit ไปตามนี้

TrueType Instructions

เพื่อเพิ่ม hint ให้กับฟอนต์ TrueType ในขณะที่ source ของเราอยู่ในรูป cubic spline ตัว script จึงใช้วิธีแปลง spline ให้เป็น quadratic ก่อน แล้ว apply AutoInstr กลางอากาศก่อน generate TTF

ซึ่งการแปลงและสั่ง AutoInstr ทำให้ modification timestamp ของฟอนต์เปลี่ยน ทำให้ได้ไฟล์ฟอนต์ที่ไม่ reproducible อีกเช่นกัน

ผมค้นคิดวิธีที่จะแก้ปัญหานี้ไปเรื่อย ๆ จนในที่สุดก็ได้ไอเดียการทำ mixed layers โดยมีหลักการคือ:

  • เพิ่ม layer ที่สี่ในไฟล์ SFD เป็นชนิด quadratic แล้ว copy spline ทั้งหมดจาก Front Layer ซึ่งเป็น cubic มายัง qudratic layer นี้ ซึ่ง Fontforge จะแปลง spline ให้ขณะ copy
  • เราสามารถแก้ไข quadratic spline ใน layer ใหม่นี้ได้ หรือหากต้องการ fine-tune TrueType instructions ก็ทำได้ แต่ในเบื้องต้นนี้ยังไม่ edit ใด ๆ และใช้ AutoInstr ไปก่อน
  • ในการ generate TTF ใน dialog box จะสามารถเลือกให้ generate จาก quadratic layer แทน Front Layer ได้ และใน script อัตโนมัติก็สามารถกำหนด layer ที่จะใช้ได้เช่นกัน เพียงแต่การเลือก layer ยังไม่รองรับใน Fontforge native script ด้วยข้อจำกัดเรื่อง syntax แต่ใน Python script สามารถทำได้

เมื่อได้หลักการเช่นนี้แล้ว ก็ได้แตก branch mixed-layer-ttf เพื่อดำเนินการ โดยตั้งชื่อ quadratic layer ให้เหมือนกันทุกฟอนต์ว่า Quad เพื่อจะได้ใช้ชื่อนี้ใน script ให้ทำงานได้ทุกฟอนต์ และเปลี่ยนมาใช้ Python script สำหรับ TTF แทน native script เดิม

ด้วยหลักการเช่นนี้ source สำหรับ TTF ก็จะเตรียมพร้อมอยู่ใน source สำหรับ generate ได้โดยไม่ต้องแก้ไขกลางอากาศอีก

ทำเสร็จหมดแล้ว ก็ merge เข้า master เสีย เป็นอันเสร็จพิธี

ส่วน LaTeX fonts ไม่มีประเด็นอะไรต้องแก้ ผลคือ ขณะนี้ fonts-tlwg สามารถ build แบบ reproducible ได้ทั้งหมดแล้ว

อนาคต

ประเด็นที่น่าจะทำในอนาคต:

  • ตัดสินใจว่าจะทำอย่างไรกับ PUA glyphs เช่น
    • หาวิธี ข้าม PUA glyphs ขณะ generate โดยไม่ต้องลบ glyph เพื่อจะได้หลีกเลี่ยง modification timestamp
    • ตัด PUA glyphs ออกจาก source เลยไหม? ซึ่งจะหมายถึงการตัดการรองรับ shaping ผ่าน TeX virtual font สำหรับ engine เก่าอย่าง pdfTeX ด้วย
  • Quad layer ที่เกิดขึ้นได้ให้อิสระในการปรับแต่ง TrueType spline และ instruction แล้ว สามารถ fine-tune ต่อไปในอนาคตได้

ป้ายกำกับ: , ,

29 สิงหาคม 2561

thpronun

ประกาศเปิดตัวโครงการ thpronun ซึ่งเป็นซอฟต์แวร์เสรีสำหรับวิเคราะห์เสียงอ่านของข้อความภาษาไทย (grapheme-to-phoneme) ภายใต้การสนับสนุนของ บริษัท เมตามีเดีย เทคโนโลยี จำกัด

ซอฟต์แวร์เสรีที่สนับสนุนโดยเอกชน

เรื่องของเรื่องคือ ผมได้รับการติดต่อว่าจ้างจากเมตามีเดียให้พัฒนาโปรแกรมสำหรับแจงคำอ่านจากตัวสะกดของคำไทย ผมจึงได้เสนอที่จะขายไลเซนส์ของตัวโปรแกรมให้ในแบบ GPL ซึ่งปรากฏว่าเมตามีเดียรับข้อเสนอนี้ และยินดีให้เผยแพร่ซอร์สโค้ดของโปรแกรมสู่สาธารณะได้ โดยมุ่งหวังให้เป็น deal ตัวอย่างในเมืองไทยที่นักพัฒนาซอฟต์แวร์เสรีจะสามารถสร้างรายได้จากตัวซอฟต์แวร์โดยตรง จึงขอขอบคุณเมตามีเดียมา ณ ที่นี้

เมื่อได้ข้อตกลงแล้ว ผมจึงนั่งร่างโปรแกรมใน local Git จนโปรแกรมพร้อมทดสอบ จึงได้หารือเรื่อง repository ที่จะใช้ส่งโค้ดระหว่างกัน ซึ่งคุณภัทระก็เสนอให้ใช้ tlwg บน GitHub ไปเลย ดังนั้น TLWG จึงได้เกิดโครงการน้องใหม่คือ thpronun ด้วยประการฉะนี้

นอกจากนี้ ในระหว่างการพัฒนา ก็ได้รับ contribution ใน libthai 0.1.28 เป็นอานิสงส์ด้วย

สัญญาว่าจ้างสิ้นสุดลงเมื่อผมออกรุ่นแรกสู่สาธารณะ (คือ รุ่น 0.2.0) หลังจากนี้ไปก็จะพัฒนาในแบบชุมชนโอเพนซอร์สตามปกติ ส่วนเมตามีเดียก็จะมี customization เชิงพาณิชย์สำหรับลูกค้าต่อไป

ลักษณะของโปรแกรม

ตัวโปรแกรมเป็นคำสั่ง command line รับข้อมูลเข้าเป็นข้อความภาษาไทย แล้วจะให้ข้อมูลออกเป็นคำอ่านที่เป็นไปได้ทั้งหมดของข้อความนั้น โดยสามารถเลือกรูปแบบของคำอ่านได้จาก command-line option

$ thpronun --help
Usage: thpronun [OPTION] [WORD...]

Thai word pronunciation program.

It reads Thai words from command-line arguments, or from standard input
if no argument is given, and generates all possible pronunciations
of the words.

Options:

General:
  -V, --version  Displays program version info
  -h, --help     Displays help
  -d<DICTPATH>   Use exception dict from <DICTPATH>
  -n             Turns off word segmentation

Output structures:
  -j             Turns on JSON output
  -g             Turns on grouping in JSON output (implies '-j')

Output notations:
  -r             Outputs Romanization
  -t             Outputs Thai pronunciation
  -p             Outputs Phonetic form
  -w             Outputs Raw pronunciation code
  -s             Outputs Soundex code

ตัวอย่างคำอ่านภาษาไทย:

$ thpronun -t เถลไถล
เถลไถล:
ถะ-เหฺล-ถะ-หฺลัย
เถน-ถะ-หฺลัย
เถ-ละ-ถะ-หฺลัย

Romanization:

$ thpronun -r เถลไถล
เถลไถล:
thalethalai
thenthalai
thelathalai

phonetic:

$ thpronun -p เถลไถล
เถลไถล:
thah1 ley4 thah1 lahy4
theyn4 thah1 lahy4
they4 lah3 thah1 lahy4

soundex:

$ thpronun -s เถลไถล
เถลไถล:
Ta_-le_-Ta_-lay
Ten-Ta_-lay
Te_-la_-Ta_-lay

หรือกระทั่ง raw code ตามที่เก็บในโปรแกรม:

$ thpronun -w เถลไถล
เถลไถล:
T_a_1@-3,l_E_4@3,T_a_1@-306,l_ay4@6
T_En4@3,T_a_1@-306,l_ay4@6
T_E_4@2,l_a_3@3,T_a_1@-306,l_ay4@6

กลไกภายใน

ตัวโปรแกรมพัฒนาด้วย C++14 (ควรคอมไพล์ด้วย GCC 6.1 ขึ้นไป หรือ Clang 3.4 ขึ้นไป) ซึ่งมีสิ่งอำนวยความสะดวกครบครันอย่างที่ภาษาโปรแกรมในยุคนี้ควรมี ทำให้ได้โค้ดที่กระชับและใช้เวลาพัฒนาไม่นานเกินไป โดยเฉพาะเมื่อเทียบกับ C++ สมัยก่อน ๆ

build-dependencies:

  • libthai สำหรับแยกแยะอักขระภาษาไทยและแบ่งคำ
  • libdatrie สำหรับจัดการพจนานุกรมคำยกเว้น
  • help2man สำหรับสร้าง man page อัตโนมัติ (ปิดใช้ได้ด้วย configure option --disable-man)

กลไกภายใน ใช้ hard-coded rule base แบบดิบ ๆ เลย ซึ่งมีข้อดีคือไม่ต้องเสียเวลาเตรียม corpus และสามารถปรับแก้กฎต่าง ๆ ได้ตามต้องการภายในกำหนดเวลาพัฒนาที่มี แต่ข้อเสียนอกเหนือจากเรื่อง human error ที่ต้องตามแก้ในกฎก็คือ ไม่สามารถให้น้ำหนักคำอ่านแต่ละแบบตามความน่าจะเป็นได้ ซึ่งเผอิญว่าโจทย์ที่ต้องการคือการค้นฐานข้อมูล ไม่ใช่การสังเคราะห์เสียงพูดที่ต้องเลือกคำอ่านเพียงแบบเดียว จึงยังพอกล้อมแกล้มได้

เมื่อแจงรูปแบบพยางค์ของ input ด้วยกฎแล้ว ก็จะได้ abstract representation ของคำอ่าน ซึ่งสามารถใช้ polymorphism ในการ generate รูปแบบคำอ่านสุดท้ายที่ต้องการ ไม่ว่าจะเป็น romanization, คำอ่านเรียงพยางค์ด้วยอักษรไทย, คำอ่านแบบ phonetic หรือกระทั่ง soundex

องค์ประกอบหลักของแต่ละพยางค์ประกอบด้วย:

  1. เสียงพยัญชนะต้น
  2. เสียงพยัญชนะควบกล้ำ (ถ้ามี)
  3. เสียงสระ
  4. เสียงพยัญชนะสะกด
  5. เสียงวรรณยุกต์

นอกจากนี้ ยังมี requirement เพิ่มเติมจากเมตามีเดียที่ต้องการให้จัดโครงสร้างข้อมูลเป็น lattice โดยแทนที่จะ enumerate คำอ่านทุก combination เป็น list เส้นตรง ก็ให้จัดเป็น lattice โดยแยกเส้นทางคำอ่านเฉพาะในช่วงที่อ่านได้หลายแบบ แล้ว merge กลับเมื่อถึงจุดร่วม โดยให้จัดรูปแบบ output เป็น nested list ของ JSON (ไม่เกิน 2 ชั้น)

$ thpronun -t -g เถลไถล
เถลไถล:
[[[["เถ","ละ"],["เถน"],["ถะ","เหฺล"]],[["ถะ","หฺลัย"]]]]

โครงสร้างดังกล่าวสามารถแทนได้ด้วย Directed Acyclic Graph (DAG) โดยแต่ละ vertex ของกราฟแทนตำแหน่งอักขระจบพยางค์ในข้อความ input และแต่ละ edge แทนเสียงอ่านที่เกิดขึ้นระหว่างตำแหน่งที่มันเชื่อมโยง

ด้วย requirement นี้ ทำให้ทุกฟีเจอร์ที่จะเพิ่มต้องคำนึงถึงการแปลงเข้าสู่ DAG และการทำ output grouping เสมอ จึงต้องเพิ่มข้อมูลตำแหน่งอักขระจบพยางค์เป็นองค์ประกอบที่หกของทุกพยางค์ด้วย โดยบางพยางค์ที่เพิ่มเข้ามาเพราะหลักอักษรนำ (เช่น ถะ ใน เถล และ ไถล ข้างต้น) ต้องแทนด้วยเลขลบที่ encode ขอบเขตพยางค์ที่มันเกาะอยู่ไปด้วยในเวลาเดียวกัน (ในทางเทคนิค สูตรที่ใช้คือ -(ตำแหน่งต้นพยางค์ * 100 + ตำแหน่งท้ายพยางค์))

ข้อยกเว้น

กฎที่ใช้แจงพยางค์จะพยายามครอบคลุมพยางค์ทั่ว ๆ ไป แต่จะไม่เจาะจงข้อยกเว้นบางอย่าง เช่น ทร ที่อ่านเป็น ซ, ฑ นางมณโฑ ที่อ่านเป็น ด, เสียงวรรณยุกต์ของคำแผลง (เช่น กำเนิด, ตำรวจ), การันต์ซับซ้อน (เช่น กษัตริย์, สิริกิติ์, รามเกียรติ์, สุรเกียรติ์) ฯลฯ ซึ่งกรณีเหล่านี้จะจัดการด้วยพจนานุกรมคำยกเว้น (exception dictionary) เพราะการพยายามรวมในกฎจะทำให้เกิด noise เป็นคำอ่านที่ผิดเจือปนเข้ามาโดยไม่จำเป็นสำหรับกรณีทั่วไป

โดยปกติ thpronun จะมีพจนานุกรมคำยกเว้นมาให้อยู่แล้ว แต่คุณก็สามารถสร้างพจนานุกรมคำยกเว้นเองได้ โดยดัดแปลงจากไดเรกทอรี data/ ใน source tree และใช้ตัวเลือก -d<DICTPATH> ใน command line เพื่อระบุพจนานุกรมคำยกเว้น

เนื้อหาของพจนานุกรม จะ map จากตัวสะกดคำไทยไปเป็นคำอ่านในรูป raw code ซึ่งเป็นรูปแบบภายในของโปรแกรมที่แสดงจากตัวเลือก -w เช่น:

ทรง s_og0@3
ทรัพย์ s_ap3@6

การแบ่งคำ

ในกรณีทั่วไป การแบ่งคำข้อความก่อนแจงพยางค์ก็ช่วยลดจำนวนคำอ่านที่เป็นไปได้ลงได้มาก โดยปกติ thpronun จึงเรียกใช้ LibThai เพื่อแบ่งคำก่อน แต่ในบางกรณี การแบ่งคำก็อาจตัดคำอ่านที่ควรจะเป็นออกไปได้ เช่น ในกรณีของคำที่ไม่อยู่ในพจนานุกรมของ LibThai เอง ในกรณีเช่นนั้น คุณก็สามารถปิดการแบ่งคำก่อนได้ โดยใช้ตัวเลือก -n ใน command line

ป้ายกำกับ:

23 สิงหาคม 2561

LibThai 0.1.28 and its Consequences

บันทึกการเปลี่ยนแปลงต่าง ๆ ที่มาใน LibThai 0.1.28 และผลพวงทั้งหลายหลังจากนั้น

LibThai 0.1.28 ออกไปตั้งแต่ต้นเดือน โดยรุ่นนี้มีรายการเปลี่ยนแปลงสำคัญ ๆ คือ:

  • แก้ปัญหาขาด header <thai/thwchar.h> ใน header ที่เกี่ยวกับฟังก์ชัน wide char หลาย ๆ ตัว เช่น thwbrk.h, thwcoll.h ฯลฯ ซึ่งเป็นปัญหาที่พบระหว่างเขียนโปรแกรมตัวหนึ่งที่เรียกใช้ libthai ทำให้ต้อง include thai/thwchar.h เอง ซึ่งไม่สะดวก ในรุ่นนี้สามารถ include header ที่ต้องการแล้วเรียกใช้งานได้เลย ไม่ต้องเพิ่ม include เองอีกแล้ว
  • ปรับโค้ดให้เป็นไปตาม C90 (ANSI C) มากขึ้น เป็นผลพวงจากที่ได้ทำกับ libdatrie 0.2.12 มาแล้ว
  • ปรับข้อมูลพจนานุกรมตัดคำ โดยในรุ่นนี้ได้รับความช่วยเหลือจากคุณ @nuttee15 จาก metamedia technology ที่ได้เสนอคำเพิ่มเข้ามาใน Issue #2 ที่เปิดไว้รับเสนอคำใหม่ในพจนานุกรมตัดคำ

จากนั้นก็ได้ upload debian package พร้อมความเปลี่ยนแปลงอย่างอื่น คือ เพิ่ม pkg-config ให้เป็น dependency ของ libthai-dev เพื่อให้แน่ใจว่า libthai.pc จะสามารถทำงานได้แม้ในระบบที่ติดตั้งแบบเล็กที่สุด (เป็นปัญหาที่พบระหว่างที่ทำงานชิ้นหนึ่งร่วมกับ metamedia technology) และ การรองรับการ build ที่ไม่ต้องใช้ (fake)root

รายการคำจากพจนานุกรมตัดคำของ libthai ก็ได้นำไปใช้ สร้าง hyphenation pattern ที่โครงการ thailatex ซึ่งขณะนี้กลายสภาพเป็นเพียงที่พักงานพัฒนา hyphenation pattern เท่านั้น จากนั้นจึงได้เสนอ pull request สำหรับ update hyphenation pattern สำหรับภาษาไทยในโครงการ TeX hyphenation patterns ซึ่งต้องรอการ merge เพื่อให้มีผลที่ต้นน้ำต่อไป

จาก TeX hyphenation pattern ก็ต้อง sync มายังเครื่องมือตัดคำสำหรับเอกสาร LaTeX ด้วย คือ swath ซึ่งนอกจากการปรับพจนานุกรมแล้ว ก็ได้ปรับโค้ดเล็ก ๆ น้อย ๆ ตามที่เคยทำในทุกรุ่นที่ผ่านมา โดยสิ่งที่ทำในรุ่นนี้คือ:

  • ทดลอง build โดยใช้ CFLAGS -Wall แล้วแก้ warning ต่าง ๆ
  • จากการแก้ warning ที่พบในโค้ดส่วน RTF filter ทำให้ตรวจพบความผิดปกติใน method หนึ่งที่ตัวฟังก์ชันทำงานตรงข้ามกับชื่อ คือ RTFToken::isEmpty()

    โค้ดส่วนจัดการ RTF นี้ ไม่ค่อยมีใครเรียกใช้ ความจริงผมเคยเสนอจะตัดทิ้งไปแล้ว แต่ด้วยความช่วยเหลือของคนในชุมชน (คุณวิทยา ไตรสารวัฒนะ) ทำให้ได้วิธีทดสอบความถูกต้องของโปรแกรม จึงยังคงเก็บไว้ แต่เนื่องจากเวลานั้น swath ยังไม่เริ่มทำ TDD จึงยังไม่ได้ใส่ test case ไว้ใน source tree

    เพื่อจะตรวจแก้ฟังก์ชันที่สงสัยนี้ ผมจึงต้องไปดึงเอกสารตัวอย่างมาจาก thread เก่าที่ว่า แล้วนำมา เพิ่ม test case เสียก่อน หากคุณสงสัยว่าทำไม source tarball ของ swath รุ่นนี้ถึงโตขึ้นจนผิดสังเกต มันก็มาจากเอกสาร RTF ทดสอบนี้นี่เอง

    จากนั้น จึงได้ แก้ฟังก์ชันที่สงสัย นั้น แล้วรัน test เปรียบเทียบ output ดูโดยใช้ LibreOffice ปรากฏว่าเป็นการแก้ที่ถูกต้องแล้ว เพราะมันทำให้ได้จุดตัดคำครบถ้วนสมบูรณ์ขึ้น

    ไม่ว่าจะมีใครใช้หรือไม่ก็ตาม แต่คอมไพเลอร์ยังคงคอมไพล์มันอยู่ และนำผมเข้ามาเจอและแก้บั๊กจนได้

  • แก้ warning อื่น ๆ และทำความสะอาดโค้ดเล็ก ๆ น้อย ๆ
  • สุดท้าย มี pull request ของคุณ @pepa65 ที่เสนอไว้นานแล้ว เพื่อร่างแฟ้ม INSTALL ที่อธิบายความแตกต่างของวิธี build swath จาก git กับจาก released tarball ซึ่งผมก็เห็นว่ามีประโยชน์กว่าแฟ้ม INSTALL ที่ GNU automake มันเติมให้แบบอัตโนมัติ จึง merge เข้ามาเสีย

แล้วก็ออกรุ่น swath 0.6.1 ตามมาด้วย Debian upload ซึ่งก่อนอัปโหลดก็ได้ปรับ branch layout ของ swath packaging ตาม DEP-14 ด้วย

ป้ายกำกับ: , ,

21 สิงหาคม 2561

DEP-14 Note

บันทึกเตือนความจำสำหรับการทำตาม DEP-14: Recommended layout for Git packaging repositories เพื่อนำไปใช้ทำกับแพกเกจอื่น ๆ ในความดูแลของผมต่อไป

สำหรับ Debian package ปกติที่จัดการเวอร์ชันบน Git และใช้ git-buildpackage ในการ build นั้น จะมี branch layout ดังนี้:

master
pristine-tar
upstream
  • master เป็น branch หลักที่มีทั้ง upstream source tree และ Debian control files ครบสำหรับ build deb
  • upstream เป็น branch ที่เก็บ upstream source tree ซึ่ง maintainer จะ import source รุ่นใหม่เข้าที่นี่ก่อน (ถ้ามีการ repack เพื่อให้สอดคล้องกับ DFSG ก็ repack ก่อน import) แล้วจึง merge เข้าที่ master เพื่อเป็นการปรับรุ่น upstream ของ deb เอง
  • pristine-tar เป็น branch สำหรับ regenerate binary tarball รุ่นต่าง ๆ ของ upstream เพื่อใช้เป็นไฟล์ *.orig.tar.[gz|bz2|xz] โดยเก็บเฉพาะ delta ระหว่างรุ่นต่าง ๆ เพื่อให้ใช้เนื้อที่อย่างมีประสิทธิภาพสูงสุด

ศึกษารายละเอียดเพิ่มเติมได้ที่:

DEP-14 ได้แนะนำให้ใช้ branch layout แบบใหม่ เพื่อให้ Debian derivatives ต่าง ๆ ทำงานได้สะดวกขึ้น พร้อมกับเป็นการเตรียมการสำหรับเครื่องมือสร้างแพกเกจบน Git ต่าง ๆ ที่จะมีต่อไปในอนาคต

สำหรับแพกเกจใน Debian เอง โดยสรุปแล้วจะมีการเปลี่ยนแปลง branch layout ภาคบังคับอยู่ 2 รายการ คือ:

  • master เปลี่ยนเป็น debian/master
  • upstream เปลี่ยนเป็น upstream/latest

ทำให้มี branch layout ขั้นต่ำคือ:

debian/master
pristine-tar
upstream/latest

ที่เหลือก็ขึ้นอยู่กับความเปลี่ยนแปลงที่เกิดขึ้นกับแพกเกจ เช่น:

  • ถ้ามีการ update ใน stable release (เช่น security update, proposed update, backport) ก็ทำใน branch debian/jessie, debian/wheezy, debian/wheezy-backports ฯลฯ แล้วแต่กรณี
  • ถ้ามี experimental upload ก็ทำใน branch debian/experimental ซึ่งเป็น branch ชั่วคราวจนกว่าจะ merge เข้า debian/master หรือถ้าแพกเกจไหนมี experimental upload คู่ขนานกับ stable upload อยู่เป็นนิตย์ ก็อาจจะแทน branch debian/master ด้วย debian/sid แล้วก็ไม่ต้องลบ branch debian/experimental เลยก็ได้
  • ถ้าต้อง update upstream ขนานกันหลาย branch ก็อาจจะใช้ upstream/latest เก็บ development release ล่าสุด และสร้าง branch เช่น upstream/1.2.x ไว้เก็บ upstream รุ่น 1.2.*

สำหรับแพกเกจที่ผมดูแล ส่งตรงจาก linux.thai.net ซึ่งที่ผ่านมามีแต่ release เป็นเส้นตรง ไม่มีแยกแขนง ก็มักไม่มีความซับซ้อนอะไร (ยกเว้นตอนที่มี security update) สิ่งที่ต้องทำในตอนนี้จึงมีเพียง 3 ขั้นตอน:

  1. เปลี่ยนชื่อ branch upstream เป็น upstream/latest
  2. เปลี่ยนชื่อ branch master เป็น debian/master
  3. เพิ่มไฟล์ debian/gbp.conf เพื่อระบุให้ใช้ branch ชื่อใหม่

เปลี่ยนชื่อ branch upstream

การเปลี่ยนชื่อ Git remote branch สามารถทำได้ตามขั้นตอนดังนี้

  1. เปลี่ยนชื่อ local branch
    $ git branch -m upstream upstream/latest
    
  2. ลบ remote branch upstream
    $ git push origin :upstream
    
  3. push local branch ชื่อใหม่ไปที่ remote
    $ git push --set-upstream origin upstream/latest
    

เปลี่ยนชื่อ branch master

โดยหลักการแล้วก็ทำเหมือนตอนเปลี่ยนชื่อ branch upstream นั่นแหละ แต่จะมีความไม่ตรงไปตรงมานิดหน่อย

  1. เปลี่ยนชื่อ local branch
    $ git branch -m master debian/master
    
  2. ลบ remote branch master

    ขั้นตอนนี้แหละที่ tricky ที่สุด เพราะ คุณกำลังจะลบ default branch (master) ออกจาก repository!

    ถ้าคุณใช้ Salsa ล่ะก็ hook script ของมันจะปฏิเสธไม่ให้ลบ default branch ผ่านการ push เลยทีเดียว คุณต้องทำผ่าน web interface ดังนี้

    1. เปลี่ยน default branch ไปที่อื่นก่อน โดยใช้เมนู Settings > General > Default Branch
    2. ลบ branch master โดยใช้เมนู Repository > Branches สังเกตว่า branch master จะถูก protect ไว้ ไม่สามารถลบผ่านการ push ได้ แต่ใช้ web interface ลบได้ โดยมันจะถามยืนยันก่อนลบ
  3. push local branch ชื่อใหม่ไปที่ remote
    $ git push --set-upstream origin debian/master
    
  4. เปลี่ยน default branch ให้ชี้มาที่ debian/master โดยใช้เมนู Settings > General > Default Branch

เพิ่มไฟล์ debian/gbp.conf

คุณอาจจะต้อง clone Git repository ใหม่อีกครั้ง เพื่อให้ค่าต่าง ๆ ของ origin ตรงกับของ remote (เช่น HEAD)

จากนั้น เพิ่มไฟล์ debian/gbp.conf ที่มีเนื้อหาดังนี้:

[DEFAULT]
pristine-tar = True
debian-branch = debian/master
upstream-branch = upstream/latest

ก็จะสามารถ build package ด้วย git-buildpackage ได้ตามปกติผ่าน branch layout ตาม DEP-14

ป้ายกำกับ:

hacker emblem