Publican-v4.3.2 000755 041472 041472 0 12555605450 14021 5 ustar 00lnewson lnewson 000000 000000 catalog 000444 041472 041472 574 12555605450 15422 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2
publican.desktop 000444 041472 041472 373 12555605450 17252 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 [Desktop Entry]
Name=Publican - Users Guide
Comment=Publishing books, articles, papers and multi-volume sets with DocBook XML
Exec=xdg-open @@FILE@@
Icon=@@ICON@@
Categories=Documentation;X-Red-Hat-Base;
Type=Application
Encoding=UTF-8
Terminal=false
MANIFEST 000444 041472 041472 161100 12555605450 15267 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 Artistic
bin/db4-2-db5
bin/db5-valid
bin/fix-zanata-map
bin/publican
book_templates/cover.tmpl
book_templates/footer.tmpl
book_templates/header.tmpl
book_templates/pdf-css.tmpl
book_templates/pdfmain-css.tmpl
book_templates/titlepage.tmpl
book_templates/toc-xsl.tmpl
Build.PL
catalog
CC0
Changes
completion/_publican
COPYING
datadir/Common_Content/brand-template/images/1.png
datadir/Common_Content/brand-template/images/1.svg
datadir/Common_Content/brand-template/images/10.png
datadir/Common_Content/brand-template/images/10.svg
datadir/Common_Content/brand-template/images/11.png
datadir/Common_Content/brand-template/images/11.svg
datadir/Common_Content/brand-template/images/12.png
datadir/Common_Content/brand-template/images/12.svg
datadir/Common_Content/brand-template/images/13.png
datadir/Common_Content/brand-template/images/13.svg
datadir/Common_Content/brand-template/images/14.png
datadir/Common_Content/brand-template/images/14.svg
datadir/Common_Content/brand-template/images/15.png
datadir/Common_Content/brand-template/images/15.svg
datadir/Common_Content/brand-template/images/16.png
datadir/Common_Content/brand-template/images/16.svg
datadir/Common_Content/brand-template/images/17.png
datadir/Common_Content/brand-template/images/17.svg
datadir/Common_Content/brand-template/images/18.png
datadir/Common_Content/brand-template/images/18.svg
datadir/Common_Content/brand-template/images/19.png
datadir/Common_Content/brand-template/images/19.svg
datadir/Common_Content/brand-template/images/2.png
datadir/Common_Content/brand-template/images/2.svg
datadir/Common_Content/brand-template/images/20.png
datadir/Common_Content/brand-template/images/20.svg
datadir/Common_Content/brand-template/images/21.png
datadir/Common_Content/brand-template/images/21.svg
datadir/Common_Content/brand-template/images/22.png
datadir/Common_Content/brand-template/images/22.svg
datadir/Common_Content/brand-template/images/23.png
datadir/Common_Content/brand-template/images/23.svg
datadir/Common_Content/brand-template/images/24.png
datadir/Common_Content/brand-template/images/24.svg
datadir/Common_Content/brand-template/images/25.png
datadir/Common_Content/brand-template/images/25.svg
datadir/Common_Content/brand-template/images/26.png
datadir/Common_Content/brand-template/images/26.svg
datadir/Common_Content/brand-template/images/27.png
datadir/Common_Content/brand-template/images/27.svg
datadir/Common_Content/brand-template/images/28.png
datadir/Common_Content/brand-template/images/28.svg
datadir/Common_Content/brand-template/images/29.png
datadir/Common_Content/brand-template/images/29.svg
datadir/Common_Content/brand-template/images/3.png
datadir/Common_Content/brand-template/images/3.svg
datadir/Common_Content/brand-template/images/30.png
datadir/Common_Content/brand-template/images/30.svg
datadir/Common_Content/brand-template/images/31.png
datadir/Common_Content/brand-template/images/31.svg
datadir/Common_Content/brand-template/images/32.png
datadir/Common_Content/brand-template/images/32.svg
datadir/Common_Content/brand-template/images/33.png
datadir/Common_Content/brand-template/images/33.svg
datadir/Common_Content/brand-template/images/34.png
datadir/Common_Content/brand-template/images/34.svg
datadir/Common_Content/brand-template/images/35.png
datadir/Common_Content/brand-template/images/35.svg
datadir/Common_Content/brand-template/images/36.png
datadir/Common_Content/brand-template/images/36.svg
datadir/Common_Content/brand-template/images/37.png
datadir/Common_Content/brand-template/images/37.svg
datadir/Common_Content/brand-template/images/38.png
datadir/Common_Content/brand-template/images/38.svg
datadir/Common_Content/brand-template/images/39.png
datadir/Common_Content/brand-template/images/39.svg
datadir/Common_Content/brand-template/images/4.png
datadir/Common_Content/brand-template/images/4.svg
datadir/Common_Content/brand-template/images/40.png
datadir/Common_Content/brand-template/images/40.svg
datadir/Common_Content/brand-template/images/5.png
datadir/Common_Content/brand-template/images/5.svg
datadir/Common_Content/brand-template/images/6.png
datadir/Common_Content/brand-template/images/6.svg
datadir/Common_Content/brand-template/images/7.png
datadir/Common_Content/brand-template/images/7.svg
datadir/Common_Content/brand-template/images/8.png
datadir/Common_Content/brand-template/images/8.svg
datadir/Common_Content/brand-template/images/9.png
datadir/Common_Content/brand-template/images/9.svg
datadir/Common_Content/brand-template/images/dot.png
datadir/Common_Content/brand-template/images/dot2.png
datadir/Common_Content/brand-template/images/green.png
datadir/Common_Content/brand-template/images/h1-bg.png
datadir/Common_Content/brand-template/images/image_left.png
datadir/Common_Content/brand-template/images/image_right.png
datadir/Common_Content/brand-template/images/important.png
datadir/Common_Content/brand-template/images/important.svg
datadir/Common_Content/brand-template/images/note.png
datadir/Common_Content/brand-template/images/note.svg
datadir/Common_Content/brand-template/images/red.png
datadir/Common_Content/brand-template/images/shine.png
datadir/Common_Content/brand-template/images/stock-go-back.png
datadir/Common_Content/brand-template/images/stock-go-forward.png
datadir/Common_Content/brand-template/images/stock-go-up.png
datadir/Common_Content/brand-template/images/stock-home.png
datadir/Common_Content/brand-template/images/title_logo.png
datadir/Common_Content/brand-template/images/title_logo.svg
datadir/Common_Content/brand-template/images/warning.png
datadir/Common_Content/brand-template/images/warning.svg
datadir/Common_Content/brand-template/images/watermark-draft.png
datadir/Common_Content/brand-template/images/yellow.png
datadir/Common_Content/common-db5/ar-SA/Conventions.po
datadir/Common_Content/common-db5/ar-SA/Feedback.po
datadir/Common_Content/common-db5/ar-SA/Program_Listing.po
datadir/Common_Content/common-db5/ar-SA/Revision_History.po
datadir/Common_Content/common-db5/as-IN/Conventions.po
datadir/Common_Content/common-db5/as-IN/Feedback.po
datadir/Common_Content/common-db5/as-IN/Program_Listing.po
datadir/Common_Content/common-db5/as-IN/Revision_History.po
datadir/Common_Content/common-db5/ast-ES/Conventions.po
datadir/Common_Content/common-db5/ast-ES/Feedback.po
datadir/Common_Content/common-db5/ast-ES/Program_Listing.po
datadir/Common_Content/common-db5/ast-ES/Revision_History.po
datadir/Common_Content/common-db5/bg-BG/Conventions.po
datadir/Common_Content/common-db5/bg-BG/Feedback.po
datadir/Common_Content/common-db5/bg-BG/Program_Listing.po
datadir/Common_Content/common-db5/bg-BG/Revision_History.po
datadir/Common_Content/common-db5/bn-IN/Conventions.po
datadir/Common_Content/common-db5/bn-IN/Feedback.po
datadir/Common_Content/common-db5/bn-IN/Program_Listing.po
datadir/Common_Content/common-db5/bn-IN/Revision_History.po
datadir/Common_Content/common-db5/bs-BA/Conventions.po
datadir/Common_Content/common-db5/bs-BA/Feedback.po
datadir/Common_Content/common-db5/bs-BA/Program_Listing.po
datadir/Common_Content/common-db5/bs-BA/Revision_History.po
datadir/Common_Content/common-db5/ca-ES/Conventions.po
datadir/Common_Content/common-db5/ca-ES/Feedback.po
datadir/Common_Content/common-db5/ca-ES/Program_Listing.po
datadir/Common_Content/common-db5/ca-ES/Revision_History.po
datadir/Common_Content/common-db5/cs-CZ/Conventions.po
datadir/Common_Content/common-db5/cs-CZ/Feedback.po
datadir/Common_Content/common-db5/cs-CZ/Program_Listing.po
datadir/Common_Content/common-db5/cs-CZ/Revision_History.po
datadir/Common_Content/common-db5/da-DK/Conventions.po
datadir/Common_Content/common-db5/da-DK/Feedback.po
datadir/Common_Content/common-db5/da-DK/Program_Listing.po
datadir/Common_Content/common-db5/da-DK/Revision_History.po
datadir/Common_Content/common-db5/de-CH/Conventions.po
datadir/Common_Content/common-db5/de-CH/Feedback.po
datadir/Common_Content/common-db5/de-CH/Program_Listing.po
datadir/Common_Content/common-db5/de-CH/Revision_History.po
datadir/Common_Content/common-db5/de-DE/Conventions.po
datadir/Common_Content/common-db5/de-DE/Feedback.po
datadir/Common_Content/common-db5/de-DE/Program_Listing.po
datadir/Common_Content/common-db5/de-DE/Revision_History.po
datadir/Common_Content/common-db5/el-GR/Conventions.po
datadir/Common_Content/common-db5/el-GR/Feedback.po
datadir/Common_Content/common-db5/el-GR/Program_Listing.po
datadir/Common_Content/common-db5/el-GR/Revision_History.po
datadir/Common_Content/common-db5/en-US/Conventions.xml
datadir/Common_Content/common-db5/en-US/css/brand.css
datadir/Common_Content/common-db5/en-US/css/common.css
datadir/Common_Content/common-db5/en-US/css/default.css
datadir/Common_Content/common-db5/en-US/css/epub.css
datadir/Common_Content/common-db5/en-US/css/print.css
datadir/Common_Content/common-db5/en-US/Feedback.xml
datadir/Common_Content/common-db5/en-US/images/dot.png
datadir/Common_Content/common-db5/en-US/images/dot2.png
datadir/Common_Content/common-db5/en-US/images/stock-go-back.png
datadir/Common_Content/common-db5/en-US/images/stock-go-forward.png
datadir/Common_Content/common-db5/en-US/images/stock-go-up.png
datadir/Common_Content/common-db5/en-US/images/stock-home.png
datadir/Common_Content/common-db5/en-US/images/title_logo.png
datadir/Common_Content/common-db5/en-US/images/title_logo.svg
datadir/Common_Content/common-db5/en-US/images/watermark-draft.png
datadir/Common_Content/common-db5/en-US/Legal_Notice.xml
datadir/Common_Content/common-db5/en-US/Program_Listing.xml
datadir/Common_Content/common-db5/en-US/Revision_History.xml
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/CHANGES.md
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/highlight.pack.js
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/LICENSE
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/README.md
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/README.ru.md
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/arta.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/ascetic.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-dune.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-dune.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-forest.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-forest.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-heath.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-heath.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-lakeside.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-lakeside.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-seaside.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/atelier-seaside.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/brown_paper.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/brown_papersq.png
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/codepen-embed.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/color-brewer.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/default.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/docco.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/far.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/foundation.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/github.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/googlecode.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/hybrid.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/idea.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/ir_black.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/kimbie.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/kimbie.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/magula.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/mono-blue.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/monokai.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/monokai_sublime.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/obsidian.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/paraiso.dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/paraiso.light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/pojoaque.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/pojoaque.jpg
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/railscasts.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/rainbow.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/school_book.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/school_book.png
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/solarized_dark.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/solarized_light.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/sunburst.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/tomorrow-night-blue.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/tomorrow-night-bright.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/tomorrow-night-eighties.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/tomorrow-night.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/tomorrow.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/vs.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/xcode.css
datadir/Common_Content/common-db5/en-US/scripts/highlight.js/styles/zenburn.css
datadir/Common_Content/common-db5/en-US/scripts/jquery-1.7.1.min.js
datadir/Common_Content/common-db5/en-US/scripts/utils.js
datadir/Common_Content/common-db5/es-ES/Conventions.po
datadir/Common_Content/common-db5/es-ES/Feedback.po
datadir/Common_Content/common-db5/es-ES/Program_Listing.po
datadir/Common_Content/common-db5/es-ES/Revision_History.po
datadir/Common_Content/common-db5/fa-IR/Conventions.po
datadir/Common_Content/common-db5/fa-IR/Feedback.po
datadir/Common_Content/common-db5/fa-IR/Program_Listing.po
datadir/Common_Content/common-db5/fa-IR/Revision_History.po
datadir/Common_Content/common-db5/fi-FI/Conventions.po
datadir/Common_Content/common-db5/fi-FI/Feedback.po
datadir/Common_Content/common-db5/fi-FI/Program_Listing.po
datadir/Common_Content/common-db5/fi-FI/Revision_History.po
datadir/Common_Content/common-db5/fr-FR/Conventions.po
datadir/Common_Content/common-db5/fr-FR/Feedback.po
datadir/Common_Content/common-db5/fr-FR/Program_Listing.po
datadir/Common_Content/common-db5/fr-FR/Revision_History.po
datadir/Common_Content/common-db5/gu-IN/Conventions.po
datadir/Common_Content/common-db5/gu-IN/Feedback.po
datadir/Common_Content/common-db5/gu-IN/Program_Listing.po
datadir/Common_Content/common-db5/gu-IN/Revision_History.po
datadir/Common_Content/common-db5/he-IL/Conventions.po
datadir/Common_Content/common-db5/he-IL/Feedback.po
datadir/Common_Content/common-db5/he-IL/Program_Listing.po
datadir/Common_Content/common-db5/he-IL/Revision_History.po
datadir/Common_Content/common-db5/hi-IN/Conventions.po
datadir/Common_Content/common-db5/hi-IN/Feedback.po
datadir/Common_Content/common-db5/hi-IN/Program_Listing.po
datadir/Common_Content/common-db5/hi-IN/Revision_History.po
datadir/Common_Content/common-db5/hr-HR/Conventions.po
datadir/Common_Content/common-db5/hr-HR/Feedback.po
datadir/Common_Content/common-db5/hr-HR/Program_Listing.po
datadir/Common_Content/common-db5/hr-HR/Revision_History.po
datadir/Common_Content/common-db5/hu-HU/Conventions.po
datadir/Common_Content/common-db5/hu-HU/Feedback.po
datadir/Common_Content/common-db5/hu-HU/Program_Listing.po
datadir/Common_Content/common-db5/hu-HU/Revision_History.po
datadir/Common_Content/common-db5/ia/Conventions.po
datadir/Common_Content/common-db5/ia/Feedback.po
datadir/Common_Content/common-db5/ia/Program_Listing.po
datadir/Common_Content/common-db5/ia/Revision_History.po
datadir/Common_Content/common-db5/id-ID/Conventions.po
datadir/Common_Content/common-db5/id-ID/Feedback.po
datadir/Common_Content/common-db5/id-ID/Program_Listing.po
datadir/Common_Content/common-db5/id-ID/Revision_History.po
datadir/Common_Content/common-db5/is-IS/Conventions.po
datadir/Common_Content/common-db5/is-IS/Feedback.po
datadir/Common_Content/common-db5/is-IS/Program_Listing.po
datadir/Common_Content/common-db5/is-IS/Revision_History.po
datadir/Common_Content/common-db5/it-IT/Conventions.po
datadir/Common_Content/common-db5/it-IT/Feedback.po
datadir/Common_Content/common-db5/it-IT/Program_Listing.po
datadir/Common_Content/common-db5/it-IT/Revision_History.po
datadir/Common_Content/common-db5/ja-JP/Conventions.po
datadir/Common_Content/common-db5/ja-JP/Feedback.po
datadir/Common_Content/common-db5/ja-JP/Program_Listing.po
datadir/Common_Content/common-db5/ja-JP/Revision_History.po
datadir/Common_Content/common-db5/kn-IN/Conventions.po
datadir/Common_Content/common-db5/kn-IN/Feedback.po
datadir/Common_Content/common-db5/kn-IN/Program_Listing.po
datadir/Common_Content/common-db5/kn-IN/Revision_History.po
datadir/Common_Content/common-db5/ko-KR/Conventions.po
datadir/Common_Content/common-db5/ko-KR/Feedback.po
datadir/Common_Content/common-db5/ko-KR/Program_Listing.po
datadir/Common_Content/common-db5/ko-KR/Revision_History.po
datadir/Common_Content/common-db5/lv-LV/Conventions.po
datadir/Common_Content/common-db5/lv-LV/Feedback.po
datadir/Common_Content/common-db5/lv-LV/Program_Listing.po
datadir/Common_Content/common-db5/lv-LV/Revision_History.po
datadir/Common_Content/common-db5/ml-IN/Conventions.po
datadir/Common_Content/common-db5/ml-IN/Feedback.po
datadir/Common_Content/common-db5/ml-IN/Program_Listing.po
datadir/Common_Content/common-db5/ml-IN/Revision_History.po
datadir/Common_Content/common-db5/mr-IN/Conventions.po
datadir/Common_Content/common-db5/mr-IN/Feedback.po
datadir/Common_Content/common-db5/mr-IN/Program_Listing.po
datadir/Common_Content/common-db5/mr-IN/Revision_History.po
datadir/Common_Content/common-db5/nb-NO/Conventions.po
datadir/Common_Content/common-db5/nb-NO/Feedback.po
datadir/Common_Content/common-db5/nb-NO/Program_Listing.po
datadir/Common_Content/common-db5/nb-NO/Revision_History.po
datadir/Common_Content/common-db5/nl-NL/Conventions.po
datadir/Common_Content/common-db5/nl-NL/Feedback.po
datadir/Common_Content/common-db5/nl-NL/Program_Listing.po
datadir/Common_Content/common-db5/nl-NL/Revision_History.po
datadir/Common_Content/common-db5/or-IN/Conventions.po
datadir/Common_Content/common-db5/or-IN/Feedback.po
datadir/Common_Content/common-db5/or-IN/Program_Listing.po
datadir/Common_Content/common-db5/or-IN/Revision_History.po
datadir/Common_Content/common-db5/pa-IN/Conventions.po
datadir/Common_Content/common-db5/pa-IN/Feedback.po
datadir/Common_Content/common-db5/pa-IN/Program_Listing.po
datadir/Common_Content/common-db5/pa-IN/Revision_History.po
datadir/Common_Content/common-db5/pl-PL/Conventions.po
datadir/Common_Content/common-db5/pl-PL/Feedback.po
datadir/Common_Content/common-db5/pl-PL/Program_Listing.po
datadir/Common_Content/common-db5/pl-PL/Revision_History.po
datadir/Common_Content/common-db5/pot/Conventions.pot
datadir/Common_Content/common-db5/pot/Feedback.pot
datadir/Common_Content/common-db5/pot/Program_Listing.pot
datadir/Common_Content/common-db5/pot/Revision_History.pot
datadir/Common_Content/common-db5/pt-BR/Conventions.po
datadir/Common_Content/common-db5/pt-BR/Feedback.po
datadir/Common_Content/common-db5/pt-BR/Program_Listing.po
datadir/Common_Content/common-db5/pt-BR/Revision_History.po
datadir/Common_Content/common-db5/pt-PT/Conventions.po
datadir/Common_Content/common-db5/pt-PT/Feedback.po
datadir/Common_Content/common-db5/pt-PT/Program_Listing.po
datadir/Common_Content/common-db5/pt-PT/Revision_History.po
datadir/Common_Content/common-db5/publican.cfg
datadir/Common_Content/common-db5/ru-RU/Conventions.po
datadir/Common_Content/common-db5/ru-RU/Feedback.po
datadir/Common_Content/common-db5/ru-RU/Program_Listing.po
datadir/Common_Content/common-db5/ru-RU/Revision_History.po
datadir/Common_Content/common-db5/si-LK/Conventions.po
datadir/Common_Content/common-db5/si-LK/Feedback.po
datadir/Common_Content/common-db5/si-LK/Program_Listing.po
datadir/Common_Content/common-db5/si-LK/Revision_History.po
datadir/Common_Content/common-db5/sk-SK/Conventions.po
datadir/Common_Content/common-db5/sk-SK/Feedback.po
datadir/Common_Content/common-db5/sk-SK/Program_Listing.po
datadir/Common_Content/common-db5/sk-SK/Revision_History.po
datadir/Common_Content/common-db5/sr-Latn-RS/Conventions.po
datadir/Common_Content/common-db5/sr-Latn-RS/Feedback.po
datadir/Common_Content/common-db5/sr-Latn-RS/Program_Listing.po
datadir/Common_Content/common-db5/sr-Latn-RS/Revision_History.po
datadir/Common_Content/common-db5/sr-RS/Conventions.po
datadir/Common_Content/common-db5/sr-RS/Feedback.po
datadir/Common_Content/common-db5/sr-RS/Program_Listing.po
datadir/Common_Content/common-db5/sr-RS/Revision_History.po
datadir/Common_Content/common-db5/sv-SE/Conventions.po
datadir/Common_Content/common-db5/sv-SE/Feedback.po
datadir/Common_Content/common-db5/sv-SE/Program_Listing.po
datadir/Common_Content/common-db5/sv-SE/Revision_History.po
datadir/Common_Content/common-db5/ta-IN/Conventions.po
datadir/Common_Content/common-db5/ta-IN/Feedback.po
datadir/Common_Content/common-db5/ta-IN/Program_Listing.po
datadir/Common_Content/common-db5/ta-IN/Revision_History.po
datadir/Common_Content/common-db5/te-IN/Conventions.po
datadir/Common_Content/common-db5/te-IN/Feedback.po
datadir/Common_Content/common-db5/te-IN/Program_Listing.po
datadir/Common_Content/common-db5/te-IN/Revision_History.po
datadir/Common_Content/common-db5/th-TH/Conventions.po
datadir/Common_Content/common-db5/th-TH/Feedback.po
datadir/Common_Content/common-db5/th-TH/Program_Listing.po
datadir/Common_Content/common-db5/th-TH/Revision_History.po
datadir/Common_Content/common-db5/uk-UA/Conventions.po
datadir/Common_Content/common-db5/uk-UA/Feedback.po
datadir/Common_Content/common-db5/uk-UA/Program_Listing.po
datadir/Common_Content/common-db5/uk-UA/Revision_History.po
datadir/Common_Content/common-db5/xsl/drupal-book.xsl
datadir/Common_Content/common-db5/xsl/epub.xsl
datadir/Common_Content/common-db5/xsl/html-common.xsl
datadir/Common_Content/common-db5/xsl/html-pdf.xsl
datadir/Common_Content/common-db5/xsl/html-single-plain.xsl
datadir/Common_Content/common-db5/xsl/html-single.xsl
datadir/Common_Content/common-db5/xsl/html.xsl
datadir/Common_Content/common-db5/xsl/pdf.xsl
datadir/Common_Content/common-db5/zh-CN/Conventions.po
datadir/Common_Content/common-db5/zh-CN/Feedback.po
datadir/Common_Content/common-db5/zh-CN/Program_Listing.po
datadir/Common_Content/common-db5/zh-CN/Revision_History.po
datadir/Common_Content/common-db5/zh-TW/Conventions.po
datadir/Common_Content/common-db5/zh-TW/Feedback.po
datadir/Common_Content/common-db5/zh-TW/Program_Listing.po
datadir/Common_Content/common-db5/zh-TW/Revision_History.po
datadir/Common_Content/common/ar-SA/Conventions.po
datadir/Common_Content/common/ar-SA/css/brand.css
datadir/Common_Content/common/ar-SA/css/lang.css
datadir/Common_Content/common/ar-SA/Feedback.po
datadir/Common_Content/common/ar-SA/Program_Listing.po
datadir/Common_Content/common/ar-SA/Revision_History.po
datadir/Common_Content/common/ar-SA/Revision_History.xml
datadir/Common_Content/common/as-IN/Conventions.po
datadir/Common_Content/common/as-IN/css/lang.css
datadir/Common_Content/common/as-IN/Feedback.po
datadir/Common_Content/common/as-IN/Program_Listing.po
datadir/Common_Content/common/as-IN/Revision_History.po
datadir/Common_Content/common/as-IN/Revision_History.xml
datadir/Common_Content/common/ast-ES/Conventions.po
datadir/Common_Content/common/ast-ES/Feedback.po
datadir/Common_Content/common/ast-ES/Program_Listing.po
datadir/Common_Content/common/ast-ES/Revision_History.po
datadir/Common_Content/common/ast-ES/Revision_History.xml
datadir/Common_Content/common/bg-BG/Conventions.po
datadir/Common_Content/common/bg-BG/Feedback.po
datadir/Common_Content/common/bg-BG/Program_Listing.po
datadir/Common_Content/common/bg-BG/Revision_History.po
datadir/Common_Content/common/bg-BG/Revision_History.xml
datadir/Common_Content/common/bn-IN/Conventions.po
datadir/Common_Content/common/bn-IN/css/lang.css
datadir/Common_Content/common/bn-IN/Feedback.po
datadir/Common_Content/common/bn-IN/Program_Listing.po
datadir/Common_Content/common/bn-IN/Revision_History.po
datadir/Common_Content/common/bn-IN/Revision_History.xml
datadir/Common_Content/common/bs-BA/Conventions.po
datadir/Common_Content/common/bs-BA/Feedback.po
datadir/Common_Content/common/bs-BA/Program_Listing.po
datadir/Common_Content/common/bs-BA/Revision_History.po
datadir/Common_Content/common/bs-BA/Revision_History.xml
datadir/Common_Content/common/ca-ES/Conventions.po
datadir/Common_Content/common/ca-ES/Feedback.po
datadir/Common_Content/common/ca-ES/Program_Listing.po
datadir/Common_Content/common/ca-ES/Revision_History.po
datadir/Common_Content/common/ca-ES/Revision_History.xml
datadir/Common_Content/common/cs-CZ/Conventions.po
datadir/Common_Content/common/cs-CZ/Feedback.po
datadir/Common_Content/common/cs-CZ/Program_Listing.po
datadir/Common_Content/common/cs-CZ/Revision_History.po
datadir/Common_Content/common/cs-CZ/Revision_History.xml
datadir/Common_Content/common/da-DK/Conventions.po
datadir/Common_Content/common/da-DK/Feedback.po
datadir/Common_Content/common/da-DK/Program_Listing.po
datadir/Common_Content/common/da-DK/Revision_History.po
datadir/Common_Content/common/da-DK/Revision_History.xml
datadir/Common_Content/common/de-CH/Conventions.po
datadir/Common_Content/common/de-CH/Feedback.po
datadir/Common_Content/common/de-CH/Program_Listing.po
datadir/Common_Content/common/de-CH/Revision_History.po
datadir/Common_Content/common/de-CH/Revision_History.xml
datadir/Common_Content/common/de-DE/Conventions.po
datadir/Common_Content/common/de-DE/Feedback.po
datadir/Common_Content/common/de-DE/Program_Listing.po
datadir/Common_Content/common/de-DE/Revision_History.po
datadir/Common_Content/common/de-DE/Revision_History.xml
datadir/Common_Content/common/el-GR/Conventions.po
datadir/Common_Content/common/el-GR/Feedback.po
datadir/Common_Content/common/el-GR/Program_Listing.po
datadir/Common_Content/common/el-GR/Revision_History.po
datadir/Common_Content/common/el-GR/Revision_History.xml
datadir/Common_Content/common/en-US/Conventions.xml
datadir/Common_Content/common/en-US/css/brand.css
datadir/Common_Content/common/en-US/css/common.css
datadir/Common_Content/common/en-US/css/default.css
datadir/Common_Content/common/en-US/css/epub.css
datadir/Common_Content/common/en-US/css/print.css
datadir/Common_Content/common/en-US/Feedback.xml
datadir/Common_Content/common/en-US/images/1.png
datadir/Common_Content/common/en-US/images/1.svg
datadir/Common_Content/common/en-US/images/10.png
datadir/Common_Content/common/en-US/images/10.svg
datadir/Common_Content/common/en-US/images/11.png
datadir/Common_Content/common/en-US/images/11.svg
datadir/Common_Content/common/en-US/images/12.png
datadir/Common_Content/common/en-US/images/12.svg
datadir/Common_Content/common/en-US/images/13.png
datadir/Common_Content/common/en-US/images/13.svg
datadir/Common_Content/common/en-US/images/14.png
datadir/Common_Content/common/en-US/images/14.svg
datadir/Common_Content/common/en-US/images/15.png
datadir/Common_Content/common/en-US/images/15.svg
datadir/Common_Content/common/en-US/images/16.png
datadir/Common_Content/common/en-US/images/16.svg
datadir/Common_Content/common/en-US/images/17.png
datadir/Common_Content/common/en-US/images/17.svg
datadir/Common_Content/common/en-US/images/18.png
datadir/Common_Content/common/en-US/images/18.svg
datadir/Common_Content/common/en-US/images/19.png
datadir/Common_Content/common/en-US/images/19.svg
datadir/Common_Content/common/en-US/images/2.png
datadir/Common_Content/common/en-US/images/2.svg
datadir/Common_Content/common/en-US/images/20.png
datadir/Common_Content/common/en-US/images/20.svg
datadir/Common_Content/common/en-US/images/21.png
datadir/Common_Content/common/en-US/images/21.svg
datadir/Common_Content/common/en-US/images/22.png
datadir/Common_Content/common/en-US/images/22.svg
datadir/Common_Content/common/en-US/images/23.png
datadir/Common_Content/common/en-US/images/23.svg
datadir/Common_Content/common/en-US/images/24.png
datadir/Common_Content/common/en-US/images/24.svg
datadir/Common_Content/common/en-US/images/25.png
datadir/Common_Content/common/en-US/images/25.svg
datadir/Common_Content/common/en-US/images/26.png
datadir/Common_Content/common/en-US/images/26.svg
datadir/Common_Content/common/en-US/images/27.png
datadir/Common_Content/common/en-US/images/27.svg
datadir/Common_Content/common/en-US/images/28.png
datadir/Common_Content/common/en-US/images/28.svg
datadir/Common_Content/common/en-US/images/29.png
datadir/Common_Content/common/en-US/images/29.svg
datadir/Common_Content/common/en-US/images/3.png
datadir/Common_Content/common/en-US/images/3.svg
datadir/Common_Content/common/en-US/images/30.png
datadir/Common_Content/common/en-US/images/30.svg
datadir/Common_Content/common/en-US/images/31.png
datadir/Common_Content/common/en-US/images/31.svg
datadir/Common_Content/common/en-US/images/32.png
datadir/Common_Content/common/en-US/images/32.svg
datadir/Common_Content/common/en-US/images/33.png
datadir/Common_Content/common/en-US/images/33.svg
datadir/Common_Content/common/en-US/images/34.png
datadir/Common_Content/common/en-US/images/34.svg
datadir/Common_Content/common/en-US/images/35.png
datadir/Common_Content/common/en-US/images/35.svg
datadir/Common_Content/common/en-US/images/36.png
datadir/Common_Content/common/en-US/images/36.svg
datadir/Common_Content/common/en-US/images/37.png
datadir/Common_Content/common/en-US/images/37.svg
datadir/Common_Content/common/en-US/images/38.png
datadir/Common_Content/common/en-US/images/38.svg
datadir/Common_Content/common/en-US/images/39.png
datadir/Common_Content/common/en-US/images/39.svg
datadir/Common_Content/common/en-US/images/4.png
datadir/Common_Content/common/en-US/images/4.svg
datadir/Common_Content/common/en-US/images/40.png
datadir/Common_Content/common/en-US/images/40.svg
datadir/Common_Content/common/en-US/images/5.png
datadir/Common_Content/common/en-US/images/5.svg
datadir/Common_Content/common/en-US/images/6.png
datadir/Common_Content/common/en-US/images/6.svg
datadir/Common_Content/common/en-US/images/7.png
datadir/Common_Content/common/en-US/images/7.svg
datadir/Common_Content/common/en-US/images/8.png
datadir/Common_Content/common/en-US/images/8.svg
datadir/Common_Content/common/en-US/images/9.png
datadir/Common_Content/common/en-US/images/9.svg
datadir/Common_Content/common/en-US/images/dot.png
datadir/Common_Content/common/en-US/images/dot2.png
datadir/Common_Content/common/en-US/images/green.png
datadir/Common_Content/common/en-US/images/h1-bg.png
datadir/Common_Content/common/en-US/images/image_left.png
datadir/Common_Content/common/en-US/images/image_right.png
datadir/Common_Content/common/en-US/images/important.png
datadir/Common_Content/common/en-US/images/important.svg
datadir/Common_Content/common/en-US/images/note.png
datadir/Common_Content/common/en-US/images/note.svg
datadir/Common_Content/common/en-US/images/red.png
datadir/Common_Content/common/en-US/images/shine.png
datadir/Common_Content/common/en-US/images/stock-go-back.png
datadir/Common_Content/common/en-US/images/stock-go-forward.png
datadir/Common_Content/common/en-US/images/stock-go-up.png
datadir/Common_Content/common/en-US/images/stock-home.png
datadir/Common_Content/common/en-US/images/title_logo.png
datadir/Common_Content/common/en-US/images/title_logo.svg
datadir/Common_Content/common/en-US/images/warning.png
datadir/Common_Content/common/en-US/images/warning.svg
datadir/Common_Content/common/en-US/images/watermark-draft.png
datadir/Common_Content/common/en-US/images/yellow.png
datadir/Common_Content/common/en-US/Legal_Notice.xml
datadir/Common_Content/common/en-US/Program_Listing.xml
datadir/Common_Content/common/en-US/Revision_History.xml
datadir/Common_Content/common/es-ES/Conventions.po
datadir/Common_Content/common/es-ES/Feedback.po
datadir/Common_Content/common/es-ES/Program_Listing.po
datadir/Common_Content/common/es-ES/Revision_History.po
datadir/Common_Content/common/es-ES/Revision_History.xml
datadir/Common_Content/common/fa-IR/Conventions.po
datadir/Common_Content/common/fa-IR/css/brand.css
datadir/Common_Content/common/fa-IR/css/lang.css
datadir/Common_Content/common/fa-IR/Feedback.po
datadir/Common_Content/common/fa-IR/Program_Listing.po
datadir/Common_Content/common/fa-IR/Revision_History.po
datadir/Common_Content/common/fa-IR/Revision_History.xml
datadir/Common_Content/common/fi-FI/Conventions.po
datadir/Common_Content/common/fi-FI/Feedback.po
datadir/Common_Content/common/fi-FI/Program_Listing.po
datadir/Common_Content/common/fi-FI/Revision_History.po
datadir/Common_Content/common/fi-FI/Revision_History.xml
datadir/Common_Content/common/fr-FR/Conventions.po
datadir/Common_Content/common/fr-FR/Feedback.po
datadir/Common_Content/common/fr-FR/Program_Listing.po
datadir/Common_Content/common/fr-FR/Revision_History.po
datadir/Common_Content/common/fr-FR/Revision_History.xml
datadir/Common_Content/common/gu-IN/Conventions.po
datadir/Common_Content/common/gu-IN/css/lang.css
datadir/Common_Content/common/gu-IN/Feedback.po
datadir/Common_Content/common/gu-IN/Program_Listing.po
datadir/Common_Content/common/gu-IN/Revision_History.po
datadir/Common_Content/common/gu-IN/Revision_History.xml
datadir/Common_Content/common/he-IL/Conventions.po
datadir/Common_Content/common/he-IL/css/brand.css
datadir/Common_Content/common/he-IL/css/lang.css
datadir/Common_Content/common/he-IL/Feedback.po
datadir/Common_Content/common/he-IL/Program_Listing.po
datadir/Common_Content/common/he-IL/Revision_History.po
datadir/Common_Content/common/he-IL/Revision_History.xml
datadir/Common_Content/common/hi-IN/Conventions.po
datadir/Common_Content/common/hi-IN/css/lang.css
datadir/Common_Content/common/hi-IN/Feedback.po
datadir/Common_Content/common/hi-IN/Program_Listing.po
datadir/Common_Content/common/hi-IN/Revision_History.po
datadir/Common_Content/common/hi-IN/Revision_History.xml
datadir/Common_Content/common/hr-HR/Conventions.po
datadir/Common_Content/common/hr-HR/Feedback.po
datadir/Common_Content/common/hr-HR/Program_Listing.po
datadir/Common_Content/common/hr-HR/Revision_History.po
datadir/Common_Content/common/hr-HR/Revision_History.xml
datadir/Common_Content/common/hu-HU/Conventions.po
datadir/Common_Content/common/hu-HU/Feedback.po
datadir/Common_Content/common/hu-HU/Program_Listing.po
datadir/Common_Content/common/hu-HU/Revision_History.po
datadir/Common_Content/common/hu-HU/Revision_History.xml
datadir/Common_Content/common/ia/Conventions.po
datadir/Common_Content/common/ia/Feedback.po
datadir/Common_Content/common/ia/Program_Listing.po
datadir/Common_Content/common/ia/Revision_History.po
datadir/Common_Content/common/ia/Revision_History.xml
datadir/Common_Content/common/id-ID/Conventions.po
datadir/Common_Content/common/id-ID/Feedback.po
datadir/Common_Content/common/id-ID/Program_Listing.po
datadir/Common_Content/common/id-ID/Revision_History.po
datadir/Common_Content/common/id-ID/Revision_History.xml
datadir/Common_Content/common/is-IS/Conventions.po
datadir/Common_Content/common/is-IS/Feedback.po
datadir/Common_Content/common/is-IS/Program_Listing.po
datadir/Common_Content/common/is-IS/Revision_History.po
datadir/Common_Content/common/is-IS/Revision_History.xml
datadir/Common_Content/common/it-IT/Conventions.po
datadir/Common_Content/common/it-IT/Feedback.po
datadir/Common_Content/common/it-IT/Program_Listing.po
datadir/Common_Content/common/it-IT/Revision_History.po
datadir/Common_Content/common/it-IT/Revision_History.xml
datadir/Common_Content/common/ja-JP/Conventions.po
datadir/Common_Content/common/ja-JP/Feedback.po
datadir/Common_Content/common/ja-JP/Program_Listing.po
datadir/Common_Content/common/ja-JP/Revision_History.po
datadir/Common_Content/common/ja-JP/Revision_History.xml
datadir/Common_Content/common/kn-IN/Conventions.po
datadir/Common_Content/common/kn-IN/css/lang.css
datadir/Common_Content/common/kn-IN/Feedback.po
datadir/Common_Content/common/kn-IN/Program_Listing.po
datadir/Common_Content/common/kn-IN/Revision_History.po
datadir/Common_Content/common/kn-IN/Revision_History.xml
datadir/Common_Content/common/ko-KR/Conventions.po
datadir/Common_Content/common/ko-KR/Feedback.po
datadir/Common_Content/common/ko-KR/Program_Listing.po
datadir/Common_Content/common/ko-KR/Revision_History.po
datadir/Common_Content/common/ko-KR/Revision_History.xml
datadir/Common_Content/common/lv-LV/Conventions.po
datadir/Common_Content/common/lv-LV/Feedback.po
datadir/Common_Content/common/lv-LV/Program_Listing.po
datadir/Common_Content/common/lv-LV/Revision_History.po
datadir/Common_Content/common/lv-LV/Revision_History.xml
datadir/Common_Content/common/ml-IN/Conventions.po
datadir/Common_Content/common/ml-IN/css/lang.css
datadir/Common_Content/common/ml-IN/Feedback.po
datadir/Common_Content/common/ml-IN/Program_Listing.po
datadir/Common_Content/common/ml-IN/Revision_History.po
datadir/Common_Content/common/ml-IN/Revision_History.xml
datadir/Common_Content/common/mr-IN/Conventions.po
datadir/Common_Content/common/mr-IN/css/lang.css
datadir/Common_Content/common/mr-IN/Feedback.po
datadir/Common_Content/common/mr-IN/Program_Listing.po
datadir/Common_Content/common/mr-IN/Revision_History.po
datadir/Common_Content/common/mr-IN/Revision_History.xml
datadir/Common_Content/common/ms-MY/Conventions.po
datadir/Common_Content/common/ms-MY/Feedback.po
datadir/Common_Content/common/ms-MY/Program_Listing.po
datadir/Common_Content/common/ms-MY/Revision_History.po
datadir/Common_Content/common/ms-MY/Revision_History.xml
datadir/Common_Content/common/nb-NO/Conventions.po
datadir/Common_Content/common/nb-NO/Feedback.po
datadir/Common_Content/common/nb-NO/Program_Listing.po
datadir/Common_Content/common/nb-NO/Revision_History.po
datadir/Common_Content/common/nb-NO/Revision_History.xml
datadir/Common_Content/common/nl-NL/Conventions.po
datadir/Common_Content/common/nl-NL/Feedback.po
datadir/Common_Content/common/nl-NL/Program_Listing.po
datadir/Common_Content/common/nl-NL/Revision_History.po
datadir/Common_Content/common/nl-NL/Revision_History.xml
datadir/Common_Content/common/or-IN/Conventions.po
datadir/Common_Content/common/or-IN/Feedback.po
datadir/Common_Content/common/or-IN/Program_Listing.po
datadir/Common_Content/common/or-IN/Revision_History.po
datadir/Common_Content/common/or-IN/Revision_History.xml
datadir/Common_Content/common/pa-IN/Conventions.po
datadir/Common_Content/common/pa-IN/css/lang.css
datadir/Common_Content/common/pa-IN/Feedback.po
datadir/Common_Content/common/pa-IN/Program_Listing.po
datadir/Common_Content/common/pa-IN/Revision_History.po
datadir/Common_Content/common/pa-IN/Revision_History.xml
datadir/Common_Content/common/pl-PL/Conventions.po
datadir/Common_Content/common/pl-PL/Feedback.po
datadir/Common_Content/common/pl-PL/Program_Listing.po
datadir/Common_Content/common/pl-PL/Revision_History.po
datadir/Common_Content/common/pl-PL/Revision_History.xml
datadir/Common_Content/common/pom.xml
datadir/Common_Content/common/pot/Conventions.pot
datadir/Common_Content/common/pot/Feedback.pot
datadir/Common_Content/common/pot/Program_Listing.pot
datadir/Common_Content/common/pot/Revision_History.pot
datadir/Common_Content/common/pt-BR/Conventions.po
datadir/Common_Content/common/pt-BR/Feedback.po
datadir/Common_Content/common/pt-BR/Program_Listing.po
datadir/Common_Content/common/pt-BR/Revision_History.po
datadir/Common_Content/common/pt-BR/Revision_History.xml
datadir/Common_Content/common/pt-PT/Conventions.po
datadir/Common_Content/common/pt-PT/Feedback.po
datadir/Common_Content/common/pt-PT/Program_Listing.po
datadir/Common_Content/common/pt-PT/Revision_History.po
datadir/Common_Content/common/pt-PT/Revision_History.xml
datadir/Common_Content/common/publican.cfg
datadir/Common_Content/common/ru-RU/Conventions.po
datadir/Common_Content/common/ru-RU/Feedback.po
datadir/Common_Content/common/ru-RU/Program_Listing.po
datadir/Common_Content/common/ru-RU/Revision_History.po
datadir/Common_Content/common/ru-RU/Revision_History.xml
datadir/Common_Content/common/si-LK/Conventions.po
datadir/Common_Content/common/si-LK/Feedback.po
datadir/Common_Content/common/si-LK/Program_Listing.po
datadir/Common_Content/common/si-LK/Revision_History.po
datadir/Common_Content/common/si-LK/Revision_History.xml
datadir/Common_Content/common/sk-SK/Conventions.po
datadir/Common_Content/common/sk-SK/Feedback.po
datadir/Common_Content/common/sk-SK/Program_Listing.po
datadir/Common_Content/common/sk-SK/Revision_History.po
datadir/Common_Content/common/sk-SK/Revision_History.xml
datadir/Common_Content/common/sr-Latn-RS/Conventions.po
datadir/Common_Content/common/sr-Latn-RS/Feedback.po
datadir/Common_Content/common/sr-Latn-RS/Program_Listing.po
datadir/Common_Content/common/sr-Latn-RS/Revision_History.po
datadir/Common_Content/common/sr-Latn-RS/Revision_History.xml
datadir/Common_Content/common/sr-RS/Conventions.po
datadir/Common_Content/common/sr-RS/Feedback.po
datadir/Common_Content/common/sr-RS/Program_Listing.po
datadir/Common_Content/common/sr-RS/Revision_History.po
datadir/Common_Content/common/sr-RS/Revision_History.xml
datadir/Common_Content/common/sv-SE/Conventions.po
datadir/Common_Content/common/sv-SE/Feedback.po
datadir/Common_Content/common/sv-SE/Program_Listing.po
datadir/Common_Content/common/sv-SE/Revision_History.po
datadir/Common_Content/common/sv-SE/Revision_History.xml
datadir/Common_Content/common/ta-IN/Conventions.po
datadir/Common_Content/common/ta-IN/css/lang.css
datadir/Common_Content/common/ta-IN/Feedback.po
datadir/Common_Content/common/ta-IN/Program_Listing.po
datadir/Common_Content/common/ta-IN/Revision_History.po
datadir/Common_Content/common/ta-IN/Revision_History.xml
datadir/Common_Content/common/te-IN/Conventions.po
datadir/Common_Content/common/te-IN/css/lang.css
datadir/Common_Content/common/te-IN/Feedback.po
datadir/Common_Content/common/te-IN/Program_Listing.po
datadir/Common_Content/common/te-IN/Revision_History.po
datadir/Common_Content/common/te-IN/Revision_History.xml
datadir/Common_Content/common/th-TH/Conventions.po
datadir/Common_Content/common/th-TH/Feedback.po
datadir/Common_Content/common/th-TH/Program_Listing.po
datadir/Common_Content/common/th-TH/Revision_History.po
datadir/Common_Content/common/th-TH/Revision_History.xml
datadir/Common_Content/common/tr-TR/Conventions.po
datadir/Common_Content/common/tr-TR/Feedback.po
datadir/Common_Content/common/tr-TR/Program_Listing.po
datadir/Common_Content/common/tr-TR/Revision_History.po
datadir/Common_Content/common/tr-TR/Revision_History.xml
datadir/Common_Content/common/uk-UA/Conventions.po
datadir/Common_Content/common/uk-UA/Feedback.po
datadir/Common_Content/common/uk-UA/Program_Listing.po
datadir/Common_Content/common/uk-UA/Revision_History.po
datadir/Common_Content/common/uk-UA/Revision_History.xml
datadir/Common_Content/common/zanata.xml
datadir/Common_Content/common/zh-CN/Conventions.po
datadir/Common_Content/common/zh-CN/Feedback.po
datadir/Common_Content/common/zh-CN/Program_Listing.po
datadir/Common_Content/common/zh-CN/Revision_History.po
datadir/Common_Content/common/zh-CN/Revision_History.xml
datadir/Common_Content/common/zh-TW/Conventions.po
datadir/Common_Content/common/zh-TW/Feedback.po
datadir/Common_Content/common/zh-TW/Program_Listing.po
datadir/Common_Content/common/zh-TW/Revision_History.po
datadir/Common_Content/common/zh-TW/Revision_History.xml
datadir/default.db
datadir/fop/fop.xconf
datadir/rpmlint.cfg
datadir/xsl/carousel.xsl
datadir/xsl/db4-upgrade.xsl
datadir/xsl/defaults.xsl
datadir/xsl/drupal-book.xsl
datadir/xsl/eclipse.xsl
datadir/xsl/epub.xsl
datadir/xsl/html-pdf.xsl
datadir/xsl/html-single-plain.xsl
datadir/xsl/html-single.xsl
datadir/xsl/html.xsl
datadir/xsl/man.xsl
datadir/xsl/merge_revisions.xsl
datadir/xsl/pdf.xsl
datadir/xsl/txt.xsl
datadir/xsl/xhtml-common.xsl
etc/publican-website.cfg
fdl.txt
lib/Publican.pm
lib/Publican/Builder.pm
lib/Publican/Builder/DocBook.pm
lib/Publican/Builder/DocBook4.pm
lib/Publican/Builder/DocBook5.pm
lib/Publican/CreateBook.pm
lib/Publican/CreateBrand.pm
lib/Publican/Localise.pm
lib/Publican/Translate.pm
lib/Publican/TreeView.pm
lib/Publican/WebSite.pm
lib/Publican/XmlClean.pm
LICENSE
MANIFEST This list of files
META.yml
perltidyrc
po/ar.po
po/as.po
po/ast.po
po/bg.po
po/bn_IN.po
po/bs.po
po/ca.po
po/cs.po
po/da.po
po/de-CH.po
po/de.po
po/de_CH.po
po/el.po
po/es.po
po/fa.po
po/fi.po
po/fr.po
po/gu.po
po/he.po
po/hi.po
po/hr.po
po/hu.po
po/ia.po
po/id.po
po/is.po
po/it.po
po/ja.po
po/kn.po
po/ko.po
po/lv.po
po/ml.po
po/mr.po
po/nb.po
po/nl.po
po/or.po
po/pa.po
po/pl.po
po/pom.xml
po/pt.po
po/pt_BR.po
po/publican.pot
po/ru.po
po/si.po
po/sk.po
po/sr.po
po/sr@Latn.po
po/sv.po
po/ta.po
po/te.po
po/th.po
po/uk.po
po/zanata.xml
po/zh_CN.po
po/zh_TW.po
pod1/publican
publican-releasenotes.desktop
publican.desktop
publican.spec
README
Release_Notes/en-US/Article_Info.xml
Release_Notes/en-US/Author_Group.xml
Release_Notes/en-US/images/icon.svg
Release_Notes/en-US/Release_Notes.ent
Release_Notes/en-US/Release_Notes.xml
Release_Notes/en-US/Revision_History.xml
Release_Notes/publican.cfg
rpm_templates/desktop-spec.tmpl
rpm_templates/spec.tmpl
rpm_templates/splash.tmpl
t/000.load.t
t/100.CreateBook.t
t/110.CreateBrand.t
t/200.XmlClean.t
t/300.Builder.t
t/310.DB5Builder.t
t/410.Translate.t
t/900.publican.t
t/910.publican.Users_Guide.t
t/920.WebSite.t
templates/anchor.tmpl
templates/books_format_menu.tmpl
templates/books_index.tmpl
templates/books_lang_menu.tmpl
templates/books_menu.tmpl
templates/index.tmpl
templates/labels.tmpl
templates/language_index.tmpl
templates/language_index_style_1.tmpl
templates/opds-langs.tmpl
templates/opds-prods.tmpl
templates/opds.tmpl
templates/products_index.tmpl
templates/products_menu.tmpl
templates/Sitemap.tmpl
templates/toc-oneline.tmpl
templates/toc.tmpl
templates/versions_index.tmpl
templates/versions_menu.tmpl
templates/web_2_footer.tmpl
templates/web_2_head.tmpl
TODO
Users_Guide/cs-CZ/Adding_Code_Samples.po
Users_Guide/cs-CZ/Adding_Files.po
Users_Guide/cs-CZ/Adding_Images.po
Users_Guide/cs-CZ/Applicable_to_RPM_only.po
Users_Guide/cs-CZ/Author_Group.po
Users_Guide/cs-CZ/Auto_Docs.po
Users_Guide/cs-CZ/Auto_Docs_Configs.po
Users_Guide/cs-CZ/Book_Info.po
Users_Guide/cs-CZ/Branding.po
Users_Guide/cs-CZ/Building_a_Book.po
Users_Guide/cs-CZ/Conditionaltagging.po
Users_Guide/cs-CZ/Creating_a_Book.po
Users_Guide/cs-CZ/Creating_a_Brand.po
Users_Guide/cs-CZ/Desktop_menu_spec.po
Users_Guide/cs-CZ/Desktop_menus.po
Users_Guide/cs-CZ/Disallowed_tags_and_attributes.po
Users_Guide/cs-CZ/Draft.po
Users_Guide/cs-CZ/Drupal_Import.po
Users_Guide/cs-CZ/Dump_File.po
Users_Guide/cs-CZ/Entities.po
Users_Guide/cs-CZ/FAQ.po
Users_Guide/cs-CZ/Files_in_the_Book_Directory.po
Users_Guide/cs-CZ/Files_in_the_Brand_Directory.po
Users_Guide/cs-CZ/Installing_a_Brand.po
Users_Guide/cs-CZ/Installing_Publican.po
Users_Guide/cs-CZ/Installing_Publican_Debian.po
Users_Guide/cs-CZ/Installing_Publican_Docker.po
Users_Guide/cs-CZ/Installing_Publican_OpenSuse.po
Users_Guide/cs-CZ/Introduction.po
Users_Guide/cs-CZ/Language_Codes.po
Users_Guide/cs-CZ/Packaging_a_Book.po
Users_Guide/cs-CZ/Packaging_a_brand.po
Users_Guide/cs-CZ/Permitted_alphanumeric.po
Users_Guide/cs-CZ/Permitted_integers.po
Users_Guide/cs-CZ/Permitted_numbers.po
Users_Guide/cs-CZ/Preface.po
Users_Guide/cs-CZ/Preparing_a_Book_for_Translation.po
Users_Guide/cs-CZ/Publican_Commands.po
Users_Guide/cs-CZ/Publican_Defaults.po
Users_Guide/cs-CZ/Renaming_a_document.po
Users_Guide/cs-CZ/Revision_History.po
Users_Guide/cs-CZ/Revision_History.xml
Users_Guide/cs-CZ/Root_nodes_and_conditionals.po
Users_Guide/cs-CZ/Sets.po
Users_Guide/cs-CZ/Websites.po
Users_Guide/cs-CZ/Websites_documents_manual.po
Users_Guide/cs-CZ/Websites_documents_rpm.po
Users_Guide/cs-CZ/Websites_homepage_manual.po
Users_Guide/cs-CZ/Websites_homepage_rpm.po
Users_Guide/cs-CZ/Websites_product_version_manual.po
Users_Guide/cs-CZ/Websites_product_version_rpm.po
Users_Guide/cs-CZ/Websites_structure_manual.po
Users_Guide/cs-CZ/Websites_structure_rpm.po
Users_Guide/cs-CZ/xrefs_and_conditionals.po
Users_Guide/en-US/Adding_Code_Samples.xml
Users_Guide/en-US/Adding_Files.xml
Users_Guide/en-US/Adding_Images.xml
Users_Guide/en-US/Applicable_to_RPM_only.xml
Users_Guide/en-US/Author_Group.xml
Users_Guide/en-US/Auto_Docs.xml
Users_Guide/en-US/Auto_Docs_Configs.xml
Users_Guide/en-US/Book_Info.xml
Users_Guide/en-US/Branding.xml
Users_Guide/en-US/Building_a_Book.xml
Users_Guide/en-US/Conditionaltagging.xml
Users_Guide/en-US/Creating_a_Book.xml
Users_Guide/en-US/Creating_a_Brand.xml
Users_Guide/en-US/Desktop_menu_spec.xml
Users_Guide/en-US/Desktop_menus.xml
Users_Guide/en-US/Disallowed_tags_and_attributes.xml
Users_Guide/en-US/Draft.xml
Users_Guide/en-US/Drupal_Import.xml
Users_Guide/en-US/Dump_File.xml
Users_Guide/en-US/Entities.xml
Users_Guide/en-US/extras/Author_Group.xml
Users_Guide/en-US/extras/Book_Info.xmlt
Users_Guide/en-US/extras/Book_Name.ent
Users_Guide/en-US/extras/Book_Name.xmlt
Users_Guide/en-US/extras/Chapter.xmlt
Users_Guide/en-US/extras/DUMP.xmlt
Users_Guide/en-US/extras/menu-example.directory
Users_Guide/en-US/extras/menu-example.menu
Users_Guide/en-US/extras/menu-example.spec
Users_Guide/en-US/extras/proof.sh
Users_Guide/en-US/extras/publican-acme.spec
Users_Guide/en-US/extras/publican.cfg
Users_Guide/en-US/extras/Set_Name.xmlt
Users_Guide/en-US/FAQ.xml
Users_Guide/en-US/Files_in_the_Book_Directory.xml
Users_Guide/en-US/Files_in_the_Brand_Directory.xml
Users_Guide/en-US/icons/16x16.png
Users_Guide/en-US/icons/22x22.png
Users_Guide/en-US/icons/24x24.png
Users_Guide/en-US/icons/32x32.png
Users_Guide/en-US/icons/48x48.png
Users_Guide/en-US/icons/icon.svg
Users_Guide/en-US/images/cover_thumbnail.png
Users_Guide/en-US/images/drupal_add_menu.png
Users_Guide/en-US/images/drupal_add_user.png
Users_Guide/en-US/images/drupal_book.png
Users_Guide/en-US/images/drupal_enable_node_import.png
Users_Guide/en-US/images/drupal_import_progress.png
Users_Guide/en-US/images/drupal_import_task.png
Users_Guide/en-US/images/drupal_node_import_settings.png
Users_Guide/en-US/images/icon.svg
Users_Guide/en-US/images/logos/engops.png
Users_Guide/en-US/images/testтimage.png
Users_Guide/en-US/Installing_a_Brand.xml
Users_Guide/en-US/Installing_Publican.xml
Users_Guide/en-US/Installing_Publican_Debian.xml
Users_Guide/en-US/Installing_Publican_Docker.xml
Users_Guide/en-US/Installing_Publican_OpenSuse.xml
Users_Guide/en-US/Introduction.xml
Users_Guide/en-US/Language_Codes.xml
Users_Guide/en-US/max_unique_id.db
Users_Guide/en-US/Packaging_a_Book.xml
Users_Guide/en-US/Packaging_a_brand.xml
Users_Guide/en-US/Permitted_alphanumeric.xml
Users_Guide/en-US/Permitted_integers.xml
Users_Guide/en-US/Permitted_numbers.xml
Users_Guide/en-US/Preface.xml
Users_Guide/en-US/Preparing_a_Book_for_Translation.xml
Users_Guide/en-US/Publican_Commands.xml
Users_Guide/en-US/Publican_Defaults.xml
Users_Guide/en-US/Renaming_a_document.xml
Users_Guide/en-US/Revision_History.xml
Users_Guide/en-US/Root_nodes_and_conditionals.xml
Users_Guide/en-US/Sets.xml
Users_Guide/en-US/Users_Guide.ent
Users_Guide/en-US/Users_Guide.xml
Users_Guide/en-US/Websites.xml
Users_Guide/en-US/Websites_documents_manual.xml
Users_Guide/en-US/Websites_documents_rpm.xml
Users_Guide/en-US/Websites_homepage_manual.xml
Users_Guide/en-US/Websites_homepage_rpm.xml
Users_Guide/en-US/Websites_product_version_manual.xml
Users_Guide/en-US/Websites_product_version_rpm.xml
Users_Guide/en-US/Websites_structure_manual.xml
Users_Guide/en-US/Websites_structure_rpm.xml
Users_Guide/en-US/xrefs_and_conditionals.xml
Users_Guide/fr-FR/Adding_Code_Samples.po
Users_Guide/fr-FR/Adding_Files.po
Users_Guide/fr-FR/Adding_Images.po
Users_Guide/fr-FR/Applicable_to_RPM_only.po
Users_Guide/fr-FR/Author_Group.po
Users_Guide/fr-FR/Auto_Docs.po
Users_Guide/fr-FR/Auto_Docs_Configs.po
Users_Guide/fr-FR/Book_Info.po
Users_Guide/fr-FR/Branding.po
Users_Guide/fr-FR/Building_a_Book.po
Users_Guide/fr-FR/Conditionaltagging.po
Users_Guide/fr-FR/Creating_a_Book.po
Users_Guide/fr-FR/Creating_a_Brand.po
Users_Guide/fr-FR/Desktop_menu_spec.po
Users_Guide/fr-FR/Desktop_menus.po
Users_Guide/fr-FR/Disallowed_tags_and_attributes.po
Users_Guide/fr-FR/Draft.po
Users_Guide/fr-FR/Drupal_Import.po
Users_Guide/fr-FR/Dump_File.po
Users_Guide/fr-FR/Entities.po
Users_Guide/fr-FR/FAQ.po
Users_Guide/fr-FR/Files_in_the_Book_Directory.po
Users_Guide/fr-FR/Files_in_the_Brand_Directory.po
Users_Guide/fr-FR/Installing_a_Brand.po
Users_Guide/fr-FR/Installing_Publican.po
Users_Guide/fr-FR/Installing_Publican_Debian.po
Users_Guide/fr-FR/Installing_Publican_Docker.po
Users_Guide/fr-FR/Installing_Publican_OpenSuse.po
Users_Guide/fr-FR/Introduction.po
Users_Guide/fr-FR/Language_Codes.po
Users_Guide/fr-FR/Packaging_a_Book.po
Users_Guide/fr-FR/Packaging_a_brand.po
Users_Guide/fr-FR/Permitted_alphanumeric.po
Users_Guide/fr-FR/Permitted_integers.po
Users_Guide/fr-FR/Permitted_numbers.po
Users_Guide/fr-FR/Preface.po
Users_Guide/fr-FR/Preparing_a_Book_for_Translation.po
Users_Guide/fr-FR/Publican_Commands.po
Users_Guide/fr-FR/Publican_Defaults.po
Users_Guide/fr-FR/Renaming_a_document.po
Users_Guide/fr-FR/Revision_History.po
Users_Guide/fr-FR/Revision_History.xml
Users_Guide/fr-FR/Root_nodes_and_conditionals.po
Users_Guide/fr-FR/Sets.po
Users_Guide/fr-FR/Websites.po
Users_Guide/fr-FR/Websites_documents_manual.po
Users_Guide/fr-FR/Websites_documents_rpm.po
Users_Guide/fr-FR/Websites_homepage_manual.po
Users_Guide/fr-FR/Websites_homepage_rpm.po
Users_Guide/fr-FR/Websites_product_version_manual.po
Users_Guide/fr-FR/Websites_product_version_rpm.po
Users_Guide/fr-FR/Websites_structure_manual.po
Users_Guide/fr-FR/Websites_structure_rpm.po
Users_Guide/fr-FR/xrefs_and_conditionals.po
Users_Guide/it-IT/Adding_Code_Samples.po
Users_Guide/it-IT/Adding_Files.po
Users_Guide/it-IT/Adding_Images.po
Users_Guide/it-IT/Applicable_to_RPM_only.po
Users_Guide/it-IT/Author_Group.po
Users_Guide/it-IT/Auto_Docs.po
Users_Guide/it-IT/Auto_Docs_Configs.po
Users_Guide/it-IT/Book_Info.po
Users_Guide/it-IT/Branding.po
Users_Guide/it-IT/Building_a_Book.po
Users_Guide/it-IT/Conditionaltagging.po
Users_Guide/it-IT/Creating_a_Book.po
Users_Guide/it-IT/Creating_a_Brand.po
Users_Guide/it-IT/Desktop_menu_spec.po
Users_Guide/it-IT/Desktop_menus.po
Users_Guide/it-IT/Disallowed_tags_and_attributes.po
Users_Guide/it-IT/Draft.po
Users_Guide/it-IT/Drupal_Import.po
Users_Guide/it-IT/Dump_File.po
Users_Guide/it-IT/Entities.po
Users_Guide/it-IT/FAQ.po
Users_Guide/it-IT/Files_in_the_Book_Directory.po
Users_Guide/it-IT/Files_in_the_Brand_Directory.po
Users_Guide/it-IT/Installing_a_Brand.po
Users_Guide/it-IT/Installing_Publican.po
Users_Guide/it-IT/Installing_Publican_Debian.po
Users_Guide/it-IT/Installing_Publican_Docker.po
Users_Guide/it-IT/Installing_Publican_OpenSuse.po
Users_Guide/it-IT/Introduction.po
Users_Guide/it-IT/Language_Codes.po
Users_Guide/it-IT/Packaging_a_Book.po
Users_Guide/it-IT/Packaging_a_brand.po
Users_Guide/it-IT/Permitted_alphanumeric.po
Users_Guide/it-IT/Permitted_integers.po
Users_Guide/it-IT/Permitted_numbers.po
Users_Guide/it-IT/Preface.po
Users_Guide/it-IT/Preparing_a_Book_for_Translation.po
Users_Guide/it-IT/Publican_Commands.po
Users_Guide/it-IT/Publican_Defaults.po
Users_Guide/it-IT/Renaming_a_document.po
Users_Guide/it-IT/Revision_History.po
Users_Guide/it-IT/Revision_History.xml
Users_Guide/it-IT/Root_nodes_and_conditionals.po
Users_Guide/it-IT/Sets.po
Users_Guide/it-IT/Users_Guide.po
Users_Guide/it-IT/Websites.po
Users_Guide/it-IT/Websites_documents_manual.po
Users_Guide/it-IT/Websites_documents_rpm.po
Users_Guide/it-IT/Websites_homepage_manual.po
Users_Guide/it-IT/Websites_homepage_rpm.po
Users_Guide/it-IT/Websites_product_version_manual.po
Users_Guide/it-IT/Websites_product_version_rpm.po
Users_Guide/it-IT/Websites_structure_manual.po
Users_Guide/it-IT/Websites_structure_rpm.po
Users_Guide/it-IT/xrefs_and_conditionals.po
Users_Guide/publican.cfg
Users_Guide/zanata.xml
web/chrome.css
web/db4.css
web/db5.css
web/default.js
web/Font-Awesome-4.2.0/css/font-awesome.css
web/Font-Awesome-4.2.0/css/font-awesome.min.css
web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.eot
web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.svg
web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.ttf
web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.woff
web/Font-Awesome-4.2.0/fonts/FontAwesome.otf
web/images/arrows.png
web/images/close.png
web/images/gradient1.png
web/images/gradient2.png
web/images/open.png
web/images/page.png
web/index.html
web/jquery-1.7.1.js
web/jquery-1.7.1.min.js
web/jquery.jcarousel.js
web/jquery.jcarousel.min.js
web/print.css
web/splash.css
win_build.pl
win_catalog.xml
windows/pp-opts
windows/publican.bmp
windows/publican.ico
windows/publican.nsi
windows/publican2.ico
xt/author/perlcritic.t
xt/author/pod-coverage.t
xt/author/pod.t
META.json
Changes 000444 041472 041472 163271 12555605450 15444 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 4.3.2 Tue Jul 28 2015
- Do not replace non-breaking spaces by spaces in msgid of POT files. BZ #1233202
- Fixed Unwanted line breaks around images. BZ #1222067
- Fixed EPUB output of db5 brands can't be viewed. BZ #1241348
4.3.1 Thu Jun 18 2015
- Fixed a regression in 4.3.0 that caused TOC's not to be included in wkhtmltopdf PDF's. BZ #1230023
- Fixed callout image urls being broken. BZ #1222716
4.3.0 Tue May 5 2015
- Fix web site templates to be more flexable.
- Tweak default website styles.
- Remove all FOP customisations. BZ #1168765
- Use FontAwesome for aswesomeness.
- Switch DocBook-5 HTML to highlight.js.
- Change splash page group publish directory structure so it can be used directly. BZ #1186990
- Fix duplicate link in Website docs. BZ #1188384
- Fix PDF builds ignoring overrides.css and lang.css. BZ #1165005
- Pulled in new/updated translations. BZ #1169605
- Removed duplicate IDs from PUG. BZ #1197523
- Removed the titlepage.xsl import from html-single due to breaking the xsl precedence. BZ #1187728
- Fix Publican doesn't fallback to base_brand xsl files. BZ #1185127
- Fix elements being stripped in drupal-book builds. BZ #1158747
- Fix malformed HTML/Drupal XML Feed for DocBook 5 content. BZ #1158740
- Fix incorrect missing image warnings for drupal builds. BZ #1158725
- Fix articles not building when using the drupal-book format. BZ #1164640
- Fix initial title page content being skipped when a user defines a custom bookinfo id. BZ #1165482
- Fix invalid XML being generated for drupal-book, when titles contain reserved chars. BZ #1165438
- Changed the drupal feed field to use the url value instead of the title. BZ #1165724
- Fix publican.cfg values are used in the feed page tag. BZ #1172402
- Fix drupal content is dropped, if the element that is chunked has no id. BZ #1173421
- Adjusted the XML output so anchors to something in the same page doesn't include the page url.
- Make legalnotice chunk in a similar way as chapters for drupal builds, so it's included in the feed.
- Enable section.label.includes.component.label for common-db5. BZ #1205952
- Fix formalpara ids being dropped for DocBook 4.5. BZ #1209344
- Add --no_clean option to allow custom entity files. BZ #1208069
4.2.6 Tue Oct 21 2014
- Fix External_Links translation not merging. BZ #1153911
4.2.5 Wed Oct 15 2014
- Fix DocBook4 epub failing for ja-JP. BZ #1152780
4.2.4 Tue Oct 14 2014
- Allow External_Links.xml to be translated. BZ #1150386
- Change ja-JP person-name style. BZ #1150866
4.2.3 Tue Oct 7 2014
- Fix DocBook4 entity text, BZ #1143060
- Remove extra white space from non-verbatim msgid's. BZ #1143792
- Fix PDF build using FOP fails with "No numberLines function available." BZ #1143852
- Add allow_network option. Defaults OFF. BZ #1144949
- Add hacks to work around BZ #1144220
4.2.2 Wed Sep 17 2014
- Fix duplicate messages in POT files. BZ #1136133
- Remove top level directory from drupal tar file. BZ #1139070
- Fix PDF font selection. BZ #1139899
4.2.1 Mon Sep 01 2014
- Remove empty msgids from POT files. BZ #1135143
- Fix highlight in callout with areaspec. BZ #1135827
4.2.0 Thu Aug 28 2014
- Add iframe video support to DocBook5 HTML5. BZ #752021
- Stop calculating column width if no width is set. BZ #1084860
- Simply styling of code, and admonitions in HTML5. BZ #1093498
- Added tip formatting. BZ #1033830
- Remove incorrect prompt. BZ #1096544
- Add "popper" to hide program listing after 4 lines. BZ #1088051
- Fix white space being removed from msgids when merging. BZ #1097090
- Add code language switching. BZ #1092351
- Fix CDATA support, bump XML::TreeBuilder dep to 5.3. BZ #1101050
- Add --showfuzzy to build options.
- Move PO manipulation to Locale::PO.
- Fix inline"\n" not working in verbatim. BZ #1097091
- Fix images for DB4 website callouts. BZ #1112899
- Remove newline after cdata. BZ #1110611
- Add Markdown output. BZ #1120455
- Bump Syntax::Highlight::Engine::Kate dep to 0.09.
- Add external link support. BZ #1123193
- Add 'th' to translation block list. BZ #1127462
4.1.7 Mon Aug 04 2014
- Another shot at fixing PDF index out of range error.
4.1.6 Tue Jul 29 2014
- Another shot at fixing PDF index out of range error.
4.1.5 Wed Jul 09 2014
- Add some web UI tranlstaion strings & sort formats. BZ #1117081
- Fix formal para title CSS. BZ #1110076
4.1.4 Thu Jul 03 2014
- Expose sort functions to version index page.
4.1.3 Wed May 21 2014
- Fix extra space breaking spec files with sort_order. BZ #1099262
- Make div.title bold in db4.css. BZ #1049661
4.1.2 Wed May 14 2014
- Fix broken DocBook5 validation stopping package builds. BZ #1097495
- Many updates to Users' Guide.
4.1.1 Thu May 8 2014
- Fix long tables and pre's breaking PDF build. BZ #1095574
4.1.0 Mon May 5 2014
- Add abstract to release notes so PDF builds
- Fix RPM upgrade not pulling in required XML::TreeBuilder version. BZ #1053609
- Allow PDF to build without any authors. BZ #1050975
- Increase XML::LibXSLT::max_depth to 10K. BZ #1035525
- Include entrytbl in cols count. BZ #1069405
- Add 'td' to translatable blocks list. BZ #1059938
- Treat entry like para for mixedmode tags. BZ #1039382
- Add blank page after cover page in PDF. BZ #1050770
- Fix replaceable override in DB 4.5 XSL. BZ #1054462
- Store processing instructions. BZ #1045463
- Add releaseinfo support. BZ #1050789
- Add support for wkhtmltopdf 0.12.0
- Add non-minified JS files. BZ #1062109
- Use term as ID node for varlistentry. BZ #1050836
- Fix acroread search and image issues. BZ #1038393 #1065810
- Add line numbering to DB5 html output. BZ #1074709
- Remove glossdiv and indexdiv headings from PDF TOC. BZ #1058545
- Add basic handling & style for revisionflag.
- Fix admonition style for wkhtmnltopdf 0.12.
- Pass chunk_section_depth to wkhtmltopdf. BZ #1044848
- Do not die on empty brand conf files. BZ #1037037
- Fix font embedding in PDF.
- Enforce RPM API requirements. BZ #1029293
- Fix desktop SPEC file creation. BZ #1081087
- Pass previous option to msgmerge. BZ #1081363
- Load splash pages in templates instead of using javascript. BZ #1081300
- Sync list layout across web and desktop styles. BZ #1080236
- Add dt_format parameter. BZ #1081808
- Provide gettext version of package name. BZ #1083102
- Fix step style. BZ #1080156
- Fix DD layout. BZ #1084242
- Fix tables breaking out. BZ #1082444
- Add zt_push and zt_pull for Zanata.
4.0.0 Wed Dec 18 2013
- Support DocBook 5 as input format. BZ #1005042
- Fix duplicate first author in PDF. BZ #996351
- Include DocBook 5-compatible templates. BZ #697366
- Fix UTF8 issue in ~/.publican.cfg. BZ #987325
- Replace abstract and subtitle xsl. BZ #953675
- Change Cover page font. BZ #1006134
- Fix TOC leader in PDF. BZ #1006056
- Fix PDF Legal Notice trademarks & formatting. BZ #970851
- Fix keyword lable showing in PDF when there are no keywords. BZ #1007146
- Indicate whether a translation is older in the web GUI. BZ #889031
- Include time in update_date. BZ #979846
- Support web site navigation for books without HTML. BZ #885916
- Support ascending Revision History. BZ #999578
- Add ability to compy installed brand web content to another site. BZ #967664
- Fix PDF example.properties template. BZ #999586
- Fix PUG PDF format for OpenSuse. BZ #999581
- Simplify highlight error message. BZ #987059
- Add css styles for table sizes. BZ #1005640
- Tidy up Build.PL for better CPAN support. BZ #999259
- Fix image path for icon.svg. BZ #1011222
- Fix print_unused not handling include from higher directories. BZ #1004955
- Fix SVG fallback to PNG. BZ #990823
- Fix subtitle font size. BZ #987431
- Support grouping of books within a version. BZ #901560
- Remove bold from titles in Indic scripts. BZ #1006135
- Overhaul EPUB, basic CSS, harcode chunking, fix errors. BZ #883159
- Fix duplicate file listing in EPUB. BZ #875119
- Fix objects in EPUB not in catalog. BZ #875125
- Fix duplicate ID's in EPUBs. BZ #875116
- Fix ConfigData not being reset after testing on all platforms. BZ #999427
- Fix links to step not functioning. BZ #1009015
- Support GIT for distributed sets. BZ #864226
- Fix Build.PL not handling .mo files. BZ #1016421
- Bold and Center titlepage edition. BZ #1017548
- Fix broken use of pushd in Build.PL. BZ #1018608
- Remove XML from spec file abstract. BZ #1018796
- Fix UTF8 in publican.cfg not being handled. BZ #1020059
- Fix Indic PDF build on F19. BZ #1018024
- Fix UTF8 encoding for title in Revision_History.xml BZ #1020570
- Fix browser not detecting UTF8 on HTML5 files with .html extension. BZ #1018659
- Fix styling of DB4 example, package, & option. Remove html.longdesc.embed xsl. BZ #1023248
- Fix UTF8 in Groups.xml. BZ #1022575
- Add translations for "Edition" BZ# 1007141
- Add translations for "English is newer" BZ #889031
- Fix broken or-IN translation.
- Update DB4 CSS steps, stepalts, OLs, term. BZ #1026173
- Remove chunk override from html.xsl. BZ #1026563
- Fix path to POD. BZ #1026563
- Update CLI translations
- Various fixes to Common Content + update Common Content translation. BZ #1027248
- Update and correct Debian installation instructions. BZ #1013934
- Correct OpenSUSE installation instructions. BZ #1000534
- Add Docker installation instructions. BZ #1015943
- Clarify where relative paths are used in brand instructions - BZ #1028815
- Update and clarify translation instructions BZ #1021287
- Expose glossterm in PO files to support sortas attribute. BZ #1030591
- Add report action to print readability statistics. BZ #1031364
- Change comment in syntax highlight to light grey. BZ #1030718
- Document use of "sortas" for indexes and glossaries in PUG
- Fix newline in translation affecting output. BZ #1036150
3.2.1 Wed Sep 04 2013
- Fix empty images dir causing packaging fail. BZ #995896
- Fix draft background being in front. BZ #996361
- Fix Titles that are ulinks are incorrectly positioned. BZ #995095
- Fix Syntax Highlighting not working when Language and Module names differ. BZ #995932
- Fix missing '/' on callout image url. BZ #998736
- Add string for brand customistaion BZ #1002388
- Fix translations updates missing from common PO files. #1000935
3.2.0 Thu Aug 8 2013
- Add spaces to web-spec.xsl to work around newer libxml2 eating white space in spec files. BZ #982424
- Fix typos in common content. BZ #952490 #974918
- Stop menu bouncing. BZ #953716
- Fix ID missing from admonitions. BZ #966494
- Support corpauthor for PDF. BZ #908666
- Fix nested block tags breaking translation flow. BZ #909728
- Fix multiple calls to update_po breaking packaging. BZ #891167
- Add website labels and translations. BZ #979885
- Add orgname to block/inline code. BZ #872955
- Fix get_keywords not using correct info file. BZ #957956
- Improve web print CSS. BZ #927513
- Fix pre border in PDF. BZ #905752
- Fix epub DOCTYPE. BZ #875129
- Fix step first child style. BZ #971221
- Fix long link word wrap in PDF. BZ #923481
- Support case-insensitive "language" attribute. BZ #919474
- Apply title style patch from Jaromir Hradilek. BZ #924518
- Expose %book_ver_list to products/versions_index.tmpl. BZ #962643
- Allow brands to ship web templates. Add site config toc_js. BZ #956935
- Add pdftool option to build for pdf tool control. BZ #953728
- Add default mapping for language to locale. BZ #844202
- Fix ID missing from translated Revision History. BZ #911462
- Add pub_dir option to override publish directory. BZ #830062
- Removed show_unknown parameter and associated code. BZ #915428
- Add img_dir parameter to override images directory. BZ #919481
- Support all DocBook conditionals. BZ #919486
- Flag spaces in product number as invalid. BZ #973895
- Standardized prompts in commands. BZ #880456
- Updated web_formats publican.cfg info BZ #839141
- Replaced 'home page' with 'product or version page' BZ #921803
- Replaced a broken link to CPAN with a working link BZ# 973461
- Remove duplicate brand files from base install. BZ #966143
- Add extras_dir parameter to override extras directory. BZ #953998
- Fix PDF ignoring cover logo. BZ #974353
- Add trans_drop action to freeze source language for translation. BZ #887707
- Fix empty pot files not being deleted. BZ #961413
- Fix long title layout on cover page in PDF. BZ #956934
- Add Mac OS X Lion installation instructions. BZ# 979229
- Add file handle limit workaround to FAQ BZ #952476
- Support CDATA tags. BZ #958343
- Fix UTF8 image names getting mangled in publish. BZ #953618
- Add wkhtmltopdf_opts parameter to pass options to wkhtmltopdf. BZ #951290
- Fix edition missing on PDF cover pages. BZ #956940
- Support XML in add_revision member. BZ #862465
- Fix duplicate footnotes in bibliography. BZ #653447
- Fix Link from footlink to footlink-ref not working in PDF. BZ #909786
- Fix TOC draft watermark in PDF. BZ #905271
- Add common-db5 sub package. BZ #958495
- Support decimals in colwidth & convert exact measures to pixels. BZ #913775
- Tweak equation formatting. BZ #804531
- Fix POT-Creation-Date format. BZ #985836
- Fix site stats report swapping languages and products.
- Fix web_dir not used for home page packages. BZ #988191
- Updated web site instructions - BZ#979224
3.1.5 Mon Mar 18 2013
- Fix translated PDF encode issue when build from packaged books. BZ #922618
3.1.4 Tue Mar 12 2013
- Fix entities in Book_Info braking build. BZ #917898
- add translations of "Revision History". BZ #918365
- Fix TOC title not translated in PDF. BZ #918365
- Fix translated strings with parameters. BZ #891166
- update translations
- add it-IT translation of PUG via BZ #797515
3.1.3 Fri Feb 22 2013
- Fix add_revision breaking XML parser. BZ #912985
- Stronger fix for cover pages causing page number overrun. BZ #912967
- Fix CSS for article front page subtitle. BZ #913016
3.1.2 Tue Feb 19 2013
- Fix tests failing when publican not installed. BZ #908956
- Fix broken mr-IN/Conventions.po. BZ #908956
- Fix footnote link unclickable. BZ #909006
- Fix missing translations for common files. BZ #908976
- Fix using edition for version on cover pages. BZ #912180
- Fix nested entities causing XML::TreeBuilder to fail. BZ #912187
- Fix for cover pages causing page number overrun. BZ #912967
- Fix PDF ignoring logo image. BZ #974353
3.1.1 Thu Feb 07 2013
- Fix web site CSS for admonitions breaking layout for books built on P3.0. BZ #908539
3.1.0 Wed Feb 06 2013
- Add Interlingua support from Nik Kalach BZ #863899
- Replace hard coded paths with Publican::ConfigData. BZ #661946
- Ensure Publican source builds and tests without Publican being installed. BZ #874180
- Fix broken menu alignment. BZ #880621
- Ensure clean_ids doesn't change owner or group. BZ #854425
- Fix incorrect Revision order. BZ #845432
- Add OpenSuse Install Section by Norman Dunbar . BZ #787243
- Fix POD typos. BZ #874277
- Remove place holder P tag from HTML para. BZ #847206
- Allow brands to override DocType Type and URI. BZ #839128
- Ignore unexpected parameters in cfg file, and emit a message. BZ #875021
- Support scripts directory in brands. BZ #839975
- Remove hard coded border from tables. BZ #875967
- Allow menu_category to be localisable. BZ #872432
- Fix UTF8 in brand_path breaking build. BZ #875021
- Support wkhtmltopdf cover pages. BZ #874344
- Add support for book_templates in brands. BZ #874344
- Fix draft not appearing in PDF. BZ #873586
- Change some H tags to DIV. BZ #846899
- Remove DocBook TOCs from PDF. BZ #874795
- Use better TOC for PDF. BZ #879388
- Fix directory ownership in SPEC file. BZ #894522
- Fix link resloution. BZ #879388
3.0.0 Wed Oct 31 2012
- Update Changes file. BZ #661568
- Cleaned up README file.
- Corrected document conventions text. BZ#651616
- Make XmlClean use File::Inplace instead of grep & sed. BZ #661567
- Deleted STRICT mode. Added banned_tags and banned_attrs configurations. BZ #663202
- Fix command example in PUG. BZ #663211
- Use revision history for edition and release. BZ #642127
- Deleted edition and release config parameters. BZ #642127
- Add add_revision action and associated options. BZ #642127
- Fix wrong BuildRequires and path for desktop packages. BZ #676472
- Correct typos. Yuri Chornoivan BZ #676997
- Fix CreateBook texts missing from pot file. BZ #677119
- Add --msgmerge to update_po to override using internal POT/PO merging. BZ #661569
- Added base_brand config option for brands to allow multiple base brands. BZ #697367
- Added site config toc_type to allow selecting TOC styles. BZ #697375
- Added authortest target for author tests.
- Purge Site statistics, site tech and HTML site map. BZ #697376
- Truncate PO Fuzzy/Un-transtaled message, added PO line number. BZ #697380
- Add Author_Group.xml handling for translations. BZ #697371
- Split pod from publican command to allow auto-generation.
- Fix bridgehead links not working in html. BZ #711348
- Re-add API check. BZ #742097
- Fix wkhtmltopdf format when building web packages.
- Fix sort order of books in website navigation. BZ #743792
- Extra bottom margin for screen. BZ #738689
- Change stepalternative list style. BZ #687894
- Add print_unused_images action. BZ #724850
- Fix print_unused not matching relative paths. BZ #740417
- Fix empty parameters being parsed as arrays. BZ #744964
- Removed border from blockquote. BZ #734154
- No newline after email when inline. BZ #745304
- Add Indic fonts to RPM spec requires.
- Switch RPM spec requires from FOP to wkhtmltopdf
- Remove old2new action & Makefile::Parser dep. BZ #752640
- Override install & common paths on darwin. BZ #752620
- Remove Image::Magick & Image::Size deps and max_image_width option. BZ #752637
- Treat graphic like imagedata. BZ #754340
- Support superscript, fix color. BZ #726548
- Fix test warnings and errors. BZ #747871
- Change title page layout.
- Remove trailing slash from --langs completion. BZ #757182
- Remove white space munging from XmlClean. BZ #756756
- Fix corpauthor killing FOP. BZ #756864
- Remove --cvs option.
- Update Conventions translation in pt-BR
- Fix build failing when source language directory is read only. BZ #798484
- Add src_dir parameter to allow building outside source tree. BZ #798485
- Apply Spanish translation update from Ismael Olea. BZ #787739
- Added web_cfg to allow non-standard paths for rpm based web sites.
- Ensure xml:lang is set by XmlClean for DocBook 5 sources. BZ #696397
- Added handling of defaults file. BZ #599283
- Catch txt not being rebuilt. BZ #802576
- Catch invalid version when installing book. BZ #748657
- Fix duplicate IDs in HTML outputs. BZ #788576
- Fix some epub validation errors. BZ #701667
- Add brand_dir option and publican XSL name space. BZ #800252
- Consolidate DataBase entries. BZ #707833
- Add sort_order parameter. BZ #744661
- Fix para tag not getting newline in TXT output. BZ #773120
- Rework toc style to fit long name products and books. BZ #696834
- Fix PO merge output order. BZ #808088
- Fix new entires in merged PO being double escaped. BZ #818768
- Fix false warning "Message missing from PO file". BZ #737426
- Fix create_brand not copying images. BZ #832345
- Fix rename requiring --name parameter. BZ #694698
- Add rev_file and info_file parameters. BZ #804917
- Fix multiple actions not being caught. BZ #838427
- Fix web_style 1 index being used when splash is installed on web_style 2 site.
- Fix table layout in HTML. BZ #847025
- Add file name to error message. BZ #846812
- Add print.css to generic web site. BZ #847552
- Fix missing IDs from many objects. BZ #848610
- Keep processing instructions in XML. BZ #819420
- Fix DOCTYPE in revision history merge. BZ #849030
- Fix incorrect Revision order. BZ #845432
- Fix fop.xconf missing. BZ #831475
- Fix ID dedupe code for sections. BZ #856555
- Fix clean_ids changing file perms. BZ #854425
- Added Drupal 6 export. BZ #850635
- Fail to import rows which title is longer than 128 characters. BZ #860927
- When update the drupal book, the index displays twice. BZ #861374
- Cannot generate drupal book in publican-doc-3.1-0.el6eng.t7 BZ #863927
- Fix DocBook5 subtitle support. BZ #850497
2.8 Thu Sep 22 2011
- Fix draft mode always on in PDF. BZ #740123
- Remove rpmlint checks. BZ #735688
- Fix Too late for -CA messages in tests. BZ #738161
2.7 Tue Sep 06 2011
- Relax version constraint. BZ #729824
- Only set dist for rpmbuild if os_ver set. BZ #729826
- Re-enable draft mode. BZ #727756
- Don't wait for brew unless told to. BZ #731601
- Place icons directory in lang dir when packaging. BZ #732608
- Fix eclipse not loading eclipse help output. BZ #727739
- Fix part TOC layout. BZ #671304
- Add code to test wkhtmltopdf.
- Change default web_formats order to make wkhtmltopdf faster.
- Fix quote being escaped in TOC. BZ #734290
2.6-3 Thu Jul 28 2011
- Force publican to use UTF8 for command line options.
- Add rpmlint cfg for brew checks.
2.6-2 Wed Jul 27 2011
- Fix archness ... java hate increases
2.6 Mon Jul 25 2011
- Catch FOP failing. BZ #661551
- Have XmlClean treat address element as verbatim. BZ #662907
- Fix task missing ID. BZ #672439
- Fix startinglinenumber ignored & XML entites not being escaped. BZ #653432
- Fix perl critic encoding check failing. BZ #684509
- Update docbook-style-xsl req to 1.76.1 for epub change. BZ #697382
- Add keep_id to steps. BZ #697370
- Update BZ links to point to Publican component.
- Catch empty tags that break packaging. (abstract, subtitle) BZ #663206
- Add rpmlint check for mock builds. BZ #663203
- Fix web menu localisation being lost on rebuild from package. BZ #662897
- Fix UTF8 issue in TXT output. BZ #673855
- Fix some set validation errors. BZ #673402
- Fix packaging of stand alone sets. BZ #689347
- Switch normal output to STDOUT, added croak call. BZ #688447
- Added mainfile parameter. BZ #688585
- Add rename action. BZ #694698
- Added detection of mixed_mode tags to XmlClean. BZ #688286
- Add update_db action to allow more robust packaging. BZ #661948
- Fix show_unknown not working. BZ #662162
- Fix version 0 not installing on web site. BZ #702550
- Don't validate xml parsed as text in print_unused. BZ #705956
- Add manual_toc_update config for web-sites. BZ #719573
- Use the force option for cvs-import.sh BZ #718102
- Fix admonition layout. BZ #715158
- Fix indexterm tag causes a line split in PDF. BZ #713669
- Add no_embedtoc config for brands. BZ #723725
- Removed auto addition of '-0' to invalid revnumber. BZ #628464
2.5 Fri Dec 02 2010
- Use SPEC_VERSION for splash page spec files
- Force removal of old packages
2.4 Thu Dec 02 2010
- Add de.po to MANIFEST
- Add menu hide option. BZ #650037
- Only set title attribute in HTMl if alt text is set. BZ #651247
- Changed tabs to spaces in the specfile xsl BZ #652120
- Fix broken version splash page icon. BZ #647360
- Add web_formats option. BZ #647360
- Add Lohit Devanagari to Marathi font list. BZ #654554
- Stop publican setting imagedata format. BZ #654939
- Fix DocBook 5 DTD string format change. BZ #655621
- Add dt_requires and menu_category options. BZ #647352
- Remove web PDF from Indic + ar-SA,fa-IR,he-IL. BZ #655713
- Fix publish breaking UTF8 file names. BZ #648126
- Fix non-en lang breaking website strings. BZ #656139
- Fix IE8 javascript and layout issues. BZ #656531
- Remove Red elements from interactive.css. BZ #650950
- Added support for home page site_overrides.css file. BZ #650950
- Add check for outdated SRPMS.
- Enable override RPM site config. BZ #695545
2.3 Tue Oct 26 2010
- Prepend product name to product/version splash pages.
- Fix bash completion for --brand and --type.
- Use --nocolours in spec files.
- Update tocs when home/product/version pages are updated. BZ #612027
- Scroll to current entry in navigation menu.
- Highlight current book in navigation menu.
- Fix single quote in abstract/subtitle breaking RPM install. BZ #642088
- Fix RPM website not installing cleanly.
- Fix splash page icon wrap. BZ #642109
- Moved titles before: example, equation, table. BZ #638787
- Change html and PDF style for verbatim & example. BZ #638787
- Change html and PDF style for admonitions. BZ #638787
- Fix HTML footer style and layout.
- Add bump action Tech Preview.
- Fix indexterm merge missing nested nodes. BZ #643275
- Add phrase to translatable tag list. BZ #643287
- Fix POT files breaking when using HTML::Tree 4.0.
- Fix translated label missing from manually installed book. BZ #643781
- Add icon.svg to Create Book. BZ #644105
- Add XML dump options for site config.
- Fix histroy typo
- Stop max_image_width overriding XML width settings.
- Decrease white space at top and bottom of PDF.
- Fix toc links to refentry in chunked HTML. BZ #645602
- Fix bridgehead links not working in html. BZ #711348
2.2 Wed Oct 06 2010
- Extend callout graphics to 40; adjust colour and font BZ #629804
- Make keycombo example consistent with RHEL6 behaviour. BZ #618735
- Restrict CSS style for edition to title pages to avoid applying to bibliographies
- Fix images/icon.svg breaking rpm build. BZ #612515
- Fix empty term breaking PDF build. BZ #614728
- Fix footnote not catching modified para. BZ #565903
- Fix SRPM not including web labels. BZ #621036
- Update tocs when home page is updated. BZ #612027
- Don't display stats for unused languages. BZ #613500
- Fix admonitions/varlistentry not having IDs. BZ #616112
- Fix procedure/itemizedlist/orderedlist not having IDs. BZ #612817
- Catch invalid revision in translation. BZ #621721
- Limit index.html redirection to installed languages. BZ #612009
- Fix smaller width being overridden by max_image_width. BZ #613140
- Fix support for def_lang for web sites. BZ #622030
- Remove ant trails from selected links.
- Add --novalid option to disable validation when building. BZ #616142
- Revert change to escaping ', ", >, <. BZ #628266
- Add support for product and version splash pages. BZ #613502
- Fix unused version breaking product hiding.
- Add support for alerts for parameters.
- Add bash completion.
- Validate revnumber for changelog. BZ #628464
- Add basic man page support. BZ #632027
- Add basic support for line numbers. BZ #629463
- Add warning messages for out of date translations.
- Add productname to IGNOREBLOCKS. BZ #625316
- Add OPDS support. BZ #615831
- Fix translated labels in web nav. BZ #631647
- Remove highlighting from output of prompt tag in html. BZ #618902
- Resize index title font to a sane size. BZ #624392
- Fix misapplied fonts for CJK. BZ #628786
- Fix attributes breaking translation merge. BZ #638816
- Fix entities missing from RPM description. BZ #626254
- Add bridgehead_in_toc parameter. BZ #616123
- Support '--lang all' for lang_stats.
- Left align CJK in PDF. BZ #639811
- Fix constraint regex on docname and productname. BZ #640082
2.1 Tue Jul 06 2010
- Fix broken install_book not updating DB.
- Fix typos in docs.
2.0 Tue Jul 06 2010
- Add Publican::Website.
- Add web_*_label params for web menus.
- Add underscores to cleanset, installbrand, and printtree. BZ #581090
- Update docs with Website content
- Update brand license text.
- Fix different log jar path on F14+
- Add constraint to help_config output.
- Fix segfault when indexterm has no leading content. BZ #592666
- Fix inline indexterm. BZ #592823
- Translate productname tag. BZ #592669
- Fix formalpara missing ID. BZ #595564
- Add dummy lang.css to avoid 404's. BZ #595799
- Improve validation error message. BZ #593887
- Fix qandaentry ID. BZ #593892
- Fix Icon non-conformance. BZ #593890
- Fix admonitions splitting across pages. BZ #596257
- Fix HTML simple list border. BZ #599258
- Fix formal object IDs. BZ #601363
- Fix Revision History layout. BZ #559787 #598828 #598833
- Remove title color from term in HTML. BZ #592822
- Fix highlight breaking callouts. BZ #590933
- Add support for LineColumn coords in area tag.
- Update font requires for F12 and F13.
- Fix clean_ids adding newline to verbatim. BZ #604465
- Fix index missing ID. BZ #606418
- Fix files dir being missed. BZ #609345
- Adjust admonition layout.
1.6.3 Wed May 12 2010
- Disable verbatim hyphenation. BZ #577068
- Fix anchors breaking HTML. BZ #579069
- Fix common options not in help text.
- Fix formatting of abstract in spec. BZ #579928
- Translate verbatim tags. BZ #580360
- Add print_unused option. BZ #580799
- Overwrite zero length PO files. BZ #581397
- Fix citerefentry breaking translation. BZ #581773
- Fix reference bug in html-single.
- Added print_known and print_banned actions.
- Fix typo in POD. RaphaУЋl Hertzog
- Fix indexterm translation. BZ #582255
- Fix non-breaking space being treated like normal white space. BZ #582649
- Fix webkit & pdf table borders. BZ #585115
- Make indexterm translatable. BZ #582680
- Make keyword translatable. BZ #583224
- Add Eclipse help target. BZ #587489
- Convert MAX_WIDTH to a parameter max_image_width. BZ #580774
- Add confidential text to title, first, and blank pages in PDF. BZ #588980
- Add confidential_text parameter. BZ #588980
- Fix article list formatting in HTML. BZ #588999
- Fix epub validation issues. BZ #589333
- Fix xref to term with indexterm BOOM. BZ #580751
- Fix keyword highlight breaking callouts. BZ #590933
- Fix right icon misaligned. BZ #590964
1.6.2 Thu Apr 01 2010
- Fix hyphenate.verbatim running out of depth. BZ #577095
- Fix UTF8 error in translations. BZ #576771
- Add surname and othername to translatable tag list. BZ #578343
- No fuzzy strings in merged XML. BZ #578337
- Allow clean_ids to add entity reference. BZ #576462
- Added --quiet and --nocolours. BZ #578366
1.6.1 Mon Mar 22 2010
- Fix package_brand including unwanted files. BZ #570715
- Fix empty lines breaking callouts. BZ #570046
- Detect verbatim content in translatable content. BZ #571633
- Fix missing IO::String requires properly. BZ #568950
- Add print style sheet to XHTML. RT #60327
- Force UTF8 on all files. BZ #570979
- Fix comments in callout breaking build. BZ #572047
- Fix table border display. BZ #572995
1.6 Mon Mar 01 2010
- Fix missing IO::String requires. BZ #568950
- Fix xml_lang error. BZ #569249
1.5 Fri Feb 26 2010
- Croak if profiling would remove root node.
- Add Archive::Zip to Build.pl
- Fix --config and add to help text
- Force footnotes and indexterms to be inline for translations. BZ #563056
- Add CVS package option. RT #59132
- Fix white space issues in abstract. BZ #559823
- Fix translation strings not matching correctly BZ #563397
- Fix entity with underscore. BZ #561178
- Fix config values of zero being ignored. BZ #564405
- Fix footnote number missing in footer. BZ #565903
- Fix duplicate text in callouts. BZ #561618
- Remove outdated references to catalogs parameter. BZ #565498
- Fix white space in book name breaking creation.
- Fix nested tag with similar name breaking translation. BZ #568201
- Fix translated packages using source version.
- Switch from object to iframe BZ #542524
- More accurate word counts for translations reports.
1.4 Fri Jan 29 2010
- make font BuildRequires match requires.
1.4 Mon Jan 25 2010
- Ignore obsolete entries in stats code. BZ #546130
- Fix valid_lang matching on unknown languages.
- Fix invalid tag in DTD. BZ #548629
- Added contrib to translation tag list. BZ #550460
- Added firstname, lastname, orgname to translation tag list. BZ #555645
- Remove comments from translations. BZ #555647
- Fix content in root nodes not being added to pot. BZ #554261
- Fix mixed mode content being dropped when merging translations. BZ #549925
- Fix ID creation in refentry. BZ #553085
- Add gettext Requires. BZ #550461
- Fix non-default tmp dir. BZ #551974
- Fix validation output. BZ #556684
- Fix tag attributes breaking translation merge. BZ #554230
- Format XML when running create. BZ #556201
- Switch Japanese font to ipa-gothic-fonts on Fedora.
- Fix Japanes mono/proportional font selection.
- Add TTC build time script. BZ #557336
- Add check for main file before parsing.
- Add check for OS before running FOP.
1.3 Tue Dec 08 2009
- Fixed --version BZ #533081
- Fixed empty params in new book cfg file. BZ #533322
- Fixed clean_ids taking too long.
- Added nowait option for brew.
- Improved epub support. BZ #536706
- Add missing rpm-build req. BZ #537970
- Changed ol ol style. BZ #537256
- Fix missing revision history field crash. BZ #539741
- Fix bug in condition logic in XmlClean. BZ #540685
- Add translation stats. BZ #540696
- Stopped processing xml files in extras dir. BZ #540383
- Fixed callout rendering. BZ #531686
- Fix wrong docs for condition usage. BZ #540691
- Remove list style from stepalternatives. BZ #511404
- Force step::para to keep-with-next if followed by a figure.
- Edited Conventions.xml.
- Exclude Legal_Notice.xml from pot creation.
- Fix nested XML breaking translations.
- Fix syntax highlighting adding whitespace. BZ #544141
- Better error message for Kate language mismatch.
1.2 Wed Nov 4 2009
- Fix images missing from distributed set output. BZ #532837
- Correct image path when running clean_ids.
- Fix typo in format description. BZ #532379
- Add comment to clean.
- force package to run clean to avoid stale content. BZ #538676
1.1 Mon Nov 2 2009
- Fix brew failure. BZ #532383
- Fix distributed sets no packaging properly.
- Translation of Document Conventions to Greek. Dimitrios Typaldos
1.0 Mon Oct 26 2009
- Add base langauge summary & descriptions to translated spec file. BZ #515573
- Fix translated package build failure.
- Change tabs to spaces in generated spec files.
- Fix Locale::Maketext::Gettext dep being missed on RHEL.
- Fix common paths on Windows
- Added docbook-style-xsl dep for version 1.75.1+
- POD fix from Mikhail Gusarov
- Added processing file message to update_pot. BZ #518354
- add EPUB stub
- Clean up Copyright in numerous files.
- Add security callback for exslt:document.
- Update XML::LibXML & XML::LibXSLT minimum versions to 1.67
- Fix rounded corners in HTML. BZ #509768
- Fix nested images breakin in PDF. BZ #491782
- Remove border from HTML table for simplelist. BZ #502126
- Fix remarks not being highlighted in PDF. BZ #509307
- Resize shade.verbatim font size. BZ #497462
- Change step page size limitation to para size limitation. BZ#492984
- Add warning message for missing images. BZ #495821
- Fix fuzzy images. BZ #479794
- swap from paths from Publican to publican and obsolete beta packages.
- Fix large example PDF issue. BZ #531685
- Translation of Document Conventions to Asturian. IУБigo Varela
- Adaptation of Document Conventions from de-DE for de-CH. Fabian Affolter
- Correct typos in de-DE. Fabian Affolter
- Translation of Document Conventions to Bulgarian. Martin Stefanov
- Update of Document Conventions in Polish. Piotr DrФ g
- Translation of Document Conventions in Ukrainian. Maxim V. Dziumanenko
- Translation of Document Conventions to Finnish. Ville-Pekka Vainio
- Translation of Document Conventions to Croatian. Josip Х umeФki
- Translation of Document Conventions to Catalan. Robert Buj
0.99 Sat Jul 18 2009
- Rebase to Perl rewrite.
0.45 Wed Mar 25 2009
- Add keep-together.within-column="always" to step. BZ #492021
- Fix right to left fo ar-AR. BZ #486162
- Patches and translations by Muayyad Alsadi
- Added missing doccomment and number to PDF highlight. BZ #491241
- Fix files dir missing from RPMs. BZ #492034
0.44 Wed Mar 11 2009
- Add 0-9 and '.' to DOCNAME regex. BZ #489626
0.43 Mon Mar 9 2009
- Fix many warnings about 'body-start() called from outside an fo:list-item' BZ #484628
- Fix Initial build of new lang failing. BZ #485179
- Add lang to final doc root node. BZ #486162
- Add embed for stanky IE. BZ #486501
- Add symlinks for langauges without country codes. BZ #487256
- Add rudimentary Obsoletes logic. RT #36366
- Rolled in following from fedora devel spec
- - Mon Feb 9 2009 Jens Petersen - 0.40-4
- - update the sazanami-fonts subpackage names
- - list liberation-fonts subpackages explicitly
- - Fri Feb 6 2009 Alex Lancaster - 0.40-3
- - Fix broken font deps: liberation-fonts -> liberation-fonts-compat
- - Sat Jan 24 2009 CaolУЁn McNamara - 0.40-2
- - cjkunifonts-uming -> cjkuni-uming-fonts
- - Thu Jan 22 2009 Alex Lancaster - 0.40-1
- - Font changes baekmuk-ttf-fonts-batang -> baekmuk-ttf-batang-fonts to
- fix broken deps in rawhide
- Translate Document Conventions into Polish. Piotr DrФ g
- Translate common Feedback section into Polish. Piotr DrФ g
- Translate Document Conventions into Dutch. Richard van der Luit
- Translate Document Conventions into European Portuguese. Rui Gouveia
- Translation of Document Conventions to Indonesian. Teguh DC
0.42 Thu Jan 29 2009
- Support chapterinfo, keywordset & keyword tags.
- Add SRC_URL. BZ #482968
- Fix web package removal when dep package has been removed.
0.41 Mon Jan 19 2009
- Fix Source tar name.
- Fix brew srpm path
- Added OS_VER to allow over ride of OS srpm is created for.
0.40 Mon Jan 5 2009
- Fix DRAFT mode in web docs.
- Fix TOC CSS spacing.
- Fix missing syntax highlighting templates. BZ #474077
- Added appendix to user guide for Makefile parameters. BZ #476913
- Fix multiple authors in revhistory. Patch by: Paul W. Frields. BZ #478552
- Add LICENSE override for RPMs. BZ #477720
- Fix empty change log. BZ #477728
- Fix spec file location. BZ #477704
- Added newline after country. BZ #477573
- Fix minimum font size breaking TOC. BZ #476884
- Fix missing font-metric files. BZ #479592
- Updated redhat brand license. BZ #478405
- Update jboss brand license. BZ #478416
- Ship PDF with Indic web packages.
0.39 Mon Dec 1 2008
- Disable make.graphic.viewport. BZ #467368
- Add missing XEP namespace. BZ #467256
- Add catch for ValidateTables where table for tgroup could not be found. BZ #468789
- Fix right margin error on verbatim and admonitions in PDF. BZ #467654
- Added foreignphrase to list of validated tags.
- Add foreignphrase, acronym, hardware to list of tags aspell should ignore.
- Fixed left align of verbatim items in notes.
- Fixed contrib class in CSS. BZ #469595
- Changed para & simpara to div in HTML. BZ #469286
- Fix layout of author in Revision History. BZ #469986
- Validated function tag. BZ #471144
- Fixed menu entry text. BZ #470967
- Validated type, methodname, excAppendix.xmleptionname, varname, interfacename tags. BZ #461708
- Banned glosslist (untranslatable) BZ #461864
- Validated uri, mousebutton, hardware tags. BZ #461870
- Validated othername tag. BZ #464315
- Removed collab from front page to match PDF output. BZ #469298
- Formalised handling of draft mode, root node only. BZ #468305
- Removed old help text from create_book and make type case insensitive. BZ #471776
- Fixed footnote numbers collapsing together. BZ #462668
- Fix translation report for po in nested directories.
- Changed Formal Para Title to follow parent indent. BZ #466309
- Validated qandadiv, tweaked layout. BZ #472482
- Handle xslthl:annotation. BZ #472500
- Fix dot on docnav css. BZ #472627
- Fix ol display in article. BZ #472491
- Added section of Drafting rules. (bforte)
- Fix CCS display of image in term.
- Add product URL. Modify header to use product url.
- Fix formalpara missing div. BZ #473843
- Fix OL missing margin in article. BZ #473844
0.38 Thu Oct 16 2008
- Fix inline tags removing following new line in verbatim tags. BZ #461369
- Fix Numeration settings for HTML ordered lists. BZ #462601
- Fix PDF Example background color. BZ #463127
- Fix list item spacing. BZ #462673
- Fix translation report error on 2 charater langs, CSS, and layout. BZ #465201
- Added error for tgroup.cols not matching entry count. BZ #462205
- Fix TOC padding for appendix and glossary. BZ #462991
- Made comments in highlighted code more prominent. BZ #462552
- Added citerefentry, refentrytitle, and manvolnum to list of QA'd tags. BZ #464038
- Fixed '1' in ulink with no text. BZ #465411
- Change env path to be more portable. Patch by Artem Zolochevskiy . BZ #466194
- Added package meta to XHTML to allow content to be tracked to an RPM.
- Added catch for missing title and productname.
- Changed Formal Para Title to follow parent indent. BZ #466309
- Fix xmlClean not handling entity names with underscores or numbers. BZ #466994
- Fix clean_ids removing comments. BZ #467145
- Fix missing revhistory giving useless error. BZ #467147
- Stopped proecssing xml files in extras directory.
- Added conditional tagging to user Guide. By Don Domingo.
0.37 Wed Sep 3 2008
- Fix Bug in web rpm upgrade script.
- Fix Article not building rpms.
- Switch ja-JP font name in pdf from SazanamiMincho to SazanamiGothic
- Remove empty para tags to break en-US HTML build so writers stop breaking translations.
- Changed docs reference from --revision to --edition for create_book option
- Fixed Article layout not matching Book Layout. BZ #460969
- Fixed Part not ledded properly in TOC BZ #460976
- Fix duplicate IDs in XHTML output.
- Made background of remark a pretty yellow. BZ #459213
- Fix Accessibility typo. BZ #460856
- Fix spurious hyphenation in verbatim.
- Fix broken RPM packages when titles have been translated.
- Fix display bug in html-single. BZ #461375
- Added FAQ entry for Java weirdness. BZ #460738
- Add default encoding to XML files. BZ #461379
- Removed corpauthor from template. BZ #461222
- Fixed create_book help text. BZ #460736
- Added menuchoice tag. BZ #459671
- Removed unused scripts entity2pot and po2entity
0.35 Mon Sep 1 2008
- Add missing xerces-j2 Requires. BZ #457497
- Fixed css path for tranlation reports.
- Fixed font path for Fedora, ensured build fails if font metric creation fails. BZ #458003
- Set vertical-align:top for TD - BZ #457851
- Added WARNING for ENTITIES declared in XML files. BZ #456170
- Added check to ensure PRODUCT has a valid format.
- Only check xml files for revision history. BZ #458740
- Made VERSION and RELEASE over-rideable. BZ #458421
- Fixed display of OL nested in UL. BZ #457915
- Added "make pom" to output a basic maven pom file.
- Updated doco. BZ #458764
- Updated Conventions.xml. BZ #456026 #459216
- Made PDF and HTML display product version in similar style. BZ #456486
- Remove ID's from common files. BZ #460770
- Allowed footnote to keep ID. BZ #460790
- Fixed bogus verbatim layout. BZ #460771
0.34 Fri Apr 11 2008
- Fix PO file name missing from translation status report
- Modify xmlClean to output dummy content for empty files (beta)
- Default SHOW_UNKNOWN tags off
- Make unset entity warnings more obvious
- Make docs use DESKTOP styles
- Fix missing list image in html-single articles
- Commented out debug output in chunking xsl
- QANDA set html and css fix BZ #442674
- Fix kde requires. BZ #443024
- Add default FOP xconf file.
- Added help_internals target.
- Added check for banned tags.
- Added --lang to create_book BZ #444851
- Added package tag BZ #444908
- Added ability to ship $lang/files directories with html/xml payloads BZ #444935
- Hardcoded PDF footnote colour to black BZ #446011
- Set segmentedlist.as.table to 1. BZ #445628
- Force monospace on command
- Switched to FOP 0.95Beta
- Fixed crash bug on files names with parentheses BZ #447659
- Fix loose directory name matching when exluding directiories.
- Added GENERATE_SECTION_TOC_LEVEL to allow section level TOC control. BZ #449720
- Banned inlinegraphic. BZ #448331
- Added Article and Set Templates
- Banned xreflabel and endterm. BZ #452051
- Generate FOP config file and font-metricfiles as build. BZ #451913
- Changed HTML and PDF common brand to more pleasing colors. BZ #442675
- Fixed incorrect PDF colours on Fedora and Common brands. BZ #442988
- Fixed PDF TOC missing Chapter numbers on Sections. BZ #452802
- Fixed spaces being removed between inline tags. BZ #453067
- Changed TOC layout (bold chapters + spacing). BZ #453885
- Changed title spacing, unbolded figure/table titles.
- Fix over size images breaking PDF and HTML layouts
- Add missing make Requires. BZ #454376
- Added call to aspell to spell check.
- Fixed incorrect other credit title in PDF. BZ #454394
- Turned on Hyphenation to split verbatim lines.
- Added code highlighting to CSS and PDF
- Remove trailing '.' from formal para title. BZ #455826
- Restructure CSS for easier maintenance of brands
- Add documentation on publican design philosophy. BZ #456170
- Italicised package tag. BZ #442668
- Updated documentation descriptions of Book_Info.xml tags. BZ #456489 BZ #456488
0.33 Mon Apr 7 2008
- Remove release from package name in html desktop spec file
- Removed --nonet from xsltproc call BZ #436342
- Add Desktop css customisations
0.32 Thu Apr 3 2008
- Bump version
0.31 Tue Mar 18 2008
- Fixed Project-Id-Version not being set on PO creation BZ #435401
- Fixed java slowing down every make run BZ #435407
- cleanIds now sets format for imagedata
- Fixed Desktop RPM build errors
- Added param DOC_URL BZ #437705
- Changed Default DOC_URL to publican web site
- Fixed perl-SGML-Translate file conflict
- Removed --nonet from xsltproc call BZ #436342
- Removed extra files logic from spec and xsl files.
0.30 Thu Feb 24 2008
- Added missing Requires perl(XML::TreeBuilder)
- Fix xref to listitem breaking BZ #432574
- Die with a decent warning when an invalid Brand is chosen. BZ #429236
- Modified title page of PDF. BZ #429977
- Fix PDF list white space issue BZ #429237
- Fix PDF ulinks too big for tables BZ #430623
- Allowed rev history to be in any file BZ #297411
- Fix keycap hard to read in admon BZ #369161
- Added per Brand Makefile
- Add per Brand xsl files
- Added Requires elinks (used for formatted text output)
- Handle different FOP versions
- Fix PDF issue with nested images
- Added id_node to clean_ids to use none title nodes for id's BZ #434726
- Fix footnotes being duplicated in wrong chunks BZ #431388
- fixed bold text CSS bug for BZ #430617
0.29-2 Wed Feb 13 2008
- replace tab in changelog with spaces
0.29 Tue Feb 12 2008
- removed %%post and %%postun as update-desktop-database is
- for desktop files with mime types
- removed release for source path and tar name
- fixed package name in desktop file to include -doc
- switched from htmlview to xdg-open
- Added xdg-utils requires for doc package
0.29 Tue Feb 12 2008
- Setup per Brand Book_Templates
- Fix soure and URL paths
- Use release in source path
- correct GPL version text and changed file name to COPYING
- dropped Provides
- reordered spec file
- added fdl.txt to tar ball.
- added fdl.txt to doc package
0.28 Mon Feb 11 2008
- Added gpl.txt
- Fix GPL identifier as GPLv2+
- Fixed Build root
- Fix desktop file
- Added Provides for documentation-devel
- Fix dist build target
- Add dist-srpm target
- fix dist failing on missing pot dir
- Put docs in sub package
- Added GFDL to License to cover content and Book_Template directories.
- Included GFDL txt file
- set full path to source
0.27 Thu Feb 07 2008
- Use docbook-style-xsl: this will break formatting.
- Update custom xsl to use docbook-xsl-1.73.2: this will break formatting.
- Remove CATALOGS override
- Remove Red Hat specific clause from Makefile.common
- Fixed invalid xhtml BZ 428931
- Update License to GPL2
- Add GPL2 Header to numerous files
0.26-5 Fri Feb 01 2008
- renamed from documentation-devil to publican
0.26-4 Thu Jan 17 2008
- Tidy up %%files, %%build, %%prep and remove comments from spec file.
- Added --atime-preserve to tar command
0.26-3 Mon Jan 07 2008
- Rename from documentation-devel to documentation-devil
0.26-2 Mon Jan 07 2008
- tidy spec file
0.26 Wed Jan 02 2008
- Added CHUNK_SECTION_DEPTH param to allow chunk.section.depth override. BZ #427172
- Fixed EXTRA_DIRS to ignore .svn dirs, Added svn_add_po target. BZ #427178
- Fixed "uninitialized value" error when product not set. BZ #426038
- Fixed Brand not updating. BZ #426043
- Replaced FORMAL-RHI with HOLDER in Book_Template. BZ #426041
- Remove reference to non-existant svg file. BZ #426063
- Override formal.title.properties for PDF. BZ #425894
- Override formal.object.heading for HTML. Fix H5 & H6 css. BZ #425894
- Prepended first 4 characters of tag to IDs to aid Translation. BZ #427312
0.25 Tue Dec 11 2007
- Add html.longdesc.embed xsl param to allow long descriptions of images to be embedded in html output
- Remove Boilerplate files as ther are dupes of Legal_Notice
- Added BRAND Makefile param to allow branding books.
- renamed redhat.xsl to defaults.xsl
- Fixed product not being updated in Makefile when using create_book BZ #391491
- Removed embedded font from English PDFs as it Breaks searching
- Added user documentation
- create_book: fixed version and revision not working
- Added dist target to create tar & spec files for desktop rpms
- Made desktop rpms use html-single BZ #351731
- Removed gnome-doc-utils dep
- Removed docbook-style-xsl dep
- Removed perl-SGML-Translate dep
- Removed unused Config::Simple module
- Switch from Template to HTML::Template as it's already in Fedora
- Switched xlf2pot from XML::SimpleObject to XML::TreeBuilder
- Added error messages for invalid VERSION or RELEASE
- Changed Default PRODUCT to Documentation
- Added warning for default PRODUCT
- Differentiated brands
- rename rhlogo.png title_logo.png
- removed unused images
- cleaned build process
0.24 Tue Nov 6 2007
- Fix bug with calling translation report script.
0.23 Mon Nov 5 2007
- Add postuff to validate po files
- Add test-po- targets to use po-validateXML from postuff
- Fixed error msgs in poxmerge
- Fix bug with directory creation for deeply nested po files
- Fixed bug where Common files could not access .ent file BZ #322721
- Add entity for root using
- Added create_book command and files to allow local creation of new books
- Added SHOW_REMARKS make param to control display of remark tags
- Added OASIS dtd in xml for Kate users
- Sort image list for bin/rmImages to aid readability
- Modified padding and margins between figures and their titles
- Added DejaVuLGCSansMono font metrics
- Added DejaVuLGCSans Oblique metrics
- Added missing dejavu-lgc-fonts dep
- Added build message when copying Product Specific common files
- Move local entity to first position so it overrides common entity files
- Added missing DocBook tags to xmlClean:
- accel blockquote classname code colophon envar example footnote
- guisubmenu interface keycap keycombo literal literallayout option
- parameter prompt property see seealso substeps systemitem wordasword
- glossary glossdiv glosssee glossseealso
- Moved executables in to bin directory.
- Fixed layout of formal para titles in PDF
- Removed trunctaion and elipses from title used for page headers
0.22 Wed Oct 3 2007
- Add handling of extras directory
- Fix Russian PDF font problem
0.21 Tue Sep 25 2007
- Modified screen and programlisting to force closing tag to be on it's own.
- Added cmdsynopsis, arg, articleinfo, article, informaltable, group to xmlClean.
- Added CHUNK_FIRST to allow per book control of first section chunking.
- Defaults to 1, first sections will be on their own page.
- Fix warning message on po files with no entries
- added role as class to orderedlist, itemizedlist, ulink, article
- Fixed po files in sub directories not being merged correctly
- Add website specific css
0.20 Tue Aug 28 2007
- Added IGNORED_TRANSLATIONS to allow users to replace the chosen languages with
- the default langauge text when building
- fix bug where build would fail if $(XML_LANG)/images did not exist
- Fix bug with rpm downgrade
- fixed CSS bug for preformatted text when rendered inside inside an example.
0.19 Tue Aug 28 2007
- Add missing targets to help output
- Add missing variables to help_params output
- Improve help and help_params text
- Changed entity RHCRTSVER to 8.0 from 7.3
- Add DejaVuLGCSans back as Liberation is broken and Russian requires DejaVuLGCSans
- Modify Makefile to pull PO files from translation CVS
- Ensure Legal_Notice.po[t] is never used
- Add a warning message for GUI_String update-pot
- Fix Bug in GUI String publish targets
- Converted reports from hard coded HTML to Templates
- Publish GUI_String translation reports to same location as documentation reports.
0.18 Thu Aug 16 2007
- Use ghelp to enable localised menus (BZ #249829)
- Fix broken if in subpackage.xsl
- Fix Icon missing from menu
0.17 Mon Aug 13 2007
- Remove unused PUB_DIR make variable
- Remove 'redhat-' from FOP common paths
- Improve help text.
- Add error message for trying to build language without po files
- Added error message for trying to report on a language with no PO files
- Added error message for trying to build reports without POT files
0.16 Fri Jun 29 2007
- Added img.src.path to admon.graphics.path
- Moved header.navigation and footer.navigation from xhtml-common to main-html
- Removed 'redhat' from name
- Remove NOCHUNK param, Added html-single targets
- Added eclipse support
- removed xmlto Requires
- added Legal_Notice.xml for future books. Boilerplate.xml remains for back compatibility.
- Fix rpm link creation
- Added creation of format specific rpms
- Added rmImages script to remove unused images from build directory
- Removed per Product content directories
- default version to 0
0.15 Wed Jun 27 2007
- remove id from list-labels in questions & answers (duplicate id bug)
- Fixed bogus publish path for Reports
0.14 Wed Jun 27 2007
- Added test-all target
- Disabled Hyphenation in FOP, zh PDFs hanging service
* Tue Jun 26 2007 Joshua Wulf 0.13
- Added JBEAP and JBEAPVER entities
- Optimised spec file creation
0.12 Mon Jun 25 2007
- Fix css rule that broke links
0.11 Tue May 08 2007
- add DocBook 4.5 DTD to package
- add DocBook 1.72.0 xsl to package
- modify makefiles to use new DocBook catalogs
- xmlClean:
- Changed DTD from 4.3 to 4.5
- Added bookname to node id's to help avoid id clashes in sets
- Fixed line wrap issue in PDF generation for zh-CN and zh-TW
- Enforced validation of xml on all build targets
- Add legalnotice tag
- Add address tag
- Add street tag
- Add city tag
- Add state tag
- Add postcode tag
- Add country tag
- Add phone tag
- Add fax tag
- Add pob tag
- Add preface tag
- Add bibliograpy related tags
- Add qandaset related tags
- Removed Confidential image and restyle confidential html text
- Added po2xlf script
- Added xlf2po script
- Added perl-XML-SimpleObject to Requires, used in xliff code
- Fixed Makefile.GUI updating po file for source lang
- Updated custom xml to match 1.72 docbook xsl
- Removed MuktiNarrow fonts - using lohit-bn
- Removed ZYSong18030 & ARPLSungtiLGB fonts - unused
- Modified Publish output line in logfile to be a URL
- Fixed creation of translated srpm
- Added Liberation fonts for PDF
- Removed DejaVuLGCSans fonts
- Turned on Line Wrap for monospace verbatim elements
- Moved entity SELinux from Translatable to Entities.ent, updated po files
- Added Legal_Notice to common
- Moved balance of non-translatable entities out of Translatable-entities.ent, updated po files
- Added missing Req perl-SGML-Translate, used for translation reports
- Updated documentation descriptions of Book_Info.xml tags. BZ #456489 BZ #456488
0.10 Tue May 01 2007
- fix image dimensions on content/common/en-US/images/redhat-logo.svg
- remove leading space from rpm spec desription
- Made abstract wrap at 72 characters and be left aligned.
- it's used for the spec description
- Move legal notice link param from xhtml.xsl to main-html so nochunks
- target will have legal notice embedded in page
0.9.1 Tue Apr 24 2007
- fix path to xsl
0.9 Tue Apr 24 2007
- Fix "Use of uninitialized value in string eq at xmlClean line 272."
- Add facility to prune xml tree based on condition attribute.
- Made COMMON_CONTENT static
0.8 Tue Apr 17 2007
- fix non RHEL books not having the PRODUCT name attached to the
- rpm and specfile to avoid duplicate name problems.
- e.g. everyone has a Deployment_Guide so non RHEL books must be Fortitude-Deployment_Guide etc.
0.7 Tue Apr 17 2007
- format temporary fo file as the lines where to long and confused FOP ... grrr
- fixed po files not having links updated when clean_ids is run
0.6 Tue Apr 17 2007
- fix Book entity file being ignored
- add white space to TOC
0.5 Tue Apr 17 2007
- Revert to kdesdk (xml2pot) to fix RHEL4 bug where entities would be dropped from pot file.
- Switching to gnome-docs-util creates ~1500 hours of translation work in the
- Deployment Guide alone making the switch impossible at this time :(
- This means inline xml comments will break translation due to a bug in the sdk.
- Added the 4 scripts from doc-tools to bin/* to avoid adding deps.
- Added missing PRODUCT en-US & pot dirs
0.4 Mon Apr 16 2007
- Fix fop config file
- Roll back font metrics file to fop 0.2 format
0.3 Mon Apr 16 2007
- Fix xmlClean, clean_ids was note validating xref ids correctly
0.2 Thu Apr 12 2007
- Fix SYSTEM not being copied to PRODUCT properly
- Fix GUI Strings reports
- Fix GUI Strings css path
- Fix Set targets as per timp@redhat.com fix.
0.1.19 Wed Apr 11 2007
- Change SYSTEM to PRODUCT as it more clearly defines what it's used for.
- Add content to README
- Fix 'make help' output for Books
0.1.18 Tue Apr 10 2007
- Fix missing Entity file
- Remove graphic from boilerplate
- Fix fop metric path to meet new package path
- PDF Appendix, URL and title fixes
0.1.15 Mon Apr 02 2007
- add 'a' to start of ID's that begin with numbers.
- stop DTD entity strings being written in clean_id mode
- fix pdf formatting issues
- Merge Common_Config
- add missing Requirements
- add DejaVuLGCSans for Russian books
0.1.13 Tue Mar 27 2007
- add appendix and appendix info to xmlClean
- convert all configuration files from fop 0.20.5 to 0.93.0 format.
- remove copying of common configuration directory
0.1.12 Mon Mar 26 2007
- bump rev for brew build
0.1.11 Fri Mar 23 2007
- fixed use of dist
0.1.10 Thu Mar 22 2007
- Switch to using gnome-doc-utils for po manipulation
0.1.9 Wed Mar 21 2007
- Remove trailing space from text nodes in xmlClean
- add feed back for user
0.1.8 Tue Mar 20 2007
- Fix re-creation of $cmd variable
- Add support for per arch build
0.1.6 Mon Mar 19 2007
- Fix path for reports script
0.0 Wed Feb 07 2007
- Initial creation
win_catalog.xml 000444 041472 041472 675 12555605450 17100 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2
META.yml 000444 041472 041472 14245 12555605450 15376 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 ---
abstract: 'Used to control settings for sub modules.'
author:
- 'Jeff Fearn '
build_requires:
Archive::Tar: '1.84'
Archive::Zip: '0'
Carp: '0'
Config::Simple: '0'
Cwd: '0'
DBI: '0'
DateTime: '0'
DateTime::Format::DateParse: '0'
Encode: '0'
File::Basename: '0'
File::Copy::Recursive: '0.38'
File::Find: '0'
File::Find::Rule: '0'
File::HomeDir: '0'
File::Inplace: '0'
File::Path: '0'
File::Slurp: '0'
File::Spec: '0'
File::Which: '0'
File::pushd: '0'
Getopt::Long: '0'
HTML::FormatText: '0'
HTML::FormatText::WithLinks: '0'
HTML::FormatText::WithLinks::AndTables: '0.02'
HTML::TreeBuilder: '0'
HTML::WikiConverter::Markdown: '0.06'
I18N::LangTags::List: '0'
IO::String: '0'
Lingua::EN::Fathom: '0'
List::MoreUtils: '0'
List::Util: '0'
Locale::Language: '0'
Locale::Maketext::Gettext: '0'
Locale::Maketext::Lexicon: '0'
Locale::Msgfmt: '0'
Locale::PO: '0.24'
Module::Build: '0'
Pod::Usage: '0'
Sort::Versions: '0'
String::Similarity: '0'
Syntax::Highlight::Engine::Kate: '0.09'
Template: '0'
Template::Constants: '0'
Term::ANSIColor: '0'
Test::More: '0'
Text::CSV_XS: '0'
Text::Wrap: '0'
Time::localtime: '0'
XML::LibXML: '1.7'
XML::LibXSLT: '1.7'
XML::Simple: '0'
XML::TreeBuilder: '5.4'
version: '0.77'
configure_requires:
Module::Build: '0'
dynamic_config: 1
generated_by: 'Module::Build version 0.4206, CPAN::Meta::Converter version 2.142060'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: Publican
provides:
Publican:
file: lib/Publican.pm
version: v4.3.2
Publican::Builder:
file: lib/Publican/Builder.pm
Publican::Builder::DocBook:
file: lib/Publican/Builder/DocBook.pm
Publican::Builder::DocBook4:
file: lib/Publican/Builder/DocBook4.pm
Publican::Builder::DocBook5:
file: lib/Publican/Builder/DocBook5.pm
Publican::CreateBook:
file: lib/Publican/CreateBook.pm
Publican::CreateBrand:
file: lib/Publican/CreateBrand.pm
Publican::Localise:
file: lib/Publican/Localise.pm
Publican::Localise::C:
file: lib/Publican/Localise.pm
Publican::Localise::as:
file: lib/Publican/Localise.pm
Publican::Localise::bg:
file: lib/Publican/Localise.pm
Publican::Localise::bn_in:
file: lib/Publican/Localise.pm
Publican::Localise::bs:
file: lib/Publican/Localise.pm
Publican::Localise::ca:
file: lib/Publican/Localise.pm
Publican::Localise::cs:
file: lib/Publican/Localise.pm
Publican::Localise::da:
file: lib/Publican/Localise.pm
Publican::Localise::de:
file: lib/Publican/Localise.pm
Publican::Localise::el:
file: lib/Publican/Localise.pm
Publican::Localise::en:
file: lib/Publican/Localise.pm
Publican::Localise::es:
file: lib/Publican/Localise.pm
Publican::Localise::fi:
file: lib/Publican/Localise.pm
Publican::Localise::fr:
file: lib/Publican/Localise.pm
Publican::Localise::gu:
file: lib/Publican/Localise.pm
Publican::Localise::he:
file: lib/Publican/Localise.pm
Publican::Localise::hi:
file: lib/Publican/Localise.pm
Publican::Localise::hr:
file: lib/Publican/Localise.pm
Publican::Localise::hu:
file: lib/Publican/Localise.pm
Publican::Localise::id:
file: lib/Publican/Localise.pm
Publican::Localise::it:
file: lib/Publican/Localise.pm
Publican::Localise::ja:
file: lib/Publican/Localise.pm
Publican::Localise::kn:
file: lib/Publican/Localise.pm
Publican::Localise::ko:
file: lib/Publican/Localise.pm
Publican::Localise::lv:
file: lib/Publican/Localise.pm
Publican::Localise::ml:
file: lib/Publican/Localise.pm
Publican::Localise::mr:
file: lib/Publican/Localise.pm
Publican::Localise::ms:
file: lib/Publican/Localise.pm
Publican::Localise::nb:
file: lib/Publican/Localise.pm
Publican::Localise::nl:
file: lib/Publican/Localise.pm
Publican::Localise::or:
file: lib/Publican/Localise.pm
Publican::Localise::pa:
file: lib/Publican/Localise.pm
Publican::Localise::pl:
file: lib/Publican/Localise.pm
Publican::Localise::pt:
file: lib/Publican/Localise.pm
Publican::Localise::pt_br:
file: lib/Publican/Localise.pm
Publican::Localise::ru:
file: lib/Publican/Localise.pm
Publican::Localise::sk:
file: lib/Publican/Localise.pm
Publican::Localise::sr:
file: lib/Publican/Localise.pm
Publican::Localise::sr_latn:
file: lib/Publican/Localise.pm
Publican::Localise::sv:
file: lib/Publican/Localise.pm
Publican::Localise::ta:
file: lib/Publican/Localise.pm
Publican::Localise::te:
file: lib/Publican/Localise.pm
Publican::Localise::uk:
file: lib/Publican/Localise.pm
Publican::Localise::zh_cn:
file: lib/Publican/Localise.pm
Publican::Localise::zh_tw:
file: lib/Publican/Localise.pm
Publican::Translate:
file: lib/Publican/Translate.pm
Publican::TreeView:
file: lib/Publican/TreeView.pm
Publican::WebSite:
file: lib/Publican/WebSite.pm
Publican::XmlClean:
file: lib/Publican/XmlClean.pm
requires:
Archive::Tar: '1.84'
Archive::Zip: '0'
Carp: '0'
Config::Simple: '0'
Cwd: '0'
DBI: '0'
DateTime: '0'
DateTime::Format::DateParse: '0'
Encode: '0'
File::Basename: '0'
File::Copy::Recursive: '0.38'
File::Find: '0'
File::Find::Rule: '0'
File::HomeDir: '0'
File::Inplace: '0'
File::Path: '0'
File::Slurp: '0'
File::Spec: '0'
File::Which: '0'
File::pushd: '0'
Getopt::Long: '0'
HTML::FormatText: '0'
HTML::FormatText::WithLinks: '0'
HTML::FormatText::WithLinks::AndTables: '0.02'
HTML::TreeBuilder: '0'
HTML::WikiConverter::Markdown: '0.06'
I18N::LangTags::List: '0'
IO::String: '0'
Lingua::EN::Fathom: '0'
List::Util: '0'
Locale::Language: '0'
Locale::Maketext::Gettext: '0'
Locale::Msgfmt: '0'
Locale::PO: '0.24'
Pod::Usage: '0'
Sort::Versions: '0'
String::Similarity: '0'
Syntax::Highlight::Engine::Kate: '0.09'
Template: '0'
Template::Constants: '0'
Term::ANSIColor: '0'
Text::CSV_XS: '0'
Text::Wrap: '0'
Time::localtime: '0'
XML::LibXML: '1.67'
XML::LibXSLT: '1.67'
XML::Simple: '0'
XML::TreeBuilder: '5.4'
version: '0.77'
resources:
license: http://dev.perl.org/licenses/
version: v4.3.2
COPYING 000444 041472 041472 43611 12555605450 15157 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 =============================================================================
Full text of the GNU General Public Licence version 2 retrieved from:
http://www.gnu.org/licenses/gpl-2.0.html
Refer to LICENSE for a breakdown of Publican licensing
=============================================================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
META.json 000444 041472 041472 22705 12555605450 15546 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 {
"abstract" : "Used to control settings for sub modules.",
"author" : [
"Jeff Fearn "
],
"dynamic_config" : 1,
"generated_by" : "Module::Build version 0.4206",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : "2"
},
"name" : "Publican",
"prereqs" : {
"build" : {
"requires" : {
"Archive::Tar" : "1.84",
"Archive::Zip" : "0",
"Carp" : "0",
"Config::Simple" : "0",
"Cwd" : "0",
"DBI" : "0",
"DateTime" : "0",
"DateTime::Format::DateParse" : "0",
"Encode" : "0",
"File::Basename" : "0",
"File::Copy::Recursive" : "0.38",
"File::Find" : "0",
"File::Find::Rule" : "0",
"File::HomeDir" : "0",
"File::Inplace" : "0",
"File::Path" : "0",
"File::Slurp" : "0",
"File::Spec" : "0",
"File::Which" : "0",
"File::pushd" : "0",
"Getopt::Long" : "0",
"HTML::FormatText" : "0",
"HTML::FormatText::WithLinks" : "0",
"HTML::FormatText::WithLinks::AndTables" : "0.02",
"HTML::TreeBuilder" : "0",
"HTML::WikiConverter::Markdown" : "0.06",
"I18N::LangTags::List" : "0",
"IO::String" : "0",
"Lingua::EN::Fathom" : "0",
"List::MoreUtils" : "0",
"List::Util" : "0",
"Locale::Language" : "0",
"Locale::Maketext::Gettext" : "0",
"Locale::Maketext::Lexicon" : "0",
"Locale::Msgfmt" : "0",
"Locale::PO" : "0.24",
"Module::Build" : "0",
"Pod::Usage" : "0",
"Sort::Versions" : "0",
"String::Similarity" : "0",
"Syntax::Highlight::Engine::Kate" : "0.09",
"Template" : "0",
"Template::Constants" : "0",
"Term::ANSIColor" : "0",
"Test::More" : "0",
"Text::CSV_XS" : "0",
"Text::Wrap" : "0",
"Time::localtime" : "0",
"XML::LibXML" : "1.7",
"XML::LibXSLT" : "1.7",
"XML::Simple" : "0",
"XML::TreeBuilder" : "5.4",
"version" : "0.77"
}
},
"configure" : {
"requires" : {
"Module::Build" : "0"
}
},
"runtime" : {
"requires" : {
"Archive::Tar" : "1.84",
"Archive::Zip" : "0",
"Carp" : "0",
"Config::Simple" : "0",
"Cwd" : "0",
"DBI" : "0",
"DateTime" : "0",
"DateTime::Format::DateParse" : "0",
"Encode" : "0",
"File::Basename" : "0",
"File::Copy::Recursive" : "0.38",
"File::Find" : "0",
"File::Find::Rule" : "0",
"File::HomeDir" : "0",
"File::Inplace" : "0",
"File::Path" : "0",
"File::Slurp" : "0",
"File::Spec" : "0",
"File::Which" : "0",
"File::pushd" : "0",
"Getopt::Long" : "0",
"HTML::FormatText" : "0",
"HTML::FormatText::WithLinks" : "0",
"HTML::FormatText::WithLinks::AndTables" : "0.02",
"HTML::TreeBuilder" : "0",
"HTML::WikiConverter::Markdown" : "0.06",
"I18N::LangTags::List" : "0",
"IO::String" : "0",
"Lingua::EN::Fathom" : "0",
"List::Util" : "0",
"Locale::Language" : "0",
"Locale::Maketext::Gettext" : "0",
"Locale::Msgfmt" : "0",
"Locale::PO" : "0.24",
"Pod::Usage" : "0",
"Sort::Versions" : "0",
"String::Similarity" : "0",
"Syntax::Highlight::Engine::Kate" : "0.09",
"Template" : "0",
"Template::Constants" : "0",
"Term::ANSIColor" : "0",
"Text::CSV_XS" : "0",
"Text::Wrap" : "0",
"Time::localtime" : "0",
"XML::LibXML" : "1.67",
"XML::LibXSLT" : "1.67",
"XML::Simple" : "0",
"XML::TreeBuilder" : "5.4",
"version" : "0.77"
}
}
},
"provides" : {
"Publican" : {
"file" : "lib/Publican.pm",
"version" : "v4.3.2"
},
"Publican::Builder" : {
"file" : "lib/Publican/Builder.pm"
},
"Publican::Builder::DocBook" : {
"file" : "lib/Publican/Builder/DocBook.pm"
},
"Publican::Builder::DocBook4" : {
"file" : "lib/Publican/Builder/DocBook4.pm"
},
"Publican::Builder::DocBook5" : {
"file" : "lib/Publican/Builder/DocBook5.pm"
},
"Publican::CreateBook" : {
"file" : "lib/Publican/CreateBook.pm"
},
"Publican::CreateBrand" : {
"file" : "lib/Publican/CreateBrand.pm"
},
"Publican::Localise" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::C" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::as" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::bg" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::bn_in" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::bs" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ca" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::cs" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::da" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::de" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::el" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::en" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::es" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::fi" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::fr" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::gu" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::he" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::hi" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::hr" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::hu" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::id" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::it" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ja" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::kn" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ko" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::lv" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ml" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::mr" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ms" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::nb" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::nl" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::or" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::pa" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::pl" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::pt" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::pt_br" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ru" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::sk" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::sr" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::sr_latn" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::sv" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::ta" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::te" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::uk" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::zh_cn" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Localise::zh_tw" : {
"file" : "lib/Publican/Localise.pm"
},
"Publican::Translate" : {
"file" : "lib/Publican/Translate.pm"
},
"Publican::TreeView" : {
"file" : "lib/Publican/TreeView.pm"
},
"Publican::WebSite" : {
"file" : "lib/Publican/WebSite.pm"
},
"Publican::XmlClean" : {
"file" : "lib/Publican/XmlClean.pm"
}
},
"release_status" : "stable",
"resources" : {
"license" : [
"http://dev.perl.org/licenses/"
]
},
"version" : "v4.3.2"
}
Build.PL 000444 041472 041472 63703 12555605450 15424 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 use strict;
use warnings;
use Module::Build;
use 5.008;
use Cwd qw(abs_path cwd);
my $cwd = cwd();
my $class = Module::Build->subclass(
class => 'My::Builder',
code => q{
# older versions of Module::Build need this duplicated.
use Cwd qw(abs_path cwd);
my $cwd = cwd();
my $dir = $cwd . '/tmp/rpm';
my $common_langs = 'all';
sub ACTION_srpm {
my $self = shift;
my $os_ver = $self->args('os_ver');
$self->depends_on('clean');
$self->depends_on('dist');
$self->do_system("mkdir -p $dir");
$self->do_system("cp Publican*.tar.gz $dir/.");
if($os_ver) {
$self->do_system( 'rpmbuild', "--define", "_sourcedir $dir", "--define",
"_builddir $dir", "--define", "_srcrpmdir $dir", "--define",
"_rpmdir $dir", "-bs", "--nodeps", "--define",
"dist $os_ver", "publican.spec");
}
else {
$self->do_system( 'rpmbuild', "--define", "_sourcedir $dir", "--define",
"_builddir $dir", "--define", "_srcrpmdir $dir", "--define",
"_rpmdir $dir", "-bs", "--nodeps", "publican.spec");
}
}
sub ACTION_rpm {
my $self = shift;
$self->ACTION_srpm || die;
my $os_ver = $self->args('os_ver');
require File::Find::Rule;
my $rule = File::Find::Rule->new;
$rule->file->name("*.src.rpm");
my @rpm_files = $rule->in($dir);
if($os_ver) {
$self->do_system( 'rpmbuild', "--define", "_sourcedir $dir", "--define",
"_builddir $dir", "--define", "_srcrpmdir $dir", "--define",
"_rpmdir $dir", "--rebuild", "--define",
"dist $os_ver", $rpm_files[0]
);
}
else {
$self->do_system( 'rpmbuild', "--define", "_sourcedir $dir", "--define",
"_builddir $dir", "--define", "_srcrpmdir $dir", "--define",
"_rpmdir $dir", "--rebuild", $rpm_files[0]
);
}
}
sub ACTION_local {
my $self = shift;
$self->ACTION_rpm || die;
require File::Find::Rule;
my $rule = File::Find::Rule->new;
$rule->file->name("*.rpm");
$rule->file->not_name("*.src.rpm");
my @rpm_files = $rule->in($dir);
my @cmd = qw(yum -y localinstall --nogpg);
unshift(@cmd, 'sudo') if($<);
$self->do_system(@cmd, @rpm_files);
}
sub process_brand_template_files {
my $self = shift;
require File::Find::Rule;
require File::Copy::Recursive;
my $path = "$cwd/blib/datadir/Common_Content/brand-template";
mkpath("$path");
File::Copy::Recursive::rcopy( "datadir/Common_Content/brand-template/*", "$path/.");
}
sub ACTION_common_files {
my $self = shift;
use lib File::Spec->catdir('blib/lib');
use File::Path;
eval {
require Publican;
$Publican::SINGLETON = undef;
require Publican::Builder::DocBook;
require Publican::Builder::DocBook4;
require File::pushd;
};
if($@){
warn($@);
} else {
my $dir = File::pushd::pushd("$cwd/datadir/Common_Content/common");
my $path = "$cwd/blib/datadir/Common_Content";
my $publican = Publican->new({NOCOLOURS => $self->args('nocolours'), common_config => "$cwd/datadir"});
my $builder = Publican::Builder::DocBook4->new();
$builder->build(
{ formats => 'xml', langs => $common_langs, publish => 1, pub_dir => 'publish' } );
mkpath("$path");
Publican::rcopy( "publish/*", "$path/.");
Publican::rcopy('publican.cfg', "$path/common/.");
$dir = undef;
$builder = undef;
$publican = undef;
}
}
sub ACTION_commondb5_files {
my $self = shift;
use lib File::Spec->catdir('blib/lib');
use File::Path;
eval {
require Publican;
$Publican::SINGLETON = undef;
require Publican::Builder::DocBook;
require Publican::Builder::DocBook5;
require File::pushd;
};
if($@){
warn("$@, $!");
} else {
my $dir = File::pushd::pushd('datadir/Common_Content/common-db5');
my $path = "$cwd/blib/datadir/Common_Content";
my $publican = Publican->new({ NOCOLOURS => $self->args('nocolours'), common_config => "$cwd/datadir"});
my $builder = Publican::Builder::DocBook5->new();
$builder->build(
{ formats => 'xml', langs => $common_langs, publish => 1, pub_dir => 'publish' } );
Publican::rcopy( "publish/*", "$path/.");
Publican::rcopy('publican.cfg', "$path/common-db5/.");
$dir = undef;
$builder = undef;
$publican = undef;
}
}
sub ACTION_locale_files {
my $self = shift;
use File::Path;
require File::Find::Rule;
require Locale::Msgfmt;
my @po_files = File::Find::Rule::find(
maxdepth => 1,
file => name => "*.po",
in => 'po',
relative => 0,
);
foreach my $po_file (@po_files) {
$po_file =~ m/po\/(.*)\.po/;
my $lang=$1;
my $dir = qq|$cwd/blib/locale/$lang/LC_MESSAGES|;
mkpath($dir) unless(-d $dir);
Locale::Msgfmt::msgfmt({in => $po_file, out=> "$dir/publican.mo"});
}
# my $dir = qq|$cwd/blib/locale/en_US/LC_MESSAGES|;
# mkpath($dir) unless(-d $dir);
# Locale::Msgfmt::msgfmt({in => "po/publican.pot", out=> qq|$cwd/blib/locale/en_US/LC_MESSAGES/publican.mo|});
}
sub ACTION_update_pot {
my $self = shift;
# BUGBUG TODO call Locale::Maketext::Extract::Run directly
# use Locale::Maketext::Extract::Run 'xgettext';
# my @args = qw(-d publican -D lib -D bin -P Locale::Maketext::Extract::Plugin::PPI=* -o po/publican.pot);
# xgettext(@ARGV);
$self->do_system('xgettext.pl -d publican -D lib -D bin -P Locale::Maketext::Extract::Plugin::PPI=* --wrap -o po/publican.pot');
}
sub ACTION_update_po {
my $self = shift;
require File::Find::Rule;
my @po_files = File::Find::Rule::find(
maxdepth => 1,
file => name => "*.po",
in => 'po',
relative => 0,
);
# BUGBUG TODO switch to internal merge code
foreach my $po_file (@po_files) {
$self->do_system("msgmerge --quiet --no-wrap --backup=none --update $po_file po/publican.pot");
}
}
sub ACTION_authortest {
my ($self) = @_;
$self->test_files( qw< xt/author > );
$self->recursive_test_files(1);
$self->depends_on('test');
return;
}
sub ACTION_install {
my ($self) = @_;
# Set ConfigData to point to the installed paths
$self->config_data('etc', $self->install_path('etc'));
$self->config_data('datadir', $self->install_path('datadir'));
$self->config_data('web', $self->install_path('web'));
$self->config_data('templates', $self->install_path('templates'));
$self->config_data('book_templates', $self->install_path('book_templates'));
$self->config_data('rpm_templates', $self->install_path('rpm_templates'));
$self->config_data('docdir', $self->install_path('docdir'));
$self->SUPER::ACTION_config_data();
return $self->SUPER::ACTION_install();
}
sub ACTION_test {
my ($self) = @_;
# $self->depends_on('build');
## Setup ConfigData so it points to the local content
$self->config_data( 'etc', $cwd . '/blib/etc' );
$self->config_data( 'datadir', $cwd . '/blib/datadir' );
$self->config_data( 'web', $cwd . '/blib/web' );
$self->config_data( 'templates', $cwd . '/blib/templates' );
$self->config_data( 'book_templates', $cwd . '/blib/book_templates' );
$self->config_data( 'rpm_templates', $cwd . '/blib/rpm_templates' );
$self->config_data( 'docdir', $cwd . '/pod1' );
$self->SUPER::ACTION_test();
# Set ConfigData to point to the installed paths
$self->config_data('etc', $self->install_path('etc'));
$self->config_data('datadir', $self->install_path('datadir'));
$self->config_data('web', $self->install_path('web'));
$self->config_data('templates', $self->install_path('templates'));
$self->config_data('book_templates', $self->install_path('book_templates'));
$self->config_data('rpm_templates', $self->install_path('rpm_templates'));
$self->config_data('docdir', $self->install_path('docdir'));
return;
}
sub ACTION_distdir {
my ($self) = @_;
$self->depends_on('authortest');
return $self->SUPER::ACTION_distdir();
}
sub ACTION_build {
my ($self) = @_;
$self->SUPER::ACTION_build();
$self->depends_on('common_files');
$self->depends_on('commondb5_files');
$self->depends_on('locale_files');
}
sub ACTION_update_pod {
my ($self) = @_;
use List::MoreUtils qw|uniq|;
my $POD_FILE;
open($POD_FILE, '>', 'pod1/publican') || die("can't open POD file");
print($POD_FILE <<'EOL');
=head1 NAME
publican - a DocBook XML publishing tool.
=head1 VERSION
This document describes publican version 4.0
=head1 SYNOPSIS
publican
publican
Command Options
--help Display help message
--man Display the man page
--help_actions Display a list of valid actions
-v Display the version of Publican
EOL
my $pod = qx|perl -CDAS -I blib/lib bin/publican --help_actions|;
print($POD_FILE $pod);
print($POD_FILE <<'EOL');
=head1 INTERFACE
EOL
$pod = qx|perl -CDAS -I blib/lib bin/publican --help all|;
my $version = $self->dist_version;
print($POD_FILE $pod, "\n");
print($POD_FILE <<'EOL');
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires access to wkhtmltopdf or Apache FOP for creating PDF files.
=head1 DEPENDENCIES
EOL
my $deps = $self->build_requires();
my $reqs = $self->requires();
foreach my $dep (sort(uniq(keys(%{$deps}), keys(%{$reqs})))) {
print($POD_FILE "$dep\n");
}
print($POD_FILE <<'EOL');
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
Bug list at L.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
=cut
EOL
close($POD_FILE);
$self->do_system('perl -CDAS -I blib/lib bin/publican --bash');
return;
}
}
);
my $builder = $class->new(
module_name => 'Publican',
dist_name => 'Publican',
license => 'perl',
dist_author => 'Jeff Fearn ',
dist_version_from => 'lib/Publican.pm',
configure_requires => { 'Module::Build' => 0 },
build_requires => {
'Module::Build' => 0,
'Test::More' => 0,
'Archive::Tar' => 1.84,
'Archive::Zip' => 0,
'Locale::Maketext::Gettext' => 0,
'Carp' => 0,
'Config::Simple' => 0,
'Cwd' => 0,
'DateTime' => 0,
'DateTime::Format::DateParse' => 0,
'DBI' => 0,
'Encode' => 0,
'File::Basename' => 0,
'File::Copy::Recursive' => 0.38,
'File::Find' => 0,
'File::Find::Rule' => 0,
'File::HomeDir' => 0,
'File::Inplace' => 0,
'File::Path' => 0,
'File::pushd' => 0,
'File::Slurp' => 0,
'File::Spec' => 0,
'File::Which' => 0,
'Getopt::Long' => 0,
'HTML::FormatText' => 0,
'HTML::FormatText::WithLinks' => 0,
'HTML::FormatText::WithLinks::AndTables' => 0.02,
'HTML::TreeBuilder' => 0,
'HTML::WikiConverter::Markdown' => 0.06,
'I18N::LangTags::List' => 0,
'IO::String' => 0,
'List::Util' => 0,
'List::MoreUtils' => 0,
'Locale::Language' => 0,
'Locale::PO' => 0.24,
'Pod::Usage' => 0,
'Sort::Versions' => 0,
'String::Similarity' => 0,
'Syntax::Highlight::Engine::Kate' => 0.09,
'Template' => 0,
'Template::Constants' => 0,
'Term::ANSIColor' => 0,
'Text::Wrap' => 0,
'Time::localtime' => 0,
'XML::LibXML' => 1.70,
'XML::LibXSLT' => 1.70,
'XML::Simple' => 0,
'XML::TreeBuilder' => 5.4,
'Text::CSV_XS' => 0,
'Locale::Maketext::Lexicon' => 0,
version => 0.77,
'Locale::Msgfmt' => 0,
'Lingua::EN::Fathom' => 0,
},
requires => {
'Archive::Tar' => 1.84,
'Archive::Zip' => 0,
'Locale::Maketext::Gettext' => 0,
'Carp' => 0,
'Config::Simple' => 0,
'Cwd' => 0,
'DateTime' => 0,
'DateTime::Format::DateParse' => 0,
'DBI' => 0,
'Encode' => 0,
'File::Basename' => 0,
'File::Copy::Recursive' => 0.38,
'File::Find' => 0,
'File::Find::Rule' => 0,
'File::HomeDir' => 0,
'File::Inplace' => 0,
'File::Path' => 0,
'File::pushd' => 0,
'File::Slurp' => 0,
'File::Spec' => 0,
'File::Which' => 0,
'Getopt::Long' => 0,
'HTML::FormatText' => 0,
'HTML::FormatText::WithLinks' => 0,
'HTML::FormatText::WithLinks::AndTables' => 0.02,
'HTML::TreeBuilder' => 0,
'HTML::WikiConverter::Markdown' => 0.06,
'I18N::LangTags::List' => 0,
'IO::String' => 0,
'List::Util' => 0,
'Locale::Language' => 0,
'Locale::PO' => 0.24,
'Pod::Usage' => 0,
'Sort::Versions' => 0,
'String::Similarity' => 0,
'Syntax::Highlight::Engine::Kate' => 0.09,
'Template' => 0,
'Template::Constants' => 0,
'Term::ANSIColor' => 0,
'Text::Wrap' => 0,
'Time::localtime' => 0,
'XML::LibXML' => 1.67,
'XML::LibXSLT' => 1.67,
'XML::Simple' => 0,
'XML::TreeBuilder' => 5.4,
'Text::CSV_XS' => 0,
version => 0.77,
'Locale::Msgfmt' => 0,
'Lingua::EN::Fathom' => 0,
},
add_to_cleanup => [
'Publican-*',
'tmp',
'blib',
'foo*',
'Test_*',
'Users_Guide/build',
'Users_Guide/publish',
'Users_Guide/tmp',
'Users_Guide/de-DE',
'datadir/Common_Content/common/tmp',
'datadir/Common_Content/common/publish',
'MANIFEST.bak',
'Site_Tech/tmp',
'Site_Tech/publish',
'META.yml',
'Splash_Page/tmp/tmp',
'Splash_Page/tmp/publish',
'datadir/Common_Content/common-db5/tmp',
'datadir/Common_Content/common-db5/publish',
'META.json',
'publican-Test_Brand',
'Release_Notes/tmp',
],
script_files => [ 'bin/publican', 'bin/db5-valid', 'bin/db4-2-db5' ],
bindoc_dirs => ['pod1'],
install_path => {
'datadir' => '/usr/share/publican',
'web' => '/usr/share/publican/sitetemplate',
'templates' => '/usr/share/publican/templates',
'book_templates' => '/usr/share/publican/book_templates',
'rpm_templates' => '/usr/share/publican/rpm_templates',
'etc' => '/etc',
'completion' => '/etc/bash_completion.d',
'docdir' => '/usr/share/doc/',
'locale' => '/usr/share/locale',
},
data_files => {
'datadir/rpmlint.cfg' => 'datadir/rpmlint.cfg',
'datadir/default.db' => 'datadir/default.db',
'datadir/fop/fop.xconf' => 'datadir/fop/fop.xconf',
'datadir/xsl/carousel.xsl' => 'datadir/xsl/carousel.xsl',
'datadir/xsl/xhtml-common.xsl' => 'datadir/xsl/xhtml-common.xsl',
'datadir/xsl/html-pdf.xsl' => 'datadir/xsl/html-pdf.xsl',
'datadir/xsl/html.xsl' => 'datadir/xsl/html.xsl',
'datadir/xsl/txt.xsl' => 'datadir/xsl/txt.xsl',
'datadir/xsl/defaults.xsl' => 'datadir/xsl/defaults.xsl',
'datadir/xsl/html-single-plain.xsl' => 'datadir/xsl/html-single-plain.xsl',
'datadir/xsl/html-single.xsl' => 'datadir/xsl/html-single.xsl',
'datadir/xsl/pdf.xsl' => 'datadir/xsl/pdf.xsl',
'datadir/xsl/epub.xsl' => 'datadir/xsl/epub.xsl',
'datadir/xsl/eclipse.xsl' => 'datadir/xsl/eclipse.xsl',
'datadir/xsl/man.xsl' => 'datadir/xsl/man.xsl',
'datadir/xsl/merge_revisions.xsl' =>
'datadir/xsl/merge_revisions.xsl',
'datadir/xsl/db4-upgrade.xsl' => 'datadir/xsl/db4-upgrade.xsl',
'datadir/xsl/drupal-book.xsl' => 'datadir/xsl/drupal-book.xsl',
},
web_files => {
'web/index.html' => 'web/index.html',
'web/default.js' => 'web/default.js',
'web/images/arrows.png' => 'web/images/arrows.png',
'web/images/close.png' => 'web/images/close.png',
'web/images/open.png' => 'web/images/open.png',
'web/images/page.png' => 'web/images/page.png',
'web/jquery-1.7.1.min.js' => 'web/jquery-1.7.1.min.js',
'web/jquery.jcarousel.min.js' => 'web/jquery.jcarousel.min.js',
'web/chrome.css' => 'web/chrome.css',
'web/db4.css' => 'web/db4.css',
'web/db5.css' => 'web/db5.css',
'web/print.css' => 'web/print.css',
'web/splash.css' => 'web/splash.css',
'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.ttf' => 'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.ttf',
'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.woff' => 'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.woff',
'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.svg' => 'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.svg',
'web/Font-Awesome-4.2.0/fonts/FontAwesome.otf' => 'web/Font-Awesome-4.2.0/fonts/FontAwesome.otf',
'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.eot' => 'web/Font-Awesome-4.2.0/fonts/fontawesome-webfont.eot',
'web/Font-Awesome-4.2.0/css/font-awesome.min.css' => 'web/Font-Awesome-4.2.0/css/font-awesome.min.css',
},
templates_files => {
'templates/anchor.tmpl' => 'templates/anchor.tmpl',
'templates/books_index.tmpl' => 'templates/books_index.tmpl',
'templates/books_format_menu.tmpl' =>
'templates/books_format_menu.tmpl',
'templates/books_lang_menu.tmpl' => 'templates/books_lang_menu.tmpl',
'templates/books_menu.tmpl' => 'templates/books_menu.tmpl',
'templates/index.tmpl' => 'templates/index.tmpl',
'templates/labels.tmpl' => 'templates/labels.tmpl',
'templates/language_index.tmpl' => 'templates/language_index.tmpl',
'templates/language_index_style_1.tmpl' =>
'templates/language_index_style_1.tmpl',
'templates/opds.tmpl' => 'templates/opds.tmpl',
'templates/opds-langs.tmpl' => 'templates/opds-langs.tmpl',
'templates/opds-prods.tmpl' => 'templates/opds-prods.tmpl',
'templates/products_index.tmpl' => 'templates/products_index.tmpl',
'templates/products_menu.tmpl' => 'templates/products_menu.tmpl',
'templates/toc.tmpl' => 'templates/toc.tmpl',
'templates/versions_index.tmpl' => 'templates/versions_index.tmpl',
'templates/versions_menu.tmpl' => 'templates/versions_menu.tmpl',
'templates/web_2_footer.tmpl' => 'templates/web_2_footer.tmpl',
'templates/web_2_head.tmpl' => 'templates/web_2_head.tmpl',
'templates/Sitemap.tmpl' => 'templates/Sitemap.tmpl',
},
book_templates_files => {
'book_templates/cover.tmpl' => 'book_templates/cover.tmpl',
'book_templates/footer.tmpl' => 'book_templates/footer.tmpl',
'book_templates/header.tmpl' => 'book_templates/header.tmpl',
'book_templates/pdf-css.tmpl' => 'book_templates/pdf-css.tmpl',
'book_templates/pdfmain-css.tmpl' =>
'book_templates/pdfmain-css.tmpl',
'book_templates/toc-xsl.tmpl' => 'book_templates/toc-xsl.tmpl',
'book_templates/titlepage.tmpl' => 'book_templates/titlepage.tmpl',
},
rpm_templates_files => {
'rpm_templates/desktop-spec.tmpl' =>
'rpm_templates/desktop-spec.tmpl',
'rpm_templates/spec.tmpl' => 'rpm_templates/spec.tmpl',
'rpm_templates/splash.tmpl' => 'rpm_templates/splash.tmpl',
},
etc_files =>
{ 'etc/publican-website.cfg' => 'etc/publican-website.cfg', },
completion_files => { 'completion/_publican' => 'completion/_publican', },
);
if ( $^O eq 'darwin' ) {
$builder->install_path( 'datadir' => '/opt/local/share/publican' );
$builder->install_path(
'generated' => '/opt/local/share/publican/sitetemplate' );
$builder->install_path(
'web' => '/opt/local/share/publican/sitetemplate' );
$builder->install_path(
'templates' => '/opt/local/share/publican/templates' );
$builder->install_path(
'book_templates' => '/opt/local/share/publican/book_templates' );
$builder->install_path(
'rpm_templates' => '/opt/local/share/publican/rpm_templates' );
$builder->install_path( 'etc' => '/opt/local/etc' );
$builder->install_path(
'completion' => '/opt/local/etc/bash_completion.d' );
$builder->install_path( 'locale' => '/opt/local/share/locale' );
}
$builder->add_build_element('brand_template');
$builder->add_build_element('data');
$builder->add_build_element('web');
$builder->add_build_element('templates');
$builder->add_build_element('book_templates');
$builder->add_build_element('rpm_templates');
$builder->add_build_element('etc');
$builder->add_build_element('completion');
$builder->add_build_element('locale');
## Setup ConfigData so it points to the local content
$builder->config_data( 'etc', $cwd . '/blib/etc' );
$builder->config_data( 'datadir', $cwd . '/blib/datadir' );
$builder->config_data( 'web', $cwd . '/blib/web' );
$builder->config_data( 'templates', $cwd . '/blib/templates' );
$builder->config_data( 'book_templates', $cwd . '/blib/book_templates' );
$builder->config_data( 'rpm_templates', $cwd . '/blib/rpm_templates' );
$builder->config_data( 'docdir', $cwd . '/pod1' );
$builder->create_build_script();
perltidyrc 000444 041472 041472 1166 12555605450 16207 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 -l=78 # Max line width is 78 cols
-i=4 # Indent level is 4 cols
-ci=4 # Continuation indent is 4 cols
-st # Output to STDOUT
-se # Errors to STDERR
-vt=2 # Maximal vertical tightness
-cti=0 # No extra indentation for closing brackets
-pt=1 # Medium parenthesis tightness
-bt=1 # Medium brace tightness
-sbt=1 # Medium square bracket tightness
-bbt=1 # Medium block brace tightness
-nsfs # No space before semicolons
-nolq # Don't outdent long quoted strings
-wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x="
# Break before all operators
README 000444 041472 041472 15114 12555605450 15001 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 README for Publican
Publican is a DocBook publication system, not just a DocBook processing tool.
As well as ensuring your DocBook XML is valid, publican works to ensure
your XML is up to publishable standard.
Web: http://publican.fedorahosted.org/
Mail: https://www.redhat.com/mailman/listinfo/publican-list
Source: http://svn.fedorahosted.org/svn/publican
Bugs: https://bugzilla.redhat.com/bugzilla/enter_bug.cgi?product=Publican
Assumptions: DocBook xml, *nix, en-US source language.
Q: What actions are there?
A: publican --help
Q: How do I update the POT files for translation?
A: publican update_pot
Q: How do I add a language?
A: publican update_po --langs=
This will create the language directory and the language specific po files.
Q: How do I update all po files?
A: publican update_po --langs=all
Q: What Book specific options can I use?
A: publican --help_config
Q: Where are the common files located?
A: By default they are in /usr/share/publican
Publican now uses Build::ConfigData to contorl this. If the default paths are not correct modify the Build time options, via the command line or in Build.PL to set them. Checkout how the options in Build.PL are modified for 'darwin' and do the same for your OS. If you submit a bug with your OS details we will include it.
Q: How do I profile publican?
A: Devel::NYTProf is a good option.
$ perl -CDAS -d:NYTProf /usr/bin/publican build --langs en-US --formats html
$ nytprofhtml
$ firefox nytprof/index.html
Q: How do I control where publican looks for files when it's installed?
A: You can override the default paths by specifiying them on the commmand line or in the Build.PL file.
e.g.
perl Build.PL --install_path datadir=/opt/foo/publican --install_path web=/opt/bar/sitetemplate
Q: How do I build publican from source?
A: It depends on your platform.
Get the source: git clone git://git.fedorahosted.org/git/publican.git
CPAN
cd publican/publican
$ perl Build.PL
if this complains about missing deps run
$ ./Build installdeps
$ ./Build
$ ./Build test
$ sudo ./Build install
RHEL/Fedora
cd publican/publican
$ perl Build.PL
if this complains about missing deps, on Fedora 10+, and RHEL 6+, run
$ sudo yum-builddep publican.spec
$ ./Build
$ ./Build rpm
Docker
For production version see Users Guide.
For testing devel branch on fedora based image:
$ mkdir $HOME/books
$ sudo chcon -R -t svirt_sandbox_file_t $HOME/books
$ docker build --rm - < Dockerfile.devel
$ docker run -i -t -v $HOME/books:$HOME/books publican /bin/bash
Debian
The publican package deb files are in the debian package repo
http://packages.debian.org/search?keywords=publican
$ cd publican/publican
$ sudo apt-get install \
libfile-pushd-perl \
libconfig-simple-perl \
libxml-treebuilder-perl \
libfile-find-rule-perl \
libmakefile-parser-perl \
liblocale-maketext-gettext-perl \
perlmagick \
libimage-size-perl \
libdatetime-perl \
liblocale-po-perl \
libxml-libxslt-perl \
libdatetime-format-dateparse-perl \
libsyntax-highlight-engine-kate-perl \
libtest-perl-critic-perl \
libtest-pod-coverage-perl \
libtest-exception-perl \
libdbd-sqlite-perl \
libdevel-cover-perl \
libdbd-sqlite3-perl
$ perl Build.PL
$ ./Build
$ ./Build dist
TODO: put the tgz where?
$ debuild
Windows:
Make a dir to work in, Publican assumes:
mkdir c:\publican
cd c:\publican
Install a decent editor
http://www.vim.org/download.php#pc
Install gitbash
http://msysgit.googlecode.com/
Set-Up ssh in gitbash shell
copy keys to ~/.ssh
ssh-agent /bin/bash.exe
ssh-add ~/.ssh/id_rsa
clone source repo
git clone ssh://git.fedorahosted.org/git/publican.git
Fetch DocBook files
mkdir c:\publican\DTD
http://www.docbook.org/xml/4.5/docbook-xml-4.5.zip
mkdir C:/publican/docbook-xsl-1.76.1
http://downloads.sourceforge.net/project/docbook/docbook-xsl/1.76.1/docbook-xsl-1.76.1.zip
Install Perl http://strawberryperl.com/
cpan tool
install Module::Build Config::Simple Perl::Critic XML::TreeBuilder Locale::Maketext::Gettext
http://search.cpan.org/CPAN/authors/id/C/CH/CHIPT/File-Inplace-0.20.tar.gz
https://rt.cpan.org/Public/Bug/Display.html?id=63940
https://rt.cpan.org/Ticket/Attachment/869125/450100/win32.diff
blah blah
install Locale::PO String::Similarity DateTime::Format::DateParse Syntax::Highlight::Engine::Kate HTML::FormatText
install HTML::FormatText::WithLinks::AndTables Test::Pod PAR::Packer
Install NSIS
http://nsis.sourceforge.net/Download
http://nsis.sourceforge.net/Environmental_Variables:_append,_prepend,_and_remove_entries
C:\Program Files\NSIS\Include
http://nsis.sourceforge.net/NsUnzip_plugin
C:\Program Files\NSIS\Plugins
$ cd publican
$ set XML_CATALOG_FILES=c:\publican\publican\publican\win_catalog.xml
$ perl win_build.pl
Q: How do I push new strings to Zanata or retrieve new translations?
A: You need to install Maven (on Fedora, yum install maven). Then, to update the translation source on Zanata from the newest version of the POT file, change into the po directory and run:
$ mvn zanata:push
and to retrieve new translations:
$ mvn zanata:pull
TODO:
what about a real list of valid langauges?
wget http://www.iana.org/assignments/language-subtag-registry
grep -A 1 -B 0 -P '^Type: (language|redundant)' language-subtag-registry | grep -P '^(Subtag|Tag)' | perl -p -e 's/^(Subtag|Tag):\s*//gi' | wc -l
sub valid_lang looks good
http://cpansearch.perl.org/src/TOBYINK/XRD-Parser-0.101/lib/XRD/Parser.pm
Release Process:
0: make sure User Guide and Release Notes are up to date.
1: Get updated sources
git checkout devel
./Build realclean
git pull
2: Update versions
gvim lib/Publican.pm
Set $VERSION
gvim Changes
Set release date
gvim publican.spec
Set Version:
Reset Release: to 0, remove any .t*
Copy Changes entry to %changelog
3: Test code
perl Build.PL
./Build manifest
./Build
./Build test
./Build realclean
4: Commit version changes and merge code to master
git commit -a -m "Release version 4.3.2"
git push
git checkout master
git pull
git merge devel
git push
git tag -a Release-4.3.2 -m "Release Version 4.3.2"
git push origin --tags
perl Build.PL
./Build
./Build srpm
5: Upload to public site
scp Publican-v4.3.2.tar.gz publican.spec tmp/rpm/publican*.src.rpm fedorahosted.org:publican
6: Bug Rudi to do release announcement
Poke him!
Updating pulicans translations on zanata
cd po
zanata-cli pull -s . -t . --include-fuzzy
cd ..
./Build update_pot
./Build update_po
cd po
zanata-cli push -s . -t . --push-type both --copy-trans 0
publican-releasenotes.desktop 000444 041472 041472 317 12555605450 21737 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 [Desktop Entry]
Name=Publican - Release Notes
Comment=Release Notes for publican.
Exec=xdg-open @@FILE@@
Icon=@@ICON@@
Categories=Documentation;X-Red-Hat-Base;
Type=Application
Encoding=UTF-8
Terminal=false
publican.spec 000444 041472 041472 67502 12555605450 16602 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2
# Track font name changes
%define RHEL6 %([[ %{?dist}x == .el6[a-z]* ]] && echo 1 || echo 0)
%define RHEL7 %([[ %{?dist}x == .el7[a-z]* ]] && echo 1 || echo 0)
# BUGBUG BZ #1144220 work around wrong entity string bug
%define DBPATH %(find /usr/share/sgml/docbook/xml-dtd-4.5*/dbcentx.mod)
%define OTHER 1
%if %{RHEL6}
%define OTHER 0
%endif
%if %{RHEL7}
%define OTHER 0
%endif
# required for desktop file install
%define my_vendor %(test %{OTHER} == 1 && echo "fedora" || echo "redhat")
%define TESTS 1
%define wwwdir /var/www/html/docs
Name: publican
Version: 4.3.2
Release: 0%{?dist}
Summary: Common files and scripts for publishing with DocBook XML
# For a breakdown of the licensing, refer to LICENSE
License: (GPLv2+ or Artistic) and CC0
Group: Applications/Publishing
URL: https://publican.fedorahosted.org
Source0: https://fedorahosted.org/released/publican/Publican-v%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildArch: noarch
Provides: publican-common = %{version}
Provides: publican-common-db5 = %{version}
Provides: publican-API = 4.1
# Get rid of the old packages
Obsoletes: perl-Publican-WebSite
Obsoletes: publican-WebSite-obsoletes
Conflicts: perl-Publican-WebSite
Conflicts: publican-WebSite-obsoletes
## work around arch -> noarch bug in yum
Obsoletes: publican < 3
BuildRequires: perl(Devel::Cover)
BuildRequires: perl(Module::Build)
BuildRequires: perl(Test::More)
BuildRequires: perl(Test::Pod) => 1.14
BuildRequires: perl(Test::Pod::Coverage) => 1.04
BuildRequires: perl(Archive::Tar) => 1.84
BuildRequires: perl(Archive::Zip)
# Not reall required, but sometimes koji pulls in a conflicting dep...
BuildRequires: perl(Compress::Zlib) => 2.030
BuildRequires: perl-Locale-Maketext-Gettext >= 1.27-1.2
BuildRequires: perl(Carp)
BuildRequires: perl(Config::Simple)
BuildRequires: perl(Cwd)
BuildRequires: perl(DateTime)
BuildRequires: perl(DateTime::Format::DateParse)
BuildRequires: perl(DBI)
BuildRequires: perl(Encode)
BuildRequires: perl(File::Basename)
BuildRequires: perl(File::Copy::Recursive) => 0.38
BuildRequires: perl(File::Find)
BuildRequires: perl(File::Find::Rule)
BuildRequires: perl(File::HomeDir)
BuildRequires: perl(File::Inplace)
BuildRequires: perl(File::Path)
BuildRequires: perl(File::pushd)
BuildRequires: perl(File::Spec)
BuildRequires: perl(File::Slurp)
BuildRequires: perl(File::Which)
BuildRequires: perl(Getopt::Long)
BuildRequires: perl(HTML::FormatText)
BuildRequires: perl(HTML::FormatText::WithLinks)
BuildRequires: perl(HTML::FormatText::WithLinks::AndTables) >= 0.02
BuildRequires: perl(HTML::TreeBuilder)
BuildRequires: perl(HTML::WikiConverter::Markdown) >= 0.06
BuildRequires: perl(I18N::LangTags::List)
BuildRequires: perl(IO::String)
BuildRequires: perl(List::MoreUtils)
BuildRequires: perl(List::Util)
BuildRequires: perl(Locale::Language)
BuildRequires: perl(Locale::PO) >= 0.24
BuildRequires: perl(Module::Build)
BuildRequires: perl(Pod::Usage)
BuildRequires: perl(String::Similarity)
BuildRequires: perl(Syntax::Highlight::Engine::Kate) >= 0.09
BuildRequires: perl(Template)
BuildRequires: perl(Template::Constants)
BuildRequires: perl(Term::ANSIColor)
BuildRequires: perl(Text::Wrap)
BuildRequires: perl(Time::localtime)
BuildRequires: perl(XML::LibXML) => 1.70
BuildRequires: perl(XML::LibXSLT) => 1.70
BuildRequires: perl(XML::Simple)
BuildRequires: perl(XML::TreeBuilder) => 5.4
# BZ #1053609
BuildRequires: perl-XML-TreeBuilder >= 5.4
BuildRequires: docbook-style-xsl >= 1.77.1
BuildRequires: desktop-file-utils
BuildRequires: gettext
BuildRequires: perl(Text::CSV_XS)
BuildRequires: perl(Sort::Versions)
BuildRequires: perl(DBD::SQLite)
BuildRequires: docbook5-schemas
BuildRequires: docbook5-style-xsl >= 1.78.1
BuildRequires: perl(version) >= 0.77
BuildRequires: perl(Locale::Msgfmt)
BuildRequires: perl(Locale::Maketext::Lexicon)
BuildRequires: perl(Lingua::EN::Fathom)
BuildRequires: rpm-build libicu-devel
# Most of these are handled automatically
Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
Requires: perl-Locale-Maketext-Gettext >= 1.27-1.2
Requires: rpm-build
Requires: docbook-style-xsl >= 1.77.1
Requires: perl(XML::LibXML) >= 1.70
Requires: perl(XML::LibXSLT) >= 1.70
Requires: perl(XML::TreeBuilder) >= 5.4
Requires: perl(HTML::WikiConverter::Markdown) >= 0.06
# BZ #1053609
Requires: perl-XML-TreeBuilder >= 5.4
Requires: perl-Template-Toolkit
Requires: perl(DBD::SQLite)
Requires: perl(Text::CSV_XS)
Requires: docbook5-schemas
Requires: docbook5-style-xsl >= 1.78.1
# Not really required, but sometimes koji pulls in a conflicting dep...
Requires: perl(Compress::Zlib) => 2.030
# Lets validate some basics
Requires: rpmlint
# Pull in the fonts for all languages, else you can't build translated PDF in brew/koji
%if %{RHEL6}
Requires: liberation-mono-fonts liberation-sans-fonts liberation-serif-fonts
Requires: cjkuni-uming-fonts ipa-gothic-fonts ipa-pgothic-fonts
Requires: lklug-fonts baekmuk-ttf-batang-fonts
Requires: lohit-assamese-fonts lohit-bengali-fonts lohit-devanagari-fonts
Requires: lohit-gujarati-fonts lohit-hindi-fonts lohit-kannada-fonts
Requires: lohit-kashmiri-fonts lohit-konkani-fonts lohit-maithili-fonts
Requires: lohit-malayalam-fonts lohit-marathi-fonts lohit-nepali-fonts
Requires: lohit-oriya-fonts lohit-punjabi-fonts lohit-sindhi-fonts
Requires: lohit-tamil-fonts lohit-telugu-fonts dejavu-lgc-sans-mono-fonts
Requires: dejavu-fonts-common dejavu-serif-fonts dejavu-sans-fonts
Requires: dejavu-sans-mono-fonts overpass-fonts
Requires: wqy-zenhei-fonts
Requires: wkhtmltopdf >= 0.12.1.devlopment
BuildRequires: wkhtmltopdf >= 0.12.1.development
BuildRequires: liberation-mono-fonts liberation-sans-fonts liberation-serif-fonts
BuildRequires: cjkuni-uming-fonts ipa-gothic-fonts ipa-pgothic-fonts
BuildRequires: lklug-fonts baekmuk-ttf-batang-fonts
BuildRequires: dejavu-fonts-common dejavu-serif-fonts dejavu-sans-fonts
BuildRequires: dejavu-sans-mono-fonts overpass-fonts dejavu-lgc-sans-mono-fonts
%endif
%if %{RHEL7}
Requires: liberation-mono-fonts liberation-sans-fonts liberation-serif-fonts
Requires: cjkuni-uming-fonts ipa-gothic-fonts ipa-pgothic-fonts
Requires: lklug-fonts baekmuk-ttf-batang-fonts overpass-fonts
Requires: wkhtmltopdf >= 0.12.1.devlopment
BuildRequires: wkhtmltopdf >= 0.12.1.development
BuildRequires: liberation-mono-fonts liberation-sans-fonts liberation-serif-fonts
BuildRequires: cjkuni-uming-fonts ipa-gothic-fonts ipa-pgothic-fonts
BuildRequires: lklug-fonts baekmuk-ttf-batang-fonts
%endif
%if %{OTHER}
Requires: liberation-mono-fonts liberation-sans-fonts liberation-serif-fonts
Requires: cjkuni-uming-fonts ipa-gothic-fonts ipa-pgothic-fonts
Requires: lklug-fonts baekmuk-ttf-batang-fonts overpass-fonts
Requires: fop
BuildRequires: fop
BuildRequires: liberation-mono-fonts liberation-sans-fonts liberation-serif-fonts
BuildRequires: cjkuni-uming-fonts ipa-gothic-fonts ipa-pgothic-fonts
BuildRequires: lklug-fonts baekmuk-ttf-batang-fonts
%endif
%description
Publican is a DocBook publication system, not just a DocBook processing tool.
As well as ensuring your DocBook XML is valid, publican works to ensure
your XML is up to publishable standard.
%package doc
Group: Documentation
Summary: Documentation for the Publican package
Requires: xdg-utils
Obsoletes: publican-doc < 3
%description doc
Publican is a tool for publishing material authored in DocBook XML.
This guide explains how to to create and build books and articles
using publican. It is not a DocBook XML tutorial and concentrates
solely on using the publican tools.
%package releasenotes
Group: Documentation
Summary: Release notes for the Publican package
Requires: xdg-utils
%description releasenotes
Release notes for Publican %{version}.
%package common-web
Group: Documentation
Summary: Website style for common brand
Requires: publican
%description common-web
Website style for common brand.
%package common-db5-web
Group: Documentation
Summary: Website style for common brand for DocBook5 content
Requires: publican
%description common-db5-web
Website style for common brand for DocBook5 content
%prep
%setup -q -n Publican-v%{version}
%build
sed -i -e 's,PATH,%{DBPATH},g' catalog
XML_CATALOG_FILES=$dir/catalog %{__perl} Build.PL installdirs=vendor --nocolours=1
XML_CATALOG_FILES=$dir/catalog ./Build --nocolours=1
dir=`pwd`
cd Users_Guide && XML_CATALOG_FILES=$dir/catalog %{__perl} -CDAS -I $dir/blib/lib $dir/blib/script/publican build \
--formats=html-desktop --publish --langs=en-US \
--common_config="$dir/blib/datadir" \
--common_content="$dir/blib/datadir/Common_Content" --nocolours
cd $dir
cd Release_Notes && XML_CATALOG_FILES=$dir/catalog %{__perl} -CDAS -I $dir/blib/lib $dir/blib/script/publican build \
--formats=html-desktop --publish --langs=en-US \
--common_config="$dir/blib/datadir" \
--common_content="$dir/blib/datadir/Common_Content" --nocolours
%install
rm -rf $RPM_BUILD_ROOT
dir=`pwd`
XML_CATALOG_FILES=$dir/catalog ./Build install destdir=$RPM_BUILD_ROOT create_packlist=0
find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \;
%{_fixperms} $RPM_BUILD_ROOT/*
sed -i -e 's|@@FILE@@|%{_docdir}/%{name}-doc%{!?_docdir_fmt:-%{version}}/en-US/index.html|' %{name}.desktop
sed -i -e 's|@@ICON@@|%{_docdir}/%{name}-doc%{!?_docdir_fmt:-%{version}}/en-US/images/icon.svg|' %{name}.desktop
sed -i -e 's|@@FILE@@|%{_docdir}/%{name}-releasenotes%{!?_docdir_fmt:-%{version}}/en-US/index.html|' %{name}-releasenotes.desktop
sed -i -e 's|@@ICON@@|%{_docdir}/%{name}-releasenotes%{!?_docdir_fmt:-%{version}}/en-US/images/icon.svg|' %{name}-releasenotes.desktop
desktop-file-install --vendor="%{my_vendor}" --dir=$RPM_BUILD_ROOT%{_datadir}/applications %{name}.desktop
desktop-file-install --vendor="%{my_vendor}" --dir=$RPM_BUILD_ROOT%{_datadir}/applications %{name}-releasenotes.desktop
%find_lang %{name} --with-man
# Package web common files
mkdir -p -m755 $RPM_BUILD_ROOT/%{wwwdir}/common
dir=`pwd`
cd datadir/Common_Content/common
XML_CATALOG_FILES=$dir/catalog %{__perl} -CDAS -I $dir/blib/lib $dir/blib/script/publican install_brand --web --path=$RPM_BUILD_ROOT/%{wwwdir}/common
cd -
mkdir -p -m755 $RPM_BUILD_ROOT/%{wwwdir}/common-db5
cd datadir/Common_Content/common-db5
XML_CATALOG_FILES=$dir/catalog %{__perl} -CDAS -I $dir/blib/lib $dir/blib/script/publican install_brand --web --path=$RPM_BUILD_ROOT/%{wwwdir}/common-db5
cd -
%check
%if %{TESTS}
dir=`pwd`
XML_CATALOG_FILES=$dir/catalog ./Build --nocolours=1 test
%endif
%post
# hack to allow branch directory BZ #800252
CATALOG=%{_sysconfdir}/xml/catalog
%{_bindir}/xmlcatalog --noout --add "rewriteURI" \
"https://fedorahosted.org/released/publican/xsl/docbook4/" \
"file://%{_datadir}/publican/xsl/" $CATALOG
CATALOG=%{_sysconfdir}/xml/catalog
%{_bindir}/xmlcatalog --noout --add "public" \
"-//OASIS//ENTITIES DocBook Character Entities V4.5//EN" \
"file://%{DBPATH}" $CATALOG
%postun
if [ "$1" = 0 ]; then
CATALOG=%{_sysconfdir}/xml/catalog
%{_bindir}/xmlcatalog --noout --del \
"https://fedorahosted.org/released/publican/xsl/docbook4/" $CATALOG
CATALOG=%{_sysconfdir}/xml/catalog
%{_bindir}/xmlcatalog --noout --del \
"-//OASIS//ENTITIES DocBook Character Entities V4.5//EN" $CATALOG
fi
%clean
rm -rf $RPM_BUILD_ROOT
%files -f %{name}.lang
%defattr(-,root,root,-)
%doc Changes README COPYING Artistic pod1/publican
%{perl_vendorlib}/Publican.pm
%{perl_vendorlib}/Publican
%{_mandir}/man3/Publican*
%{_mandir}/man1/*
%{_bindir}/publican
%{_bindir}/db5-valid
%{_bindir}/db4-2-db5
%{_datadir}/publican
%config(noreplace) %{_datadir}/publican/default.db
%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/publican-website.cfg
%config(noreplace) %{_sysconfdir}/bash_completion.d/_publican
%files doc
%defattr(-,root,root,-)
%doc Users_Guide/publish/desktop/*
%{_datadir}/applications/%{my_vendor}-%{name}.desktop
%doc fdl.txt
%files releasenotes
%defattr(-,root,root,-)
%doc Release_Notes/publish/desktop/*
%{_datadir}/applications/%{my_vendor}-%{name}-releasenotes.desktop
%doc fdl.txt
%files common-web
%defattr(-,root,root,-)
%{wwwdir}/common
%files common-db5-web
%defattr(-,root,root,-)
%{wwwdir}/common-db5
%changelog
* Tue Jul 28 2015 Lee Newson 4.3.2-0
- Do not replace non-breaking spaces by spaces in msgid of POT files. BZ #1233202
- Fixed Unwanted line breaks around images. BZ #1222067
- Fixed EPUB output of db5 brands can't be viewed. BZ #1241348
* Thu Jun 18 2015 Lee Newson 4.3.1-0
- Fixed a regression in 4.3.0 that caused TOC's not to be included in wkhtmltopdf PDF's. BZ #1230023
- Fixed callout image urls being broken. BZ #1222716
* Tue May 5 2015 Jeff Fearn 4.3.0-0
- Fix web site templates to be more flexable.
- Tweak default website styles.
- Remove all FOP customisations. BZ #1168765
- Use FontAwesome for aswesomeness.
- Switch DocBook-5 HTML to highlight.js.
- Change splash page group publish directory structure so it can be used directly. BZ #1186990
- Fix duplicate link in Website docs. BZ #1188384
- Fix PDF builds ignoring overrides.css and lang.css. BZ #1165005
- Pulled in new/updated translations. BZ #1169605
- Removed duplicate IDs from PUG. BZ #1197523
- Removed the titlepage.xsl import from html-single due to breaking the xsl precedence. BZ #1187728
- Fix Publican doesn't fallback to base_brand xsl files. BZ #1185127
- Fix elements being stripped in drupal-book builds. BZ #1158747
- Fix malformed HTML/Drupal XML Feed for DocBook 5 content. BZ #1158740
- Fix incorrect missing image warnings for drupal builds. BZ #1158725
- Fix articles not building when using the drupal-book format. BZ #1164640
- Fix initial title page content being skipped when a user defines a custom bookinfo id. BZ #1165482
- Fix invalid XML being generated for drupal-book, when titles contain reserved chars. BZ #1165438
- Changed the drupal feed field to use the url value instead of the title. BZ #1165724
- Fix publican.cfg values are used in the feed page tag. BZ #1172402
- Fix drupal content is dropped, if the element that is chunked has no id. BZ #1173421
- Adjusted the XML output so anchors to something in the same page doesn't include the page url.
- Make legalnotice chunk in a similar way as chapters for drupal builds, so it's included in the feed.
- Enable section.label.includes.component.label for common-db5. BZ #1205952
- Fix formalpara ids being dropped for DocBook 4.5. BZ #1209344
- Add --no_clean option to allow custom entity files. BZ #1208069
* Tue Oct 21 2014 Jeff Fearn 4.2.6-0
- Fix External_Links translation not merging. BZ #1153911
* Wed Oct 15 2014 Jeff Fearn 4.2.5-0
- Fix DocBook4 epub failing for ja-JP. BZ #1152780
* Tue Oct 14 2014 Jeff Fearn 4.2.4-0
- Allow External_Links.xml to be translated. BZ #1150386
- Change ja-JP person-name style. BZ #1150866
* Tue Oct 7 2014 Jeff Fearn 4.2.3-0
- Fix DocBook4 entity text, BZ #1143060
- Remove extra white space from non-verbatim msgid's. BZ #1143792
- Fix PDF build using FOP fails with "No numberLines function available." BZ #1143852
- Add allow_network option. Defaults OFF. BZ #1144949
- Add hacks to work around BZ #1144220
* Wed Sep 17 2014 Jeff Fearn 4.2.2-2
- Fix duplicate messages in POT files. BZ #1136133
- Remove top level directory from drupal tar file. BZ #1139070
- Fix PDF font selection. BZ #1139899
* Mon Sep 01 2014 Jeff Fearn 4.2.1-0
- Remove empty msgids from POT files. BZ #1135143
- Fix highlight in callout with areaspec. BZ #1135827
* Thu Aug 28 2014 Jeff Fearn 4.2.0-0
- Add iframe video support to DocBook5 HTML5. BZ #752021
- Stop calculating column width if no width is set. BZ #1084860
- Simply styling of code, and admonitions in HTML5. BZ #1093498
- Added tip formatting. BZ #1033830
- Remove incorrect prompt. BZ #1096544
- Add "popper" to hide program listing after 4 lines. BZ #1088051
- Fix white space being removed from msgids when merging. BZ #1097090
- Add code language switching. BZ #1092351
- Fix CDATA support, bump XML::TreeBuilder dep to 5.3. BZ #1101050
- Add --showfuzzy to build options.
- Move PO manipulation to Locale::PO.
- Fix inline"\n" not working in verbatim. BZ #1097091 (TODO bump Locale::PO version when released)
- Fix images for DB4 website callouts. BZ #1112899
- Remove newline after cdata. BZ #1110611
- Add Markdown output. BZ #1120455
- Bump Syntax::Highlight::Engine::Kate dep to 0.09.
- Add external link support. BZ #1123193
- Add 'th' to translation block list. BZ #1127462
* Mon Aug 04 2014 Jeff Fearn 4.1.7-0
- Another shot at fixing PDF index out of range error.
* Tue Jul 29 2014 Jeff Fearn 4.1.6-0
- Another shot at fixing PDF index out of range error.
* Wed Jul 09 2014 Jeff Fearn 4.1.5-0
- Add some web UI tranlstaion strings & sort formats. BZ #1117081
- Fix formal para title CSS. BZ #1110076
* Thu Jul 03 2014 Jeff Fearn 4.1.4-1
- Expose sort functions to version index page.
* Wed May 21 2014 Jeff Fearn 4.1.4-0
- Fix headers and footers triggering index out of range in PDF Build.
* Wed May 21 2014 Jeff Fearn 4.1.3-0
- Fix extra space breaking spec files with sort_order. BZ #1099262
- Make div.title bold in db4.css. BZ #1049661
* Wed May 14 2014 Jeff Fearn 4.1.2-0.1
- Fix Fedora and RHEL7 requires
* Wed May 14 2014 Jeff Fearn 4.1.2-0
- Fix broken DocBook5 validation stopping package builds. BZ #1097495
* Thu May 8 2014 Jeff Fearn 4.1.1-0
- Fix long tables and pre's breaking PDF build. BZ #1095574
* Mon May 5 2014 Jeff Fearn 4.1.0-0
- Add abstract to release notes so PDF builds
- Fix RPM upgrade not pulling in required XML::TreeBuilder version. BZ #1053609
- Allow PDF to build without any authors. BZ #1050975
- Increase XML::LibXSLT::max_depth to 10K. BZ #1035525
- Include entrytbl in cols count. BZ #1069405
- Add 'td' to translatable blocks list. BZ #1059938
- Treat entry like para for mixedmode tags. BZ #1039382
- Add blank page after cover page in PDF. BZ #1050770
- Fix replaceable override in DB 4.5 XSL. BZ #1054462
- Store processing instructions. BZ #1045463
- Add releaseinfo support. BZ #1050789
- Add suppor5t for wkhtmltopdf 0.12.0
- Add non-minified JS files. BZ #1062109
- Use term as ID node for varlistentry. BZ #1050836
- Fix acroread search and image issues. BZ #1038393 #1065810
- Add line numbering to DB5 html output. BZ #1074709
- Remove glossdiv and indexdiv headings from PDF TOC. BZ #1058545
- Add basic handling & style for revisionflag.
- Fix admonition style for wkhtmnltopdf 0.12.
- Pass chunk_section_depth to wkhtmltopdf. BZ #1044848
- Do not die on empty brand conf files. BZ #1037037
- Fix font embedding
- Enforce RPM API requirements. BZ #1029293
- Fix desktop SPEC file creation. BZ #1081087
- Pass previous option to msgmerge. BZ #1081363
- Load splash pages in templates instead of using javascript. BZ #1081300
- Sync list layout across web and desktop styles. BZ #1080236
- Add dt_format parameter. BZ #1081808
- Provide gettext version of package name. BZ #1083102
- Fix step style. BZ #1080156
- Fix DD layout. BZ #1084242
- Fix tables breaking out. BZ #1082444
- Add zt_push and zt_pull for Zanata.
* Wed Dec 18 2013 RУМdiger Landmann 4.0.0-0
- Support DocBook 5 as input format. BZ #1005042
- Fix duplicate first author in PDF. BZ #996351
- Include DocBook 5-compatible templates. BZ #697366
- Fix UTF8 issue in ~/.publican.cfg. BZ #987325
- Replace abstract and subtitle xsl. BZ #953675
- Change Cover page font. BZ #1006134
- Fix TOC leader in PDF. BZ #1006056
- Fix PDF Legal Notice trademarks & formatting. BZ #970851
- Fix keyword lable showing in PDF when there are no keywords. BZ #1007146
- Indicate whether a translation is older in the web GUI. BZ #889031
- Include time in update_date. BZ #979846
- Support web site navigation for books without HTML. BZ #885916
- Support ascending Revision History. BZ #999578
- Add ability to compy installed brand web content to another site. BZ #967664
- Fix PDF example.properties template. BZ #999586
- Fix PUG PDF format for OpenSuse. BZ #999581
- Simplify highlight error message. BZ #987059
- Add css styles for table sizes. BZ #1005640
- Tidy up Build.PL for better CPAN support. BZ #999259
- Fix image path for icon.svg. BZ #1011222
- Fix print_unused not handling include from higher directories. BZ #1004955
- Fix SVG fallback to PNG. BZ #990823
- Fix subtitle font size. BZ #987431
- Support grouping of books within a version. BZ #901560
- Remove bold from titles in Indic scripts. BZ #1006135
- Overhaul EPUB, basic CSS, harcode chunking, fix errors. BZ #883159
- Fix duplicate file listing in EPUB. BZ #875119
- Fix objects in EPUB not in catalog. BZ #875125
- Fix duplicate ID's in EPUBs. BZ #875116
- Fix ConfigData not being reset after testing on all platforms. BZ #999427
- Fix links to step not functioning. BZ #1009015
- Support GIT for distributed sets. BZ #864226
- Fix Build.PL not handling .mo files. BZ #1016421
- Bold and Center titlepage edition. BZ #1017548
- Fix broken use of pushd in Build.PL. BZ #1018608
- Remove XML from spec file abstract. BZ #1018796
- Fix UTF8 in publican.cfg not being handled. BZ #1020059
- Fix Indic PDF build on F19. BZ #1018024
- Fix UTF8 encoding for title in Revision_History.xml BZ #1020570
- Fix browser not detecting UTF8 on HTML5 files with .html extension. BZ #1018659
- Fix styling of DB4 example, package, & option. Remove html.longdesc.embed xsl. BZ #1023248
- Fix UTF8 in Groups.xml. BZ #1022575
- Add translations for "Edition" BZ# 1007141
- Add translations for "English is newer" BZ #889031
- Fix broken or-IN translation.
- Update DB4 CSS steps, stepalts, OLs, term. BZ #1026173
- Remove chunk override from html.xsl. BZ #1026563
- Fix path to POD. BZ #1026563
- Update CLI translations
- Various fixes to Common Content + update Common Content translation. BZ #1027248
- Update and correct Debian installation instructions. BZ #1013934
- Correct OpenSUSE installation instructions. BZ #1000534
- Add Docker installation instructions. BZ #1015943
- Clarify where relative paths are used in brand instructions - BZ #1028815
- Update and clarify translation instructions BZ #1021287
- Expose glossterm in PO files to support sortas attribute. BZ #1030591
- Add report action to print readability statistics. BZ #1031364
- Change comment in syntax highlight to light grey. BZ #1030718
- Document use of "sortas" for indexes and glossaries in PUG
- Fix newline in translation affecting output. BZ #1036150
* Fri Oct 4 2013 Jeff Fearn 3.9.9-0
- Publican 4.0 RC1
* Wed Sep 04 2013 Jeff Fearn 3.2.1-0
- Fix empty images dir causing packaging fail. BZ #996349
- Fix draft background being in front. BZ #996361
- Fix Titles that are ulinks are incorrectly positioned. BZ #995095
- Fix Syntax Highlighting not working when Language and Module names differ. BZ #995932
- Fix missing '/' on callout image url. BZ #998736
- Add string for brand customistaion BZ #1002388
* Thu Aug 8 2013 Jeff Fearn 3.2.0-0
- Add spaces to web-spec.xsl to work around newer libxml2 eating white space in spec files BZ #982424
- Fix typos in common content BZ #952490 #974918
- Stop menu bouncing. BZ #953716
- Fix ID missing from admonitions. BZ #966494
- Support corpauthor for PDF. BZ #908666
- Fix nested block tags breaking translation flow. BZ #909728
- Fix multiple calls to update_po breaking packaging. BZ #891167
- Add website labels and translations. BZ #979885
- Add orgname to block/inline code. BZ #872955
- Fix get_keywords not using correct info file. BZ #957956
- Improve web print CSS. BZ #927513
- Fix pre border in PDF. BZ #905752
- Fix epub DOCTYPE. BZ #875129
- Fix step first child style. BZ #971221
- Fix long link word wrap in PDF. BZ #923481
- Support case-insensitive "language" attribute. BZ #919474
- Apply title style patch from Jaromir Hradilek. BZ #924518
- Expose %book_ver_list to products/versions_index.tmpl. BZ #962643
- Allow brands to ship web templates. Add site config toc_js. BZ #956935
- Add pdftool option to build for pdf tool control. BZ #953728
- Add default mapping for language to locale. BZ #844202
- Fix ID missing from translated Revision History. BZ #911462
- Add pub_dir option to override publish directory. BZ #830062
- Removed show_unknown parameter and associated code. BZ #915428
- Add img_dir parameter to override images directory. BZ #919481
- Support all DocBook conditionals. BZ #919486
- Flag spaces in product number as invalid. BZ #973895
- Standardized prompts in commands. BZ #880456
- Updated web_formats publican.cfg info BZ #839141
- Replaced 'home page' with 'product or version page' BZ #921803
- Replaced a broken link to CPAN with a working link BZ# 973461
- Remove duplicate brand files from base install. BZ #966143
- Add extras_dir parameter to override extras directory. BZ #953998
- Fix PDF ignoring cover logo. BZ #974353
- Add trans_drop action to freeze source language for translation. BZ #887707
- Fix empty pot files not being deleted. BZ #961413
- Fix long title layout on cover page in PDF. BZ #956934
- Add Mac OS X Lion installation instructions. BZ# 979229
- Add file handle limit workaround to FAQ BZ #952476
- Support CDATA tags. BZ #958343
- Fix UTF8 image names getting mangled in publish. BZ #953618
- Add wkhtmltopdf_opts parameter to pass options to wkhtmltopdf. BZ #951290
- Fix edition missing on PDF cover pages. BZ #956940
- Support XML in add_revision member. BZ #862465
- Fix duplicate footnotes in bibliography. BZ #653447
- Fix Link from footlink to footlink-ref not working in PDF. BZ #909786
- Fix TOC draft watermark in PDF. BZ #905271
- Add common-db5 sub package. BZ #958495
- Support decimals in colwidth & convert exact measures to pixels. BZ #913775
- Tweak equation formatting. BZ #804531
- Fix POT-Creation-Date format. BZ #985836
- Fix site stats report swapping languages and products.
- Fix web_dir not used for home page packages. BZ #988191
- Updated web site instructions - BZ#979224
* Mon Mar 18 2013 Jeff Fearn 3.1.5-0
- Fix translated PDF encode issue when build from packaged books. BZ #922618
* Tue Mar 12 2013 Jeff Fearn 3.1.4-0
- Fix entities in Book_Info braking build. BZ #917898
- add translations of "Revision History". BZ #918365
- Fix TOC title not translated in PDF. BZ #918365
- Fix translated strings with parameters. BZ #891166
- update translations
- add it-IT translation of PUG via BZ #797515
* Fri Feb 22 2013 Jeff Fearn 3.1.3-1
- Fix add_revision breaking XML parser. BZ #912985
- Stronger fix for cover pages causing page number overrun. BZ #912967
- Fix CSS for article front page subtile. BZ #913016
* Mon Feb 18 2013 Jeff Fearn 3.1.2-0
- Fix tests failing when publican not installed. BZ #908956
- Fix broken mr-IN/Conventions.po. BZ #908956
- Fix footnote link unclickable. BZ #909006
- Fix missing translations for common files. BZ #908976
- Fix using edition for version on cover pages. BZ #912180
- Fix nested entities causing XML::TreeBuilder to fail. BZ #912187
* Thu Feb 7 2013 Jeff Fearn 3.1.1-0
- Fix web site CSS for admonitions. BZ #908539
* Mon Feb 4 2013 Jeff Fearn 3.1.0-2
- Fix translated text
* Mon Feb 4 2013 Jeff Fearn 3.1.0-1
- Warn of failure to chmod/chown.
* Fri Jan 25 2013 Jeff Fearn 3.1.0-0
- new upstream package.
* Wed Oct 31 2012 Jeff Fearn 3.0.0-0
- new upstream package.
LICENSE 000444 041472 041472 5420 12555605450 15105 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 =============================================================================
PUBLICAN -- COPYRIGHT, LICENSING, AND DISCLAIMER OF WARRANTY
=============================================================================
Publican is copyright 2007-2009 Red Hat, Inc.
Author: Jeff Fearn except for:
Author (defaults.xsl, html-single.xsl, html.xsl, pdf.xsl, txt.xsl, and
xhtml-common.xsl): Jeff Fearn ,
Tammy Fox , and Andy Fitzsimon
Author (TreeView.pm): Ryan Lerch
Publican is free software; you can redistribute it and/or modify it under
the following terms:
1. Files in the datadir/Common_Content directory and its subdirectories are
licensed under the CC0 1.0 Universal license.
To the extent possible under law, the developers of Publican waive all
copyright and related or neighboring rights to the files contained in
the datadir/Common_Content directory and its subdirectories.
NOTE: The legal notice delimited by the tag in the
Legal_Notice.xml file applies to the documents in which it is included
by Publican. It does not apply to the file itself nor to the package
containing the file.
2. Other than the files in the datadir/Common_Content directory and its
subdirectories, you can redistribute and/or modify any other part of
Publican under your choice of (1) the GNU General Public License,
version 2 or any later version, and/or (2) the Artistic License 1.0.
DISCLAIMER OF WARRANTY
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR, OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
fdl.txt 000444 041472 041472 47663 12555605450 15445 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 GNU Free Documentation License
Version 1.2, November 2002
Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or other
functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.
This License is a kind of "copyleft", which means that derivative
works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.
A "Modified Version" of the Document means any work containing the
Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.
A "Secondary Section" is a named appendix or a front-matter section of
the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall subject
(or to related matters) and contains nothing that could fall directly
within that overall subject. (Thus, if the Document is in part a
textbook of mathematics, a Secondary Section may not explain any
mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.
The "Invariant Sections" are certain Secondary Sections whose titles
are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.
The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a machine-readable copy,
represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent copies include plain
ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.
The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.
A section "Entitled XYZ" means a named subunit of the Document whose
title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.
The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.
2. VERBATIM COPYING
You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.
If you publish or distribute Opaque copies of the Document numbering
more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.
If the Modified Version includes new front-matter sections or
appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.
You may add a section Entitled "Endorsements", provided it contains
nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.
You may add a passage of up to five words as a Front-Cover Text, and a
passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License
give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.
The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections Entitled "History"
in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT WORKS
A compilation of the Document or its derivatives with other separate
and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these
copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.
If a section in the Document is Entitled "Acknowledgements",
"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised versions
of the GNU Free Documentation License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns. See
http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number.
If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.
ADDENDUM: How to use this License for your documents
To use this License in a document you have written, include a copy of
the License in the document and put the following copyright and
license notices just after the title page:
Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
replace the "with...Texts." line with this:
with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
If you have Invariant Sections without Cover Texts, or some other
combination of the three, merge those two alternatives to suit the
situation.
If your document contains nontrivial examples of program code, we
recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.
CC0 000444 041472 041472 16421 12555605450 14413 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 =============================================================================
Full text of the CC0 version 1.0 Univeral retrieved from:
http://creativecommons.org/publicdomain/zero/1.0/legalcode
Refer to LICENSE for a breakdown of Publican licensing
=============================================================================
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-
CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN
"AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF
THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND
DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT
OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific
works ("Commons") that the public can reliably and without fear of later
claims of infringement build upon, modify, incorporate in other works, reuse
and redistribute as freely as possible in any form whatsoever and for any
purposes, including without limitation commercial purposes. These owners may
contribute to the Commons to promote the ideal of a free culture and the
further production of creative, cultural and scientific works, or to gain
reputation or greater distribution for their Work in part through the use and
efforts of others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not limited
to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations
thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention of,
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
the Waiver for the benefit of each member of the public at large and to the
detriment of Affirmer's heirs and successors, fully intending that such Waiver
shall not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of the Work
by the public as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason be
judged legally invalid or ineffective under applicable law, then the Waiver
shall be preserved to the maximum extent permitted taking into account
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
is so judged Affirmer hereby grants to each affected person a royalty-free,
non transferable, non sublicensable, non exclusive, irrevocable and
unconditional license to exercise Affirmer's Copyright and Related Rights in
the Work (i) in all territories worldwide, (ii) for the maximum duration
provided by applicable law or treaty (including future time extensions), (iii)
in any current or future medium and for any number of copies, and (iv) for any
purpose whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective as
of the date CC0 was applied by Affirmer to the Work. Should any part of the
License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated claims
and causes of action with respect to the Work, in either case contrary to
Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied, statutory
or otherwise, including without limitation warranties of title,
merchantability, fitness for a particular purpose, non infringement, or
the absence of latent or other defects, accuracy, or the present or
absence of errors, whether or not discoverable, all to the greatest
extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
win_build.pl 000555 041472 041472 3652 12555605450 16421 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 #!/usr/bin/perl
use strict;
use warnings;
use File::pushd;
use Cwd qw(abs_path);
=head1 Description
This script builds the Windows installer. The installer creates a stand alone installation that bundles the perl environment.
It requires:
=over
=item *
The publican source including the brands
=item *
Perl
=item *
NSIS
=item *
PP
=item *
Up to date LibXML and LibXSLT packages
=back
See README for more information on deps.
=cut
my $build = 1;
my @brands = qw{publican-fedora publican-gimp publican-jboss publican-jboss-community publican-jboss-community-hibernate publican-redhat publican-jboss-community-richfaces };
if($build) {
system('Build realclean') if( -f 'Build' );
system('perl Build.PL');
system('Build');
}
my $common_content = abs_path('blib/datadir/Common_Content');
my $common_config = abs_path('blib/datadir');
my $publican = abs_path('blib/script/publican');
my $lib = abs_path('blib/lib');
my $dir;
if($build) {
$dir = pushd("Users_Guide");
system(qq{perl -CDAS -I $lib $publican clean --common_config="$common_config" --common_content="$common_content"});
system(qq{perl -CDAS -I $lib $publican build --publish --formats=html-desktop --langs=en-US --common_config="$common_config" --common_content="$common_content"});
$dir = undef;
my $brand_path = 'C:\Users\jfearn\publican';#'C:\publican\trunk';
foreach my $brand (@brands) {
print("\nPreparing $brand\n");
$dir = pushd("$brand_path/$brand");
system(qq{perl -CDAS -I $lib $publican clean --common_config="$common_config" --common_content="$common_content"});
system(qq{perl -CDAS -I $lib $publican build --formats=xml --langs=all --publish --common_config="$common_config" --common_content="$common_content"});
$dir = undef;
}
}
$dir = pushd('windows');
print("\nRunning pp\n");
system('pp @pp-opts ..\bin\publican -vv 1>2> pp.log');
print("\nRunning NSIS\n");
system('"C:\Program Files\NSIS\makensis.exe" publican.nsi');
$dir = undef;
exit(0);
TODO 000444 041472 041472 3774 12555605450 14602 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 Get Locale::Maketext::Gettext patch upstream! https://rt.cpan.org/Ticket/Display.html?id=97771
EPUB:
$ java -jar ~/Downloads/epubcheck/epubcheck-3.0b2.jar build/en-US/Publican-4.0-Users_Guide-en-US.epub
*********************************************************
GIT
Chase up tig!
branch rename
generate Changes file from git log ... requires hygeine
######################################
Publican 4.3
######################################
Test web hosting for highlight.js
1186990 - problem is there is no access to templates that are not installed from rpms ...
######################################
PUG changes
######################################
PUBLICAN_PATH="/home/jfearn/Source/fedora/publican"
perl -CDAS -I $PUBLICAN_PATH/lib $PUBLICAN_PATH/bin/publican clean
git checkout en-US/
../bin/db4-2-db5
Update command docs:
cd Users_Guide
perl -CDAS -I $PUBLICAN_PATH/lib $PUBLICAN_PATH/bin/publican --help docbook
perl -CDAS -I $PUBLICAN_PATH/lib $PUBLICAN_PATH/bin/publican build --brand_dir $PUBLICAN_PATH/datadir/Common_Content/common-db5 --formats html
perl -CDAS -I $PUBLICAN_PATH/lib $PUBLICAN_PATH/bin/publican build --brand_dir $PUBLICAN_PATH/datadir/Common_Content/common-db5 --formats drupal-book
cd build/en-US/xml
xmllint -xinclude Users_Guide.xml > test.xml
xmllint --relaxng /usr/share/xml/docbook5/schema/rng/5.0/docbook.rng --noout test.xml
gvim test.xml
cd -
jing /usr/share/xml/docbook5/schema/rng/5.0/docbook.rng --noout test.xml
Sample spec file for desktop menu package" up to date?
"1.1.1. Fedora & Red Hat Enterprise Linux 6"
add note about publican-doc package and how to read them
"4.3. Adding code samples" display programlistingco?
"4.5. Renaming a document" can we just use the auto docs?
"When I build my document, I get an error about an тundefined languageт т what's wr" note case insensitive matching
Document: mediaobject role="logo"
:nmap %% :let X=11G!!
:nmap !! /FATAL ERROR\::s/\:/\=X.':'/:let X=X+1!!
%%
:% s/FATAL ERROR/FATAL ERROR /g
Artistic 000444 041472 041472 17713 12555605450 15635 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 PERLARTISTIC(1) User Contributed Perl Documentation PERLARTISTIC(1)
NNAAMMEE
perlartistic - the Perl Artistic License
SSYYNNOOPPSSIISS
You can refer to this document in Pod via "L"
Or you can see this document by entering "perldoc perlartistic"
DDEESSCCRRIIPPTTIIOONN
This is ""TThhee AArrttiissttiicc LLiicceennssee"". Itтs here so that modules, programs,
etc., that want to declare this as their distribution license, can link
to it.
It is also one of the two licenses Perl allows itself to be
redistributed and/or modified; for the other one, the GNU General
Public License, see the perlgpl.
TThhee ""AArrttiissttiicc LLiicceennssee""
PPrreeaammbbllee
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to make
reasonable modifications.
DDeeffiinniittiioonnss
"Package"
refers to the collection of files distributed by the Copyright
Holder, and derivatives of that collection of files created through
textual modification.
"Standard Version"
refers to such a Package if it has not been modified, or has been
modified in accordance with the wishes of the Copyright Holder as
specified below.
"Copyright Holder"
is whoever is named in the copyright or copyrights for the package.
"You"
is you, if youтre thinking about copying or distributing this
Package.
"Reasonable copying fee"
is whatever you can justify on the basis of media cost, duplication
charges, time of people involved, and so on. (You will not be
required to justify it to the Copyright Holder, but only to the
computing community at large as a market that must bear the fee.)
"Freely Available"
means that no fee is charged for the item itself, though there may
be fees involved in handling the item. It also means that
recipients of the item may redistribute it under the same
conditions they received it.
CCoonnddiittiioonnss
1. You may make and give away verbatim copies of the source form of
the Standard Version of this Package without restriction, provided
that you duplicate all of the original copyright notices and
associated disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A
Package modified in such a way shall still be considered the
Standard Version.
3. You may otherwise modify your copy of this Package in any way,
provided that you insert a prominent notice in each changed file
stating how and when you changed that file, and provided that you
do at least ONE of the following:
a) place your modifications in the Public Domain or otherwise make
them Freely Available, such as by posting said modifications to
Usenet or an equivalent medium, or placing the modifications on
a major archive site such as uunet.uu.net, or by allowing the
Copyright Holder to include your modifications in the Standard
Version of the Package.
b) use the modified Package only within your corporation or
organization.
c) rename any non-standard executables so the names do not
conflict with standard executables, which must also be
provided, and provide a separate manual page for each non-
standard executable that clearly documents how it differs from
the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the
following:
a) distribute a Standard Version of the executables and library
files, together with instructions (in the manual page or
equivalent) on where to get the Standard Version.
b) accompany the distribution with the machine-readable source of
the Package with your modifications.
c) give non-standard executables non-standard names, and clearly
document the differences in manual pages (or equivalent),
together with instructions on where to get the Standard
Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of
this Package. You may charge any fee you choose for support of
this Package. You may not charge a fee for this Package itself.
However, you may distribute this Package in aggregate with other
(possibly commercial) programs as part of a larger (possibly
commercial) software distribution provided that you do not
advertise this Package as a product of your own. You may embed
this Packageтs interpreter within an executable of yours (by
linking); this shall be construed as a mere form of aggregation,
provided that the complete Standard Version of the interpreter is
so embedded.
6. The scripts and library files supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whoever
generated them, and may be sold commercially, and may be aggregated
with this Package. If such scripts or library files are aggregated
with this Package via the so-called "undump" or "unexec" methods of
producing a binary executable image, then distribution of such an
image shall neither be construed as a distribution of this Package
nor shall it fall under the restrictions of Paragraphs 3 and 4,
provided that you do not represent such an executable image as a
Standard Version of this Package.
7. C subroutines (or comparably compiled subroutines in other
languages) supplied by you and linked into this Package in order to
emulate subroutines and variables of the language defined by this
Package shall not be considered part of this Package, but are the
equivalent of input as in Paragraph 6, provided these subroutines
do not change the language in any way that would cause it to fail
the regression tests for the language.
8. Aggregation of this Package with a commercial distribution is
always permitted provided that the use of this Package is embedded;
that is, when no overt attempt is made to make this Packageтs
interfaces visible to the end user of the commercial distribution.
Such use shall not be construed as a distribution of this Package.
9. The name of the Copyright Holder may not be used to endorse or
promote products derived from this software without specific prior
written permission.
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
perl v5.10.0 2009-04-10 PERLARTISTIC(1)
pod1 000755 041472 041472 0 12555605450 14605 5 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 publican 000444 041472 041472 63512 12555605450 16511 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/pod1 =head1 NAME
publican - a DocBook XML publishing tool.
=head1 VERSION
This document describes publican version 4.0
=head1 SYNOPSIS
publican
publican
Command Options
--help Display help message
--man Display the man page
--help_actions Display a list of valid actions
-v Display the version of Publican
Valid actions are:
add_revision Add an entry to the revision history
build Transform XML to other formats (pdf, html, html-single, drupal-book, etc)
clean Remove all temporary files and directories
clean_ids Run clean ids for source XML
clean_set Remove local copies of remote set books
copy_web_brand Copy a brand's installed web content to another site
create Create a new book, set, or article
create_brand Create a new brand
create_site Create a new WebSite in the supplied location.
help_config Display help text for the configuration file
install_book Install a book in to a WebSite.
install_brand Install a brand to the supplied location
lang_stats report PO statistics
migrate_site Migrate a website DataBase from Publican < 3 to Publican 3.
package Package a language for shipping
print_banned Print a list of banned DocBook tags
print_known Print a list of QA'd DocBook tags
print_tree Print a tree of the xi:includes
print_unused Print a list of unused XML files
print_unused_images Print a list of unused Image files
remove_book Remove a book from a WebSite.
rename Rename a publican book
report Print a readability report for the source text.
site_stats Report on the contents of a WebSite
trans_drop Snapshot the source language for use in translation.
update_db Add or remove database entries. Used for processing pre-build books, such as when building packages.
update_po Update the PO files
update_pot Update the POT files
update_site Update an existing sites templates.
zt_pull Pull translations from Zanata.
zt_push Push translations to Zanata.
Run: 'bin/publican --help' for details on action usage
=head1 INTERFACE
add_revision
Add an entry to the revision history
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--lang= The language the XML will be written in
--revnumber= Revision number to use for a revision.
--date= Date to use for a revision.
--member= An entry to be added to the revision. Can be specified multiple times.
--firstname= firstname to use for a revision.
--surname= surname to use for a revision.
--email= email to use for a revision.
build
Transform XML to other formats (pdf, html, html-single, drupal-book, etc)
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--formats= Comma-separated list of formats, for example: html,pdf,html-single,html-desktop,txt,epub
--langs= Comma-separated list of languages, for example: en-US,de-DE,all
--publish Set up built content for publishing
--embedtoc Embed the web site TOC object in the generated HTML
--distributed_set This flag tells publican the data being processed is a distributed set. Note: do not use distributed_set on the command line. Publican uses this flag when calling itself to process distributed sets. This is the only safe way this flag can be used.
--novalid Do not run the DTD validation
--src_dir= Directory to source publican files from.
--pdftool= Override the tool to use when creating PDFs. Valid options are wkhtmltopdf and fop.
--pub_dir= Directory to publish files to. Defaults to publish.
clean
Remove all temporary files and directories
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--pub_dir= Directory to publish files to. Defaults to publish.
clean_ids
Run clean ids for source XML
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
clean_set
Remove local copies of remote set books
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
copy_web_brand
Copy a brand's installed web content to another site
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--brand= The brand to use
--site_config= WebSite configuration file to use or create.
--old_site_config= WebSite configuration file to use when copying content between sites.
create
Create a new book, set, or article
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--name= The name of the book, article, set, or brand
--version= The version of the product
--edition= The edition of the book, article, or set
--product= The name of the product
--brand= The brand to use
--lang= The language the XML will be written in
--type= The type (book, article, or set)
--dtdver= The version of the DocBook DTD to use
create_brand
Create a new brand
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--name= The name of the book, article, set, or brand
--lang= The language the XML will be written in
create_site
Create a new WebSite in the supplied location.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
--db_file= Override default database file.
--toc_path= Override the default TOC path.
--tmpl_path= Override the default template path.
--lang= The language the XML will be written in
help_config
Display help text for the configuration file
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
install_book
Install a book in to a WebSite.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
--lang= The language the XML will be written in
install_brand
Install a brand to the supplied location
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--path= /path/to/install/to
--web Install the web content for a brand.
--pub_dir= Directory to publish files to. Defaults to publish.
lang_stats
report PO statistics
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--lang= The language the XML will be written in
migrate_site
Migrate a website DataBase from Publican < 3 to Publican 3.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
package
Package a language for shipping
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--lang= The language the XML will be written in
--desktop Create desktop instead of web package
--brew Push SRPM to brew
--scratch Use scratch instead of tag build
--short_sighted Create package without using version in package name
--binary Build binary rpm when running package
--wait Wait for brew to finish building
--pub_dir= Directory to publish files to. Defaults to publish.
print_banned
Print a list of banned DocBook tags
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
print_known
Print a list of QA'd DocBook tags
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
print_tree
Print a tree of the xi:includes
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
print_unused
Print a list of unused XML files
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
print_unused_images
Print a list of unused Image files
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
remove_book
Remove a book from a WebSite.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
--lang= The language the XML will be written in
rename
Rename a publican book
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--name= The name of the book, article, set, or brand
--product= The name of the product
--version= The version of the product
report
Print a readability report for the source text.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
site_stats
Report on the contents of a WebSite
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
trans_drop
Snapshot the source language for use in translation.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
update_db
Add or remove database entries. Used for processing pre-build books, such as when building packages.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
--add Add a database entry
--del Delete a database entry
--lang= The language the XML will be written in
--product= The name of the product
--version= The version of the product
--name= The name of the book, article, set, or brand
--formats= Comma-separated list of formats, for example: html,pdf,html-single,html-desktop,txt,epub
--subtitle= Sub title for a book
--abstract= Abstract for a book
--product_label= product label for a book
--version_label= version label for a book
--name_label= name label for a book
--sort_order= Order to sort a book
--book_version= The version number of the book being installed.
--book_src_lang= The language this translation is based on.
update_po
Update the PO files
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--langs= Comma-separated list of languages, for example: en-US,de-DE,all
--msgmerge Use gettext's msgmerge for POT/PO merging.
--firstname= firstname to use for a revision.
--surname= surname to use for a revision.
--email= email to use for a revision.
--previous Keep previous msgid when fuzzy matches are detected in PO updates.
update_pot
Update the POT files
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
update_site
Update an existing sites templates.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
--site_config= WebSite configuration file to use or create.
zt_pull
Pull translations from Zanata.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
zt_push
Push translations to Zanata.
Options:
--help Display help message
--config=s Use a nonstandard config file
--common_config=s Override path to Common_Config directory
--common_content=s Override path to Common_Content directory
--nocolours Disable ANSI colourisation of logging.
--quiet Disable all logging.
--brand_dir=s Directory to source brand files from.
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires access to wkhtmltopdf or Apache FOP for creating PDF files.
=head1 DEPENDENCIES
Archive::Tar
Archive::Zip
Carp
Config::Simple
Cwd
DBI
DateTime
DateTime::Format::DateParse
Devel::Cover
Encode
File::Basename
File::Copy::Recursive
File::Find
File::Find::Rule
File::HomeDir
File::Inplace
File::Path
File::Spec
File::Which
File::pushd
Getopt::Long
HTML::FormatText
HTML::FormatText::WithLinks
HTML::FormatText::WithLinks::AndTables
HTML::TreeBuilder
I18N::LangTags::List
IO::String
Lingua::EN::Fathom
List::MoreUtils
List::Util
Locale::Language
Locale::Maketext::Gettext
Locale::Maketext::Lexicon
Locale::Msgfmt
Locale::PO
Module::Build
Pod::Usage
Sort::Versions
String::Similarity
Syntax::Highlight::Engine::Kate
Template
Template::Constants
Term::ANSIColor
Test::More
Test::Pod
Test::Pod::Coverage
Text::CSV_XS
Text::Wrap
Time::localtime
XML::LibXML
XML::LibXSLT
XML::Simple
XML::TreeBuilder
version
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
Bug list at L.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
=cut
etc 000755 041472 041472 0 12555605450 14515 5 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 publican-website.cfg 000444 041472 041472 337 12555605450 20553 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/etc # where will the content be published to?
toc_path: /var/www/html/docs
# Where are the templates to build the TOCs?
tmpl_path: /usr/share/publican/templates
# Where is the database?
db_file: /usr/share/publican/default.db
bin 000755 041472 041472 0 12555605450 14512 5 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 fix-zanata-map 000555 041472 041472 4625 12555605450 17421 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/bin #!/usr/bin/perl -CDAS
use strict;
use warnings;
use XML::TreeBuilder;
my $file = 'zanata.xml';
my %mapping = (
'ar' => 'ar-SA',
'as' => 'as-IN',
'ast' => 'ast-ES',
'bg' => 'bg-BG',
'bn-IN' => 'bn-IN',
'bs' => 'bs-BA',
'ca' => 'ca-ES',
'cs' => 'cs-CZ',
'da' => 'da-DK',
'de-CH' => 'de-CH',
'de-DE' => 'de-DE',
'el' => 'el-GR',
'en-US' => 'en-US',
'es-ES' => 'es-ES',
'fa' => 'fa-IR',
'fi' => 'fi-FI',
'fr' => 'fr-FR',
'gu' => 'gu-IN',
'he' => 'he-IL',
'hi' => 'hi-IN',
'hr' => 'hr-HR',
'hu' => 'hu-HU',
'id' => 'id-ID',
'is' => 'is-IS',
'it' => 'it-IT',
'ja' => 'ja-JP',
'kn' => 'kn-IN',
'ko' => 'ko-KR',
'lv' => 'lv-LV',
'ml' => 'ml-IN',
'mr' => 'mr-IN',
'ms' => 'ms-MY',
'nb' => 'nb-NO',
'nl' => 'nl-NL',
'or' => 'or-IN',
'pa' => 'pa-IN',
'pl' => 'pl-PL',
'pt-BR' => 'pt-BR',
'pt-PT' => 'pt-PT',
'ru' => 'ru-RU',
'si' => 'si-LK',
'sk' => 'sk-SK',
'sr-Latn' => 'sr-Latn-RS',
'sr-Cyrl' => 'sr-RS',
'sv' => 'sv-SE',
'ta-IN' => 'ta-IN',
'te' => 'te-IN',
'th' => 'th-TH',
'tr' => 'tr-TR',
'uk' => 'uk-UA',
'zh-Hans-CN' => 'zh-CN',
'zh-Hant-TW' => 'zh-TW',
);
my $xml_doc = XML::TreeBuilder->new( { 'NoExpand' => "1", 'ErrorContext' => "2" } );
$xml_doc->store_comments(1);
$xml_doc->store_declarations(1);
$xml_doc->parse_file($file)
|| croak( maketext( "Can't open file '[_1]' [_2]", $file, $@ ) );
fix_mapping($xml_doc);
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", "$file" )
|| croak( maketext( "Could not open [_1] for output!", $file ) );
print( $OUTDOC $xml_doc->as_XML() );
close($OUTDOC);
exit;
#### code ###
sub fix_mapping {
my $xml_doc = shift;
$xml_doc->pos( $xml_doc->root() );
foreach my $node ( $xml_doc->look_down( "_tag", "locale" ) ) {
my $locale = $node->as_text();
if ( defined( $mapping{$locale} ) && $mapping{$locale} ne $locale ) {
$node->attr( 'map-from', $mapping{$locale} );
}
}
}
publican 000555 041472 041472 147412 12555605450 16443 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/bin #!/usr/bin/perl -CDAS
use warnings;
use strict;
use 5.008;
use Carp;
use Getopt::Long qw(:config no_auto_abbrev);
use Pod::Usage;
use Publican;
use Publican::CreateBook;
use Publican::CreateBrand;
use Publican::Builder;
use Publican::Builder::DocBook4;
use Publican::Builder::DocBook5;
use Publican::XmlClean;
use Publican::TreeView;
use Publican::WebSite;
use File::Path;
use File::Find::Rule;
use File::pushd;
use Archive::Tar;
use Term::ANSIColor qw(:constants);
use Cwd qw(abs_path cwd);
use File::Basename;
use File::HomeDir;
use Publican::ConfigData;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
use Lingua::EN::Fathom;
#binmode STDIN, ":encoding(UTF-8)";
#binmode STDOUT, ":encoding(UTF-8)";
my $VERSION = "$Publican::VERSION";
my $LANG_PATTERN = q|__LANG__|;
my $WEB_TEMPLATE_PATH = Publican::ConfigData->config('web');
my $DATA_DIR = Publican::ConfigData->config('datadir');
# Try to catch SRPMS created using outdated versions of publican in brew/koji/mock
if ( ( $ENV{RPM_BUILD_DIR} )
&& ( $ENV{RPM_BUILD_DIR} ne "" )
&& ( $ENV{RPM_PACKAGE_NAME} ne "publican" )
&& (-f "/builddir/build/SRPMS/$ENV{RPM_PACKAGE_NAME}-$ENV{RPM_PACKAGE_VERSION}-$ENV{RPM_PACKAGE_RELEASE}.src.rpm"
)
)
{
my $pkg
= qq|/builddir/build/SRPMS/$ENV{RPM_PACKAGE_NAME}-$ENV{RPM_PACKAGE_VERSION}-$ENV{RPM_PACKAGE_RELEASE}.src.rpm|;
my $req_version
= qx|rpm --requires -qp $pkg \| grep 'publican-API' \| sed -e 's/^[^0-9\.]*//'|;
system("rpm -Uvh $pkg");
my $spec = qq|/builddir/build/SPECS/$ENV{RPM_PACKAGE_NAME}.spec|;
my $db_count = qx|grep -c 'publican update_db' $spec|;
my $pm_count = qx|grep -c 'use Publican' $spec|;
chomp($req_version);
if (( $db_count > 0 or $pm_count > 0 )
and ( !$req_version
|| $req_version eq ""
|| $req_version != $Publican::SPEC_VERSION )
)
{
croak(
"\n\n\nERROR: The version of publican used to create the SRPM is not compatible with this version of publican. Upgrade or downgrade publican on your local machine to a version that supplies API version $Publican::SPEC_VERSION and try again.\n\n\n"
);
}
}
### Code goes here
my $man = 0;
my $help = 0;
my $action = "";
my $help_actions = 0;
my $show_version = 0;
my $bash_comp = undef;
#Getopt::Long::Configure("debug");
my $ver = $VERSION;
$ver =~ s/v//g;
my @pod_paths
= ( './pod1', Publican::ConfigData->config('docdir') . "/publican-$ver", Publican::ConfigData->config('docdir') . "/publican" );
# Global options
my %opts = (
help => \$help,
man => \$man,
v => \$show_version,
help_actions => \$help_actions,
bash => \$bash_comp,
);
#Action options
my %options = (
help => maketext('Display help message'),
man => maketext('Display full man page'),
v => maketext('Display the version of Publican'),
'config=s' => maketext('Use a nonstandard config file'),
binary => maketext('Build binary rpm when running package'),
brew => maketext('Push SRPM to brew'),
scratch => maketext('Use scratch instead of tag build'),
wait => maketext('Wait for brew to finish building'),
'common_config=s' => maketext('Override path to Common_Config directory'),
'common_content=s' =>
maketext('Override path to Common_Content directory'),
'formats=s' => maketext(
'Comma-separated list of formats, for example: html,pdf,html-single,html-desktop,txt,epub'
),
'langs=s' => maketext(
'Comma-separated list of languages, for example: en-US,de-DE,all'),
'embedtoc' =>
maketext('Embed the web site TOC object in the generated HTML'),
'name=s' => maketext('The name of the book, article, set, or brand'),
'version=s' => maketext('The version of the product'),
'edition=s' => maketext('The edition of the book, article, or set'),
'product=s' => maketext('The name of the product'),
'brand=s' => maketext('The brand to use'),
'lang=s' => maketext('The language the XML will be written in'),
'type=s' => maketext('The type (book, article, or set)'),
publish => maketext('Set up built content for publishing'),
desktop => maketext('Create desktop instead of web package'),
short_sighted =>
maketext('Create package without using version in package name'),
'path=s' => maketext('/path/to/install/to'),
distributed_set => maketext(
qq|This flag tells publican the data being processed is a distributed set. Note: do not use distributed_set on the command line. Publican uses this flag when calling itself to process distributed sets. This is the only safe way this flag can be used.|
),
nocolours => maketext('Disable ANSI colourisation of logging.'),
quiet => maketext('Disable all logging.'),
## WebSite options
'db_file=s' => maketext('Override default database file.'),
'toc_path=s' => maketext('Override the default TOC path.'),
'tmpl_path=s' => maketext('Override the default template path.'),
'site_config=s' =>
maketext('WebSite configuration file to use or create.'),
novalid => maketext('Do not run the DTD validation'),
add => maketext('Add a database entry'),
del => maketext('Delete a database entry'),
'subtitle=s' => maketext('Sub title for a book'),
'abstract=s' => maketext('Abstract for a book'),
'product_label=s' => maketext('product label for a book'),
'version_label=s' => maketext('version label for a book'),
'name_label=s' => maketext('name label for a book'),
## Revisions
'revnumber=s' => maketext('Revision number to use for a revision.'),
'date=s' => maketext('Date to use for a revision.'),
'member=s@' => maketext(
'An entry to be added to the revision. Can be specified multiple times.'
),
'firstname=s' => maketext('firstname to use for a revision.'),
'surname=s' => maketext('surname to use for a revision.'),
'email=s' => maketext('email to use for a revision.'),
msgmerge => maketext(q|Use gettext's msgmerge for POT/PO merging.|),
web => maketext(q|Install the web content for a brand.|),
'src_dir=s' => maketext(q|Directory to source publican files from.|),
'brand_dir=s' => maketext(q|Directory to source brand files from.|),
'sort_order=s' => maketext('Order to sort a book'),
'pdftool=s' => maketext(
'Override the tool to use when creating PDFs. Valid options are wkhtmltopdf and fop.'
),
'pub_dir=s' =>
maketext(q|Directory to publish files to. Defaults to publish.|),
'dtdver=s' => maketext('The version of the DocBook DTD to use'),
'book_version=s' =>
maketext('The version number of the book being installed.'),
'book_src_lang=s' =>
maketext('The language this translation is based on.'),
'old_site_config=s' => maketext(
'WebSite configuration file to use when copying content between sites.'
),
'previous' => maketext(
'Keep previous msgid when fuzzy matches are detected in PO updates.'),
showfuzzy => maketext('Show fuzzy translation entries in output. Defaults off.'),
'allow_network' => maketext(q|Allow the XML and XSLT processing to access the network. Defaults off.|),
no_clean => maketext(q|Do not use the XML cleaner, use the XML as provided. WARNING: Will be ignored for translations!|),
);
# Options all actions use
my @utility_opts = (
'help', 'config=s',
'common_config=s', 'common_content=s',
'nocolours', 'quiet',
'brand_dir=s', 'allow_network'
);
# Actions
my %actions = (
'build' => {
'brief' => maketext(
'Transform XML to other formats (pdf, html, html-single, drupal-book, etc)'
),
'options' => [
'formats', 'langs', 'publish', 'embedtoc',
'distributed_set', 'novalid', 'src_dir', 'pdftool',
'pub_dir', 'showfuzzy', 'no_clean'
],
},
'clean' => {
'brief' => maketext('Remove all temporary files and directories'),
'options' => ['pub_dir'],
},
'clean_set' => {
'brief' => maketext('Remove local copies of remote set books'),
'options' => [],
},
'clean_ids' => {
'brief' => maketext('Run clean ids for source XML'),
'options' => [],
},
'print_tree' => {
'brief' => maketext('Print a tree of the xi:includes'),
'options' => [],
},
'print_banned' => {
'brief' => maketext('Print a list of banned DocBook tags'),
'options' => [],
},
'print_known' => {
'brief' => maketext("Print a list of QA'd DocBook tags"),
'options' => [],
},
'print_unused' => {
'brief' => maketext('Print a list of unused XML files'),
'options' => [],
},
'print_unused_images' => {
'brief' => maketext('Print a list of unused Image files'),
'options' => [],
},
'create' => {
'brief' => maketext('Create a new book, set, or article'),
'options' => [
'name', 'version', 'edition', 'product',
'brand', 'lang', 'type', 'dtdver'
],
},
'create_brand' => {
'brief' => maketext('Create a new brand'),
'options' => [ 'name', 'lang' ],
},
'package' => {
'brief' => maketext('Package a language for shipping'),
'options' => [
'lang', 'desktop', 'brew', 'scratch',
'short_sighted', 'binary', 'wait', 'pub_dir'
],
},
'update_pot' => {
'brief' => maketext('Update the POT files'),
'options' => [],
},
'update_po' => {
'brief' => maketext('Update the PO files'),
'options' => [
'langs', 'msgmerge', 'firstname', 'surname',
'email', 'previous'
],
},
'install_brand' => {
'brief' => maketext('Install a brand to the supplied location'),
'options' => [ 'path', 'web', 'pub_dir' ],
},
'copy_web_brand' => {
'brief' =>
maketext("Copy a brand's installed web content to another site"),
'options' => [ 'brand', 'site_config', 'old_site_config' ],
},
'help_config' => {
'brief' => maketext('Display help text for the configuration file'),
'options' => [],
},
'lang_stats' => {
'brief' => maketext('report PO statistics'),
'options' => ['lang'],
},
## WebSite actions
'create_site' => {
'brief' => maketext('Create a new WebSite in the supplied location.'),
'options' =>
[ 'site_config', 'db_file', 'toc_path', 'tmpl_path', 'lang' ],
},
'update_site' => {
'brief' => maketext('Update an existing sites templates.'),
'options' => ['site_config'],
},
'install_book' => {
'brief' => maketext('Install a book in to a WebSite.'),
'options' => [ 'site_config', 'lang' ],
},
'remove_book' => {
'brief' => maketext('Remove a book from a WebSite.'),
'options' => [ 'site_config', 'lang' ],
},
'site_stats' => {
'brief' => maketext('Report on the contents of a WebSite'),
'options' => ['site_config'],
},
'update_db' => {
'brief' => maketext(
'Add or remove database entries. Used for processing pre-build books, such as when building packages.'
),
'options' => [
'site_config', 'add',
'del', 'lang',
'product', 'version',
'name', 'formats',
'subtitle', 'abstract',
'product_label', 'version_label',
'name_label', 'sort_order',
'book_version', 'book_src_lang'
],
},
'add_revision' => {
'brief' => maketext('Add an entry to the revision history'),
'options' => [
'lang', 'revnumber', 'date', 'member',
'firstname', 'surname', 'email'
],
},
'rename' => {
'brief' => maketext('Rename a publican book'),
'options' => [ 'name', 'product', 'version' ],
},
'migrate_site' => {
'brief' => maketext(
'Migrate a website DataBase from Publican < 3 to Publican 3.'),
'options' => ['site_config'],
},
'trans_drop' => {
'brief' =>
maketext('Snapshot the source language for use in translation.'),
'options' => [],
},
'report' => {
'brief' =>
maketext('Print a readability report for the source text.'),
'options' => [],
},
'zt_pull' => {
'brief' => maketext('Pull translations from Zanata.'),
'options' => [],
},
'zt_push' => {
'brief' => maketext('Push translations to Zanata.'),
'options' => [],
},
);
# Grab to limit options to the valid ones for this action
# TODO should we croak on more than one action? Handle more than one?
$action = ( $ARGV[0] || "" );
# Getopt: standard + the options for the supplied action
my @optns = ( keys(%opts), @utility_opts );
if ( defined $actions{$action} ) {
foreach my $opt ( @{ $actions{$action}->{options} } ) {
if ( $options{$opt} ) {
push( @optns, $opt );
}
# match options that take a String
# this will need to be exapnded if other types are used
elsif ( $options{"$opt=s"} ) {
push( @optns, "$opt=s" );
}
elsif ( $options{"$opt=s@"} ) {
push( @optns, "$opt=s@" );
}
else {
# This should never happen
croak(
maketext(
"Invalid option '[_1]' in \$actions{\$action}->{options}",
$opt
)
);
}
}
}
GetOptions( \%opts, @optns, )
or pod2usage(
-verbose => 1,
-exit => 1,
-input => 'publican',
-pathlist => \@pod_paths
);
# catch multiple actions
if ( scalar @ARGV > 1 ) {
croak(
maketext(
"publican only accepts one action you supplied '[_1]': [_2]\n",
scalar @ARGV, join( ' & ', @ARGV )
)
);
}
# Getopt will remove the options leaving only the action
$action = ( $ARGV[0] || "" );
if ($show_version) {
print("version=$VERSION\n");
exit(0) if ( $action eq "" );
}
# Undocumented way of getting help for all actions
if ( $help and ( $action eq "all" ) ) {
foreach my $cmd ( sort( keys(%actions) ) ) {
_help_action($cmd);
print("\n");
}
exit(0);
}
sub _help_actions {
print( "\n", maketext("Valid actions are:"), "\n\n" );
foreach my $cmd ( sort( keys(%actions) ) ) {
printf( " %-12s %s\n", $cmd, $actions{$cmd}->{brief} );
}
print("\n\n");
print(
maketext(
"Run: '[_1] --help' for details on action usage", $0
),
"\n\n"
);
return;
}
if ($bash_comp) {
_bash_completion();
exit(0);
}
# Undocumented way of getting help for all actions as DocBook 5.0 XML
# TODO should spit out the docs in every language ...
if ( $help and ( $action eq "docbook" ) ) {
my $xml_doc = XML::Element->new_from_lol(
[ 'appendix', {id=>'Command_summary'}, [ 'info', [ 'title', maketext('Command summary') ], ] ] );
my $section = XML::Element->new_from_lol(
[ 'section',
{ id => 'Auto_Docs-Command_options' },
[ 'info', [ 'title', maketext('Command options') ], ],
]
);
my $var_list = XML::Element->new_from_lol(
[ 'variablelist' ]
);
$section->push_content($var_list);
$xml_doc->push_content($section);
foreach my $option ( sort(@utility_opts) ) {
my $entry = XML::Element->new_from_lol(
[ 'varlistentry',
[ 'term', "--$option" ],
[ 'listitem', [ 'para', $options{$option} ] ]
]
);
$var_list->push_content($entry);
}
$section = XML::Element->new_from_lol(
[ 'section',
{ id => 'Auto_Docs-Command_actions' },
[ 'info', [ 'title', maketext('Command actions') ], ],
]
);
$var_list = XML::Element->new_from_lol(
[ 'variablelist' ]
);
$section->push_content($var_list);
$xml_doc->push_content($section);
foreach my $cmd ( sort( keys(%actions) ) ) {
$var_list->push_content( _help_action_asdb($cmd) );
}
my $OUTDOC;
my $out_file = 'en-US/Auto_Docs.xml';
open( $OUTDOC, ">:encoding(UTF-8)", $out_file )
|| croak( maketext( "Could not open [_1] for output!", $out_file ) );
print( $OUTDOC Publican::Builder::dtd_string(
{ tag => 'appendix', dtdver => '5.0', cleaning => 1 }
)
);
print( $OUTDOC $xml_doc->as_XML() );
close($OUTDOC);
$xml_doc->root()->delete();
my $cleaner = Publican::XmlClean->new( { exclude_ent => 1 } );
$cleaner->process_file( { file => $out_file, out_file => $out_file } );
# all the parameters
$xml_doc = XML::Element->new_from_lol(
[ 'appendix', {id => 'Configuration_summary'}, [ 'info', [ 'title', maketext('Configuration summary') ], ] ] );
$section = XML::Element->new_from_lol(
[ 'section',
{ id => 'Auto_Docs_Configs-General_options' },
[ 'info', [ 'title', maketext('General options') ], ],
['para', maketext("These are set in the books or brands configuration files.") ],
]
);
my $gen_list = XML::Element->new_from_lol(
[ 'variablelist']
);
$section->push_content($gen_list);
$xml_doc->push_content($section);
my $brand_list = XML::Element->new_from_lol(
[ 'variablelist'],
);
$section = XML::Element->new_from_lol(
[ 'section',
{ id => 'Auto_Docs_Configs-Brand_options' },
[ 'info', [ 'title', maketext('Brand options') ], ],
['para', maketext("These are set in the brands configuration files.") ],
]
);
$section->push_content($brand_list);
$xml_doc->push_content($section);
my $web_list = XML::Element->new_from_lol(
[ 'variablelist'],
);
$section = XML::Element->new_from_lol(
[ 'section',
{ id => 'Auto_Docs_Configs-Site_option' },
[ 'info', [ 'title', maketext('Site options') ], ],
['para', maketext("These are set in the sites configuration file.") ],
]
);
$section->push_content($web_list);
$xml_doc->push_content($section);
$xml_doc->push_content(Publican::params_as_docbook($gen_list,$brand_list,$web_list));
$xml_doc->push_content(Publican::WebSite::site_params_as_docbook($web_list));
$out_file = 'en-US/Auto_Docs_Configs.xml';
open( $OUTDOC, ">:encoding(UTF-8)", $out_file )
|| croak( maketext( "Could not open [_1] for output!", $out_file ) );
print( $OUTDOC Publican::Builder::dtd_string(
{ tag => 'appendix', dtdver => '5.0', cleaning => 1 }
)
);
print( $OUTDOC $xml_doc->as_XML() );
close($OUTDOC);
$xml_doc->root()->delete();
$cleaner->process_file( { file => $out_file, out_file => $out_file } );
exit(0);
}
sub _help_action_asdb {
my $cmd = shift || croak maketext( "[_1] is a required argument", 'cmd' );
my $brief = $actions{$cmd}->{brief};
my $varentry = XML::Element->new_from_lol(
[ 'varlistentry', {id => $cmd},
[ 'term', [ 'prompt', '$' ], [ 'command', ' publican' ],
" $cmd"
],
]
);
my $item
= XML::Element->new_from_lol( [ 'listitem', [ 'para', $brief ] ], );
$varentry->push_content($item);
my $varlist = XML::Element->new_from_lol( [ 'variablelist', ] );
foreach my $option ( sort( @{ $actions{$cmd}->{options} } ) ) {
my $entry;
if ( $options{$option} ) {
$entry = XML::Element->new_from_lol(
[ 'varlistentry',
[ 'term', "--$option" ],
[ 'listitem', [ 'para', $options{$option} ] ]
]
);
}
else {
my $text
= maketext( $options{"$option=s"} || $options{"$option=s@"} );
$entry = XML::Element->new_from_lol(
[ 'varlistentry',
[ 'term', "--$option=", [ 'replaceable', uc($option) ] ],
[ 'listitem', [ 'para', $text ] ]
]
);
}
$varlist->push_content($entry);
}
$item->push_content($varlist) if(!$varlist->is_empty());
return ($varentry);
}
# catch no action set
if ( $action eq "" ) {
pod2usage(
-verbose => 1,
-exit => 0,
-input => 'publican',
-pathlist => \@pod_paths
) if $help;
pod2usage(
-verbose => 2,
-exit => 0,
-input => 'publican',
-pathlist => \@pod_paths
) if $man;
if ($help_actions) {
_help_actions();
exit(0);
}
pod2usage(
-msg => "\n" . maketext("Action required!") . "\n",
-verbose => 1,
-exit => 1,
-input => 'publican',
-pathlist => \@pod_paths
);
exit(1);
}
# Catch bogus action
if ( not defined( $actions{$action} ) ) {
print( maketext( "'[_1]' is an unknown action!", $action ), "\n\n" );
_help_actions();
exit(1);
}
sub _help_action {
my $cmd = shift || croak maketext( "[_1] is a required argument", 'cmd' );
print( "$cmd\n " . $actions{$cmd}->{brief} );
print( "\n\n\t", maketext("Options:"), "\n" );
foreach my $option ( @utility_opts, @{ $actions{$cmd}->{options} } ) {
debug_msg("TODO: does printf work for right to left languages?\n");
if ( $options{$option} ) {
printf( " --%-20s %s\n",
$option, maketext( $options{$option} ) );
}
else {
printf(
" --%-20s %s\n",
"$option=<" . uc($option) . ">",
maketext( $options{"$option=s"} || $options{"$option=s@"} )
);
}
}
print("\n");
return;
}
# $action must be set to get here
if ($help) {
_help_action($action);
exit(0);
}
#######################################################################
#
# Start processing actions
#
#######################################################################
#pod2usage(1) if ( !$name || $type !~ /[Book|Set|Article]/);
if ( $action eq 'create' ) {
my $docname = $opts{name}
|| croak( maketext("name is a required parameter") );
$docname =~ s/\s/_/g;
my $creator = Publican::CreateBook->new(
{ name => $docname,
version => $opts{version},
edition => $opts{edition},
product => $opts{product},
brand => $opts{brand},
lang => $opts{lang},
type => $opts{type},
dtdver => $opts{dtdver},
}
);
$creator->create();
my $dir = pushd($docname);
my $publican = Publican->new(
{ configfile => $opts{config},
common_config => $opts{common_config},
common_content => $opts{common_content},
QUIET => $opts{quiet},
NOCOLOURS => $opts{nocolours},
}
);
my $builder;
if ( $opts{dtdver} && $opts{dtdver} =~ /^5/ ) {
$builder = Publican::Builder::DocBook5->new();
}
else {
$builder = Publican::Builder::DocBook4->new();
}
$builder->clean_ids();
$dir = undef;
exit(0);
}
if ( $action eq 'create_brand' ) {
my $creator = Publican::CreateBrand->new(
{ name => $opts{name},
lang => $opts{lang},
}
);
$creator->create();
exit(0);
}
if ( $action eq 'create_site' ) {
my $site_config = $opts{site_config}
|| croak( maketext( "[_1] is a required argument", 'site_config' ) );
my $db_file = $opts{db_file}
|| croak( maketext( "[_1] is a required argument", 'db_file' ) );
my $toc_path = $opts{toc_path}
|| croak( maketext( "[_1] is a required argument", 'toc_path' ) );
my $tmpl_path = $opts{tmpl_path} || undef;
my $def_lang = $opts{lang} || undef;
if ( -f $site_config ) {
croak(
maketext(
"Config file exists, you must supply a non-existent filename."
)
);
}
my $config = new Config::Simple();
$config->syntax('http');
my ( $filename, $directories, $suffix ) = fileparse($db_file);
mkpath($directories) unless -d $directories;
$config->param( 'db_file', abs_path($db_file) ) if ($db_file);
if ($toc_path) {
mkpath($toc_path) unless -d $toc_path;
$config->param( 'toc_path', abs_path($toc_path) );
rcopy( "$WEB_TEMPLATE_PATH/*", "$toc_path/." );
}
$config->param( 'tmpl_path', abs_path($tmpl_path) ) if ($tmpl_path);
$config->param( 'def_lang', $def_lang ) if ($def_lang);
$config->write($site_config);
my $ws = Publican::WebSite->new(
{ create => 1, site_config => $site_config } );
$ws->regen_all_toc();
exit(0);
}
if ( $action eq 'update_site' ) {
my $site_config = $opts{site_config} || undef;
local $File::Copy::Recursive::RMTrgFil = 1;
my $ws = Publican::WebSite->new( { site_config => $site_config } );
rcopy( "$WEB_TEMPLATE_PATH/*", $ws->toc_path() . "/." );
$ws->regen_all_toc( { force => 1 } );
exit(0);
}
if ( $action eq 'migrate_site' ) {
my $site_config = $opts{site_config} || undef;
local $File::Copy::Recursive::RMTrgFil = 1;
my $ws = Publican::WebSite->new( { site_config => $site_config } );
$ws->MigrateDB();
$ws->regen_all_toc( { force => 1 } );
print(
maketext(
"Now that your site is migrated you will need to rebuild your brands and install the brands web payload on your site.\n\nIt is also recommended that you rebuild and reinstall all books to ensure the layout is properly migrated."
)
);
print( maketext('$ cd path/to/brand'), "\n" );
print( maketext('$ publican build --formats=xml --langs=all --publish'),
"\n" );
## BUGBUG should this use siteconfig?
print(
maketext(
'$ publican install_brand --web --path=/path/to/site/%{brand}'),
"\n"
);
print(
maketext('$ publican update_site --site_config /path/to/site/config'),
"\n"
);
exit(0);
}
if ( $action eq 'site_stats' ) {
my $site_config = $opts{site_config} || undef;
my $ws = Publican::WebSite->new( { site_config => $site_config } );
print( $ws->report() );
exit(0);
}
# install/remove book for pre-build content (RPM, DEB, etc)
# BUGBUG formats isn't required for del
if ( $action eq 'update_db' ) {
my $site_config = $opts{site_config} || undef;
my $ws = Publican::WebSite->new( { site_config => $site_config } );
my $add = $opts{add} || undef;
my $del = $opts{del} || undef;
croak(
maketext("One of add or del is required when updating the database") )
unless ( $add || $del );
my $lang = $opts{lang}
|| croak( maketext( "[_1] is a required argument", 'lang' ) );
my $product = $opts{product}
|| croak( maketext( "[_1] is a required argument", 'product' ) );
my $version
= defined $opts{version}
? $opts{version}
: croak( maketext( "[_1] is a required argument", 'version' ) );
my $name = $opts{name}
|| croak( maketext( "[_1] is a required argument", 'name' ) );
my $formats = $opts{formats}
|| croak( maketext( "[_1] is a required argument", 'formats' ) );
# required for add
my $subtitle = $opts{subtitle} || undef;
my $abstract = $opts{abstract} || undef;
my $book_version = $opts{book_version} || undef;
my $book_src_lang = $opts{book_src_lang} || undef;
if ($add) {
croak( maketext( "[_1] is a required argument", 'subtitle' ) )
unless ($subtitle);
croak( maketext( "[_1] is a required argument", 'abstract' ) )
unless ($abstract);
croak( maketext( "[_1] is a required argument", 'book_version' ) )
unless ($book_version);
}
# optional for add
my $product_label = $opts{product_label} || undef;
my $version_label = $opts{version_label} || undef;
my $name_label = $opts{name_label} || undef;
my $sort_order = $opts{sort_order} || undef;
if ($add) {
$ws->update_or_add_entry(
{ language => $lang,
product => $product,
version => $version,
name => $name,
formats => $formats,
product_label => $product_label,
version_label => $version_label,
name_label => $name_label,
subtitle => $subtitle,
abstract => $abstract,
sort_order => $sort_order,
book_version => $book_version,
book_src_lang => $book_src_lang,
}
);
}
else {
$ws->del_entry(
{ language => $lang,
product => $product,
version => $version,
name => $name,
}
);
}
## BUGBUG TODO only update langauges that have been updated
# make sure OPDS is correct...
$ws->regen_all_toc();
exit(0);
}
if ( $action eq 'copy_web_brand' ) {
my $brand = $opts{brand}
|| croak( maketext( "[_1] is a required argument", 'brand' ) );
my $site_config = $opts{site_config}
|| croak( maketext( "[_1] is a required argument", 'site_config' ) );
my $old_site_config = $opts{old_site_config}
|| croak(
maketext( "[_1] is a required argument", 'old_site_config' ) );
my $old_config = new Config::Simple();
$old_config->syntax('http');
$old_config->read($old_site_config)
|| croak("Failed to load config file: $old_site_config");
my $old_path = $old_config->param('toc_path')
|| croak(
maketext(
"[_1] is a mandatory field in a site configuration file",
'toc_path'
)
);
my $new_config = new Config::Simple();
$new_config->syntax('http');
$new_config->read($site_config)
|| croak("Failed to load config file: $site_config");
my $new_path = $new_config->param('toc_path')
|| croak(
maketext(
"[_1] is a mandatory field in a site configuration file",
'toc_path'
)
);
rcopy( "$old_path/$brand", "$new_path/$brand" );
exit(0);
}
## NOTE: All targets here MUST have a valid publican.cfg file
if ( $action eq 'print_known' ) {
Publican::XmlClean::print_known_tags();
exit(0);
}
my %args = ( 'configfile' => $opts{config} );
my $src_dir;
my $cwd = cwd();
if ( defined( $opts{src_dir} ) ) {
$src_dir = pushd( $opts{src_dir} );
}
if ( !defined( $opts{pub_dir} ) ) {
$opts{pub_dir} = 'publish';
}
my $publican = Publican->new(
{ 'configfile' => $opts{config},
common_config => $opts{common_config},
common_content => $opts{common_content},
QUIET => $opts{quiet},
NOCOLOURS => $opts{nocolours},
brand_dir => $opts{brand_dir},
allow_network => $opts{allow_network},
no_clean => $opts{no_clean},
}
);
my $configfile = File::HomeDir->home() . "/.publican.cfg";
if ( -f $configfile ) {
my $user_cfg = new Config::Simple();
$user_cfg->syntax('http');
$user_cfg->read($configfile)
|| croak(
maketext( "Failed to load user config file: [_1]", $configfile ) );
$opts{firstname} = decode_utf8( $user_cfg->param('firstname') )
unless ( $opts{firstname} );
$opts{surname} = decode_utf8( $user_cfg->param('surname') )
unless ( $opts{surname} );
$opts{email} = decode_utf8( $user_cfg->param('email') )
unless ( $opts{email} );
$opts{lang} = decode_utf8( $user_cfg->param('lang') )
unless ( $opts{lang} );
$opts{formats} = decode_utf8( $user_cfg->param('formats') )
unless ( $opts{formats} );
$opts{langs} = decode_utf8( $user_cfg->param('langs') )
unless ( $opts{langs} );
}
if ( defined( $opts{src_dir} ) ) {
$publican->{config}->param( 'tmp_dir',
abs_path( "$cwd/" . $publican->param('tmp_dir') ) );
}
if ( $action eq 'print_banned' ) {
$publican->print_banned_tags();
exit(0);
}
if ( $action eq 'install_brand' ) {
my $brand = $publican->param('brand')
|| croak("Can't find brand name");
my $xml_lang = $publican->param('xml_lang');
croak( maketext( "[_1] is a required argument", 'path' ) )
unless ( $opts{path} );
croak( maketext("you need to publish the brand first") )
unless ( -d $opts{pub_dir} );
croak( maketext("destination must exist") ) unless ( -d $opts{path} );
if ( $opts{web} ) {
foreach my $ln ( split( ',', get_all_langs() ) ) {
mkpath("$opts{path}/$ln/css") unless ( -f "$opts{path}/$ln/css" );
rcopy( "$xml_lang/css/brand.css", "$opts{path}/$ln/css/brand.css" )
if ( -f "$xml_lang/css/brand.css" );
rcopy( "$ln/css/lang.css", "$opts{path}/$ln/css/lang.css" )
if ( -f "$ln/css/lang.css" );
my $images = $publican->param('img_dir');
mkpath("$opts{path}/$ln/$images")
unless ( -f "$opts{path}/$ln/$images" );
rcopy( "$xml_lang/$images/*", "$opts{path}/$ln/$images/." )
if ( -d "$xml_lang/$images" );
rcopy( "$ln/$images/*", "$opts{path}/$ln/$images/." )
if ( -d "$ln/$images" );
if ( -d "$xml_lang/scripts" ) {
mkpath("$opts{path}/$ln/scripts")
unless ( -f "$opts{path}/$ln/scripts" );
rcopy( "$xml_lang/scripts/*", "$opts{path}/$ln/scripts/." );
}
if ( -d "$ln/scripts" ) {
mkpath("$opts{path}/$ln/scripts")
unless ( -f "$opts{path}/$ln/scripts" );
rcopy( "$ln/scripts/*", "$opts{path}/$ln/scripts/." );
}
}
}
else {
rcopy( "$opts{pub_dir}/*", "$opts{path}/." );
rcopy( "publican.cfg", "$opts{path}/$brand/." );
rcopy( "defaults.cfg", "$opts{path}/$brand/." )
if ( -f "defaults.cfg" );
rcopy( "overrides.cfg", "$opts{path}/$brand/." )
if ( -f "overrides.cfg" );
}
exit(0);
}
if ( $action eq 'help_config' ) {
$publican->help_config();
exit(0);
}
if ( $action eq 'print_tree' ) {
my $treeview = Publican::TreeView->new();
$treeview->print_tree();
exit(0);
}
if ( $action eq 'print_unused' ) {
my $treeview = Publican::TreeView->new();
$treeview->print_unused();
exit(0);
}
if ( $action eq 'print_unused_images' ) {
my $treeview = Publican::TreeView->new();
$treeview->print_unused_images();
exit(0);
}
if ( $action eq 'clean' || $action eq 'package' ) {
if ( $action eq 'package' ) {
logger(
maketext(
"Running clean process to ensure stale content is not bundled in packages."
)
. "\n",
RED
);
}
logger(
maketext( "Clean: Removing [_1] and publish directories.",
$publican->param('tmp_dir') )
. "\n",
);
my $error;
rmtree( $publican->param('tmp_dir') );
rmtree( $opts{pub_dir} );
my $books = $publican->param('books') || "";
foreach my $book ( split( " ", $books ) ) {
rmtree("$book/tmp");
rmtree("$book/$opts{pub_dir}");
}
}
if ( $action eq 'clean_set' ) {
my $books = $publican->param('books') || "";
foreach my $book ( split( " ", $books ) ) {
rmtree("$book");
}
}
if ( $action eq 'clean_ids' ) {
my $dtdver = $publican->param('dtdver');
my $builder;
if ( $dtdver =~ /^5/ ) {
$builder = Publican::Builder::DocBook5->new();
}
else {
$builder = Publican::Builder::DocBook4->new();
}
$builder->clean_ids();
}
if ( $action eq 'trans_drop' ) {
my $translater = Publican::Translate->new();
$translater->trans_drop();
}
if ( $action eq 'update_pot' ) {
my $translater = Publican::Translate->new();
$translater->update_pot();
}
if ( $action eq 'update_po' ) {
my $translater = Publican::Translate->new();
if ( !defined $opts{langs} || $opts{langs} eq 'all' ) {
$translater->update_po_all(
{ msgmerge => $opts{msgmerge},
email => $opts{email},
firstname => $opts{firstname},
surname => $opts{surname},
previous => $opts{previous},
}
);
}
else {
$translater->update_po(
{ langs => $opts{langs},
msgmerge => $opts{msgmerge},
email => $opts{email},
firstname => $opts{firstname},
surname => $opts{surname},
previous => $opts{previous},
}
);
}
}
if ( $action eq 'lang_stats' ) {
my $translater = Publican::Translate->new();
if ( $opts{lang} eq 'all' ) {
foreach my $lang ( split( /,/, get_all_langs(1) ) ) {
$translater->po_report( { lang => $lang } );
}
}
else {
$translater->po_report( { lang => $opts{lang} } );
}
}
if ( $action eq 'build' ) {
my $dtdver = $publican->param('dtdver');
my $builder;
if ( $dtdver =~ m/^5/ ) {
$builder = Publican::Builder::DocBook5->new(
{ novalid => $opts{novalid}, showfuzzy => $opts{showfuzzy} } );
}
else {
$builder = Publican::Builder::DocBook4->new(
{ novalid => $opts{novalid}, showfuzzy => $opts{showfuzzy} } );
}
$builder->build(
{ formats => $opts{formats},
langs => $opts{langs},
publish => $opts{publish},
embedtoc => $opts{embedtoc},
distributed_set => $opts{distributed_set},
pdftool => $opts{pdftool},
pub_dir => $opts{pub_dir},
}
);
}
if ( $action eq 'add_revision' ) {
if ( $publican->param('type') eq 'brand' ) {
croak( maketext("add_revision does not work for brands.") );
}
$publican->add_revision(
{ lang => $opts{lang},
revnumber => $opts{revnumber},
date => $opts{date},
members => $opts{member},
email => $opts{email},
firstname => $opts{firstname},
surname => $opts{surname},
}
);
}
if ( $action eq 'package' ) {
my $builder = Publican::Builder::DocBook4->new();
if ( $publican->param('type') eq 'brand' ) {
$builder->package_brand( { binary => $opts{binary} } );
}
elsif ( $publican->param('web_home') || $publican->param('web_type') ) {
$builder->package_home( { binary => $opts{binary} } );
}
else {
$builder->package(
{ lang => $opts{lang},
desktop => $opts{desktop},
short_sighted => $opts{short_sighted},
binary => $opts{binary}
}
);
}
if ( $opts{brew} ) {
my @filelist = File::Find::Rule->file->name('*.src.rpm')
->in( $publican->param('tmp_dir') );
my $srpm = pop(@filelist);
my @brew_args = ( "brew", "build" );
push( @brew_args, "--scratch" ) if ( $opts{scratch} );
if ( $opts{'wait'} ) {
push( @brew_args, "--wait" );
}
else {
push( @brew_args, "--nowait" );
}
push( @brew_args, $publican->param('brew_dist') );
if ( -f "$srpm" ) {
my $result = system( @brew_args, "$srpm" );
if ($result) {
croak( maketext("Brew died, error $result: '$!'") );
}
}
else {
croak( maketext("Can't locate srpm, packaging aborted") );
}
}
}
if ( $action eq 'install_book' ) {
my $site_config = $opts{site_config} || undef;
my $ws = Publican::WebSite->new( { site_config => $site_config } );
if ( $publican->param('web_home') || $publican->param('web_type') ) {
croak( maketext("can't find 'publish' directory") )
unless ( -d "$opts{pub_dir}/home" );
rcopy( "$opts{pub_dir}/home/*", $ws->toc_path() . "/." );
}
else {
my $lang = $opts{lang}
|| croak( maketext( "[_1] is a required argument", 'lang' ) );
my $product = $publican->param('product');
my $version = $publican->param('version');
my $name = $publican->param('docname');
my $product_label = $publican->param('web_product_label');
my $version_label = $publican->param('web_version_label');
my $name_label = $publican->param('web_name_label');
my $sort_order = $publican->param('sort_order');
my $builder;
if ( $opts{dtdver} && $opts{dtdver} =~ /^5/ ) {
$builder = Publican::Builder::DocBook5->new();
}
else {
$builder = Publican::Builder::DocBook4->new();
}
my $subtitle = $builder->get_subtitle( { lang => $lang } );
my $abstract = $builder->get_abstract( { lang => $lang } );
croak(
maketext(
"can't find publish directory '[_1]/[_2]'", $opts{pub_dir},
$lang
)
) unless ( -d "$opts{pub_dir}/$lang" );
my $type = $publican->param('type');
my $xml_lang = $publican->param('xml_lang');
my $tmp_dir = $publican->param('tmp_dir');
# get translated labels
## BUGBUG this is copied from Publican.pm, maybe a sub for these?
if ( $lang ne $xml_lang ) {
my $xml_file = "$tmp_dir/$lang/xml/$type" . '_Info.xml';
$xml_file = "$tmp_dir/$lang/xml/" . $publican->param('info_file')
if ( $publican->param('info_file') );
croak( maketext( "Can't locate required file: [_1]", $xml_file ) )
if ( !-f $xml_file );
my $xml_doc = XML::TreeBuilder->new();
$xml_doc->parse_file($xml_file);
# BUGBUG can't translate overridden labels :(
unless ($product_label) {
$product_label = eval {
$xml_doc->root()->look_down( "_tag", "productname" )
->as_text();
};
if ($@) {
# croak maketext("productname not found in Info file");
}
else {
$product_label =~ s/\s/_/g;
$product_label = undef if ( $product_label eq $product );
}
}
unless ($name_label) {
$name_label = eval {
$xml_doc->root()->look_down( "_tag", "title" )->as_text();
};
if ($@) {
# croak maketext("title not found in Info file");
}
else {
$name_label =~ s/\s/_/g;
$name_label = undef if ( $name_label eq $name );
}
}
}
mkpath( $ws->toc_path() . "/$lang" )
unless ( -d $ws->toc_path() . "/$lang" );
rcopy( "$opts{pub_dir}/$lang/*", $ws->toc_path() . "/$lang/." );
my @formats;
foreach my $format (glob("publish/$lang/$product/$version/*")) {
$format =~ s{publish/$lang/$product/$version/}{}g;
push(@formats, $format);
}
$ws->update_or_add_entry(
{ language => $lang,
product => $product,
version => $version,
name => $name,
formats => join(',',@formats),
product_label => $product_label,
version_label => $version_label,
name_label => $name_label,
subtitle => $subtitle,
abstract => $abstract,
sort_order => $sort_order,
}
);
}
$ws->regen_all_toc();
}
if ( $action eq 'remove_book' ) {
my $site_config = $opts{site_config} || undef;
my $ws = Publican::WebSite->new( { site_config => $site_config } );
my $lang = $opts{lang}
|| croak( maketext( "[_1] is a required argument", 'lang' ) );
my $product = $publican->param('product');
my $version = $publican->param('version');
my $name = $publican->param('docname');
$ws->del_entry(
{ language => $lang,
product => $product,
version => $version,
name => $name,
}
);
# Since every format uses the name, this finds all the formats even if they aren't in the DB.
foreach my $fdir (File::Find::Rule->name($name)->in("$ws->{toc_path}/$lang/$product/$version")) {
rmtree($fdir);
my $format = $fdir;
$format =~ s{$ws->{toc_path}/$lang/$product/$version/}{};
$format =~ s{/$name}{};
next if($format eq "");
# if we delete the last of this format, then delete the format dir.
# BUGBUG might need to check for non-template created files? e.g. index.html
my $dir = "$ws->{toc_path}/$lang/$product/$version/$format";
unless ( File::Find::Rule->not_name(qr/(\.|\.\.)/)->in($dir) ) {
rmtree($dir);
$dir = "$ws->{toc_path}/$lang/$product/$version";
# if we delete the last format for this vrerison., delete the version dir.
unless ( File::Find::Rule->not_name(qr/(\.|\.\.)/)->in($dir) ) {
rmtree($dir);
$dir = "$ws->{toc_path}/$lang/$product";
# if we delete the last version for this product, delete the product dir.
unless ( File::Find::Rule->not_name(qr/(\.|\.\.)/)->in($dir) )
{
rmtree($dir);
}
}
}
}
# Have to regenerate all languages as translations have untranslated and source newer tags.
$ws->regen_all_toc();
}
if ( $action eq 'rename' ) {
my $conf_file = ( $opts{config} || 'publican.cfg' );
my $config = new Config::Simple($conf_file);
$config->syntax('http');
# load in $type_Info.xml
my $file
= $config->param('xml_lang') . '/'
. ( $config->param('type') || 'Book' )
. '_Info.xml';
$file = $config->param('xml_lang') . "/" . $config->param('info_file')
if ( $config->param('info_file') );
my $cleaner = Publican::XmlClean->new( { clean_id => 1 } );
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
$xml_doc->store_comments(1);
$xml_doc->parse_file($file)
|| croak( maketext( "Can't open file '[_1]' [_2]", $file, $@ ) );
if ( $opts{name} ) {
# set mainfile in publican.cfg if it's not set
unless ( $config->param('mainfile') ) {
$config->param( 'mainfile',
$publican->{config}->param('docname') );
}
# delete docname
$config->delete('docname');
# Change Title
my $title = $xml_doc->root()->look_down( "_tag", "title" )
|| croak( maketext('Cannot locate title tag in Info file!') );
$title->delete_content();
$title->push_content( $opts{name} );
}
# Change Product Name
if ( $opts{product} ) {
my $prod = $xml_doc->root()->look_down( "_tag", "productname" )
|| croak(
maketext('Cannot locate productname tag in Info file!') );
$prod->delete_content();
$prod->push_content( $opts{product} );
}
# Change Product Number
if ( $opts{version} ) {
my $prod_num = $xml_doc->root()->look_down( "_tag", "productnumber" )
|| croak(
maketext('Cannot locate productnumber tag in Info file!') );
$prod_num->delete_content();
$prod_num->push_content( $opts{version} );
}
# write out new files
$config->write($conf_file);
$cleaner->print_xml( { xml_doc => $xml_doc, out_file => $file } );
# clean up memory
$xml_doc->root()->delete();
}
if ( $action eq 'report' ) {
my $dtdver = $publican->param('dtdver');
my $builder;
my $lang = $publican->param('xml_lang');
my $tmp_dir = $publican->param('tmp_dir');
my $docname = $publican->param('docname');
if ( $dtdver =~ m/^5/ ) {
$builder = Publican::Builder::DocBook5->new(
{ novalid => $opts{novalid} } );
}
else {
$builder = Publican::Builder::DocBook4->new(
{ novalid => $opts{novalid} } );
}
$builder->build(
{ formats => 'txt',
langs => $publican->param('xml_lang'),
pub_dir => $opts{pub_dir},
}
);
my $file = "$tmp_dir/$lang/txt/$docname.txt";
my $text = new Lingua::EN::Fathom;
$text->analyse_file($file);
print( $text->report );
}
if ( $action eq 'zt_pull' ) {
my @zanata_cmd
= qw(zanata-cli pull --src-dir pot --trans-dir . --include-fuzzy --locales);
push( @zanata_cmd, get_all_langs(1) );
my $result = system(@zanata_cmd);
if ($result) {
croak(
maketext( "Zanata call failed, error [_1]: '[2]'", $result, $! )
);
}
}
if ( $action eq 'zt_push' ) {
my @zanata_cmd
= qw(zanata-cli push --src-dir pot --trans-dir . --push-type both --copy-trans 0 --locales );
push( @zanata_cmd, get_all_langs(1) );
my $result = system(@zanata_cmd);
if ($result) {
croak(
maketext( "Zanata call failed, error [_1]: '[2]'", $result, $! )
);
}
}
exit(0);
# Secret action to create bash completion file.
# Nothing special just don't want to confuse people by discussing
# it in the general help
sub _bash_completion {
my $actions = join( " ", sort( keys(%actions) ) );
my $util_opts = "";
foreach my $opto ( sort(@utility_opts) ) {
$opto =~ s/=.*$//g;
$util_opts .= "--$opto ";
}
my $top = <", "completion/_publican" )
|| croak("file open fail: @_");
print( $COMP_FILE $top );
print( $COMP_FILE $options );
print( $COMP_FILE $bottom );
close($COMP_FILE);
return;
}
db5-valid 000555 041472 041472 3026 12555605450 16345 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/bin #!/usr/bin/perl
use utf8;
use strict;
use warnings;
use 5.008;
use Carp;
use XML::LibXSLT;
use XML::LibXML;
use Getopt::Long;
use Pod::Usage;
my $man = 0; # display man page
my $help = 0; # display help
my $file = undef;
my $version = '5.0';
GetOptions(
'help|?' => \$help,
'man' => \$man,
'file=s' => \$file,
'version=s' => \$version,
) || pod2usage( -verbose => 0 );
pod2usage( -verbose => 1 ) if ($help);
pod2usage( -verbose => 2 ) if ($man);
pod2usage( { -message => "file is a mandatory parameter", -exitvalue => 1 } )
unless ($file);
my $parser;
$parser = XML::LibXML->new(
{ pedantic_parser => 1,
suppress_errors => 0,
suppress_warnings => 1,
line_numbers => 1,
expand_xinclude => 1
}
);
my $source;
eval { $source = $parser->parse_file("$file"); };
my $rngschema = XML::LibXML::RelaxNG->new(
location => "http://docbook.org/xml/$version/rng/docbook.rng" );
eval { $rngschema->validate($source); };
if ($@) {
print("RelaxNG Validation failed: ");
croak($@);
}
print("RelaxNG Validation OK\n");
exit;
__END__
=head1 NAME
db5-valid - a tool to run RelaxNG validation for DocBook 5 sources.
=head1 SYNOPSIS
db5-valid [options]
=head1 OPTIONS
=over 4
=item B<--help>
Print a brief help message and exits.
=item B<--man>
Prints the manual page and exits.
=item B<--file=>
The DocBook 5 master file.
=item B<--version=>
The DocBook version to validate against. Deafults to B<5.0>.
=back
=cut
db4-2-db5 000555 041472 041472 3422 12555605450 16056 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/bin #!/usr/bin/perl -CDAS
use strict;
use warnings;
use Publican;
use XML::LibXML;
use XML::LibXSLT;
use Carp;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
my $publican = Publican->new();
my $common_config = $publican->param('common_config');
my $xsl_file = $common_config . "/xsl/db4-upgrade.xsl";
# required for Windows
$xsl_file =~ s/"//g;
my $parser = XML::LibXML->new(
{ pedantic_parser => 0,
suppress_errors => 0,
suppress_warnings => 0,
line_numbers => 1,
expand_xinclude => 0,
expand_entities => 0,
recover_silently => 0,
}
);
my $xslt = XML::LibXSLT->new();
my @xml_files = dir_list( $publican->param('xml_lang'), '*.xml' );
foreach my $xml_file ( sort(@xml_files) ) {
print("Processing: $xml_file\n");
my $source;
eval { $source = $parser->parse_file("$xml_file"); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
carp(
maketext(
"FATAL ERROR: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
next;
}
else {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
}
my $style_doc = $parser->parse_file($xsl_file);
my $stylesheet = $xslt->parse_stylesheet($style_doc);
my $results = $stylesheet->transform($source);
my $outfile;
open( $outfile, ">:encoding(UTF-8)", "$xml_file" )
|| croak( maketext( "Can't open ad file: [_1]", $@ ) );
print( $outfile decode_utf8( $stylesheet->output_string($results) ) );
close($outfile);
}
lib 000755 041472 041472 0 12555605450 14510 5 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2 Publican.pm 000444 041472 041472 154071 12555605450 17010 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib package Publican;
use utf8;
use warnings;
use strict;
use Carp;
use Config::Simple '-strict';
use XML::TreeBuilder 5.4;
use I18N::LangTags::List;
use Term::ANSIColor qw(:constants uncolor);
use File::Find::Rule;
use XML::LibXSLT;
use XML::LibXML;
use Publican::Localise;
use Publican::ConfigData;
use Encode;
use Cwd qw(abs_path);
use Data::Dumper;
use File::Copy::Recursive;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
use Sort::Versions;
use version;
use vars
qw(@ISA $VERSION @EXPORT @EXPORT_OK $SINGLETON $LOCALISE $SPEC_VERSION %PARAMS);
$File::Copy::Recursive::KeepMode = 0;
$VERSION = version->declare('v4.3.2');
@ISA = qw(Exporter);
@EXPORT
= qw(dir_list debug_msg get_all_langs logger help_config maketext new_tree dtd_string rcopy dircopy fcopy rcopy_glob fmove dirmove params_as_docbook);
# Track when the SPEC file generation is incompatible.
$SPEC_VERSION = '4.1';
my $DEFAULT_CONFIG_FILE = 'publican.cfg';
my $DEBUG = undef;
my $NOCOLOURS = undef;
my $QUIET = undef;
my %PARAM_OLD = (
ARCH => 'arch',
BOOKS => 'books',
BRAND => 'brand',
BREW_DIST => 'brew_dist',
CHUNK_FIRST => 'chunk_first',
CHUNK_SECTION_DEPTH => 'chunk_section_depth',
CLASSPATH => 'classpath',
COMMON_CONFIG => '',
COMMON_CONTENT => '',
CONDITION => 'condition',
CONFIDENTIAL => 'confidential',
DEFAULT_LANGS => '',
DOCNAME => '',
DOC_TYPE => 'type',
DOC_URL => 'doc_url',
DTD_VER => 'dtdver',
DT_OBSOLETES => 'dt_obsoletes',
GENERATE_SECTION_TOC_LEVEL => 'generate_section_toc_level',
IGNORED_TRANSLATIONS => 'ignored_translations',
LICENSE => 'license',
OS_VER => 'os_ver',
PRODUCT => '',
PROD_URL => 'prod_url',
PROD_VERSION => '',
PROGNAME => '', # l10n
SET_REPO => 'repo',
SET_REPO_TYPE => 'scm',
SHOW_REMARKS => 'show_remarks',
SOURCE => '', # l10n
SRC_URL => 'src_url',
TRANSLATIONS => '',
TOC_SECTION_DEPTH => 'toc_section_depth',
WEB_BREW_DIST => 'web_brew_dist',
WEB_OBSOLETES => 'web_obsoletes',
XMLFILE => '',
XML_LANG => 'xml_lang',
);
# All the valid fields in the publican.cfg file
# constraint: a regex to validate the content
%PARAMS = (
arch => {
descr => maketext('Arch to filter output on.'),
},
audience => {
descr => maketext('audience to filter output on.'),
},
books => {
descr => maketext(
'A space-separated list of books used in this remote set.'),
},
banned_attrs => {
descr => maketext(
'A comma-separated list of XML attributes that are not permitted in the source.'
),
limit_to => 'brand',
},
banned_tags => {
descr => maketext(
'A comma-separated list of XML tags that are not permitted in the source.'
),
limit_to => 'brand',
},
base_brand => {
descr => maketext('The base brand to use for this brand.'),
default => 'common',
limit_to => 'brand',
},
brand => {
descr => maketext('The brand to use when building this package.'),
default => 'common',
},
brew_dist => {
descr => maketext(
'The brew dist to use for building the standalone desktop rpm.'),
default => 'docs-5E',
alert => maketext(
'This field is deprecated and will be removed from Publican in the future.'
),
},
bridgehead_in_toc => {
descr => maketext('Display bridge head elements in the TOCs?'),
default => 0,
},
chunk_first => {
descr => maketext(
'For HTML, should the first section be on the same page as its parent?'
),
default => 0,
},
chunk_section_depth => {
descr => maketext(
'For HTML, what is the deepest level of nesting at which a section should be split onto its own page?'
),
default => 4,
},
classpath => {
descr => maketext('Path to jar files for FOP.'),
default =>
'/usr/share/java/ant/ant-trax-1.7.0.jar:/usr/share/java/xmlgraphics-commons.jar:/usr/share/java/batik-all.jar:/usr/share/java/xml-commons-apis.jar:/usr/share/java/xml-commons-apis-ext.jar',
},
common_config => {
descr => maketext('Path to publican content.'),
default => Publican::ConfigData->config('datadir'),
},
common_content => {
descr => maketext('Path to publican common content.'),
default => Publican::ConfigData->config('datadir')
. '/Common_Content',
},
condition => {
descr => maketext(
'Conditions on which to prune XML before transformation.'),
},
confidential => {
descr => maketext('Is the content confidential?'),
default => 0,
},
confidential_text => {
descr =>
maketext('The text used to indicate content is confidential.'),
default => maketext('CONFIDENTIAL'),
},
conformance => {
descr => maketext('conformance to filter output on.'),
},
debug => {
descr => maketext('Print out extra messages?'),
default => 0,
},
docname => {
descr => maketext(
'Name of this document. Fetched from title tag in xml_lang/TYPE_Info.xml if not set in cfg file.'
),
constraint => '^[0-9a-zA-Z_\-\.\+]+$',
not_for => 'brand',
},
doc_url => {
descr => maketext(
'URL for the documentation team for this package. Used for top right URL on HTML.'
),
default => 'https://fedorahosted.org/publican',
},
dtd_type => {
descr =>
maketext('Override Type for DocType. Must be a complete string.'),
limit_to => 'brand',
},
dtd_uri => {
descr =>
maketext('Override URI for DocType. Must be a complete string.'),
limit_to => 'brand',
},
## BUGBUG this should be ripped from file header
dtdver => {
descr => maketext(
'Version of the DocBook DTD on which this project is based.'),
default => '4.5',
},
dt_format => {
descr => maketext('The format to use for the desktop output.'),
default => 'html-desktop',
},
dt_obsoletes => {
descr => maketext(
'Space-separated list of packages the desktop RPM obsoletes.'
),
},
dt_requires => {
descr => maketext(
'Space-separated list of packages the desktop RPM requires.'),
},
'ec_id' => {
descr =>
maketext('Eclipse plugin ID. Defaults to "$product.$docname"'),
},
'ec_name' => {
descr =>
maketext('Eclipse plugin name. Defaults to "$product $docname"'),
},
'ec_provider' => {
descr => maketext(
'Eclipse plugin provider. Defaults to "Publican-[_1]"', $VERSION
),
},
extras_dir => {
descr => maketext('Directory where images are located.'),
default => 'extras',
},
generate_section_toc_level => {
descr => maketext(
'Generate table of contents down to the given section depth.'),
default => 0,
},
ignored_translations => {
descr => maketext(
'Languages to replace with xml_lang regardless of translation status.'
),
},
img_dir => {
descr => maketext('Directory where images are located.'),
default => 'images',
},
info_file => { descr => maketext('Override the default Info file.'), },
lang => {
descr => maketext('lang to filter output on.'),
},
license => {
descr => maketext('License this package uses.'),
default => 'GFDL',
},
mainfile => {
descr => maketext(
'The name of the main xml and ent files for this book, sans file extension and language. Fetched from docname if not set.'
),
},
menu_category => {
descr => maketext(
'Semicolon-separated list of menu categories for the desktop package.'
),
},
no_embedtoc => {
descr => maketext(
'Brand option to disable embedding the navigational toc in web packages'
),
limit_to => 'brand',
},
os => {
descr => maketext('os to filter output on.'),
},
os_ver => { descr => maketext('The OS for which to build packages.'), },
pdf_body_font => {
descr => maketext('The font to use for body text in PDFs.'),
default => 'Liberation Sans',
},
pdf_mono_font => {
descr => maketext('The font to use for mono text in PDFs.'),
default => 'Liberation Mono',
},
product => {
descr => maketext(
'Product this package covers. Fetched from productname tag in xml_lang/TYPE_Info.xml'
),
constraint => '^[0-9a-zA-Z_\-\.\+]+$',
not_for => 'brand',
},
prod_url => {
descr =>
maketext('URL for the product. Used in top left URL in HTML.'),
default => 'https://fedorahosted.org/publican',
},
repo => {
descr => maketext('Repository from which to fetch remote set books.'),
},
scm => {
descr => maketext(
'Type of repository in which books that form part of a remote set are stored. Supported types: SVN, GIT.'
),
},
rev_dir => {
descr => maketext(
q|By default Revision History is sorted in descending order. Set this to 'asc' or 'ascending' to reverse the sort.|
),
},
rev_file =>
{ descr => maketext('Override the default Revision History file.'), },
revision => {
descr => maketext('revision to filter output on.'),
},
revisionflag => {
descr => maketext('revisionflag to filter output on.'),
},
role => {
descr => maketext('role to filter output on.'),
},
security => {
descr => maketext('security to filter output on.'),
},
show_remarks => {
descr => maketext('Display remarks in transformed output.'),
default => 0,
},
sort_order => {
descr =>
maketext('Override the default sort weighting. Defaults to 50.'),
},
src_url => {
descr => maketext(
'URL to find tar of source files. Used in RPM Spec files.'),
},
status => {
descr => maketext('status to filter output on.'),
},
tmp_dir => {
descr => maketext('Directory to use for building.'),
default => 'tmp',
},
toc_section_depth => {
descr => maketext(
'Depth of sections to include in the main table of contents.'),
default => 2,
},
type => {
descr => maketext(
'Type of content this package contains. Supported: set, book, article, brand'
),
default => 'Book',
},
txt_formater => {
descr =>
maketext('Choose the formatter to use when creating txt output.'),
constraint => '^(links{1}|tables{1}|default)$',
default => 'default',
},
userlevel => {
descr => maketext('userlevel to filter output on.'),
},
vendor => {
descr => maketext('vendor to filter output on.'),
},
version => {
descr => maketext(
'Version of this package. Fetched from productnumber tag in xml_lang/TYPE_Info.xml'
),
constraint => '^[0-9][^\p{IsSpace}]*$',
},
web_brew_dist => {
descr => maketext('The brew dist to use for building the web rpm.'),
default => 'docs-5E',
},
web_formats => {
descr => maketext(
'A comma-separated list of the formats to use for the web packages.'
),
default => 'html,html-single,pdf,epub',
},
web_home => {
descr => maketext(
'This is a home page for a Publican-generated website, not a standard book.'
),
alert =>
'web_home is deprecated and will be removed from Publican in the future. Use "web_type: home" instead.',
},
web_type => {
descr => maketext(
'This is a special page for a Publican-generated website, not a standard book. Valid types are home, product, and version.'
),
constraint => '^(home|product|version)$',
},
web_host => {
descr => maketext(
'This is a host name for a Publican-generated website, used for searches and the Sitemap. Be sure to include the full path to your document tree. E.g. if your documents are in the docs directory: http://www.example.com/docs'
),
alert =>
'web_host is deprecated and will be removed from Publican in the future. Use "host" in the web site configuration file instead.',
},
web_obsoletes =>
{ descr => maketext('Packages to obsolete in web RPM.'), },
web_search => {
descr => maketext(
'Override the default search form for a Publican website. By default this will use Google search and do a site search if web_host is set.'
),
alert =>
'web_search is deprecated and will be removed from Publican in the future. Use "search" in the web site configuration file instead.',
},
web_name_label => {
descr => maketext(
'Override the book name, bottom level, menu label on a Publican website.'
),
},
web_product_label => {
descr => maketext(
'Override the product, top level, menu label on a Publican website.'
),
},
web_version_label => {
descr => maketext(
'Override the version, middle level, menu label on a Publican website. To hide this menu item set this to: UNUSED'
),
},
web_cfg => {
descr => maketext(
'Full path for the publican site configuration file for non standard RPM websites.'
),
limit_to => 'brand',
},
web_dir => {
descr => maketext('Install path for non standard RPM websites.'),
limit_to => 'brand',
},
web_req => {
descr => maketext(
'Name of site package for non standard RPM websites. Required to ensure the site is installed.'
),
limit_to => 'brand',
},
wkhtmltopdf_opts => {
descr => maketext(
'Extra options to pass to wkhtmltopdf. e.g. wkhtmltopdf_opts: "-O landscape -s A3"'
),
},
wordsize => {
descr => maketext('wordsize to filter output on.'),
},
xml_lang => {
descr => maketext('Language in which XML is authored.'),
default => 'en-US',
},
drupal_author => {
descr => maketext(
'The author name to be shown in drupal book page. It must be a valid drupal username.'
),
default => 'Publican',
},
drupal_menu_title => {
descr => maketext(
'Override the bookname that will be shown in the drupal menu.'),
},
drupal_menu_block => {
descr => maketext('The menu where we can find the book.'),
default => 'user-guide',
},
drupal_image_path => {
descr => maketext(
'The directory where the image should be stored in drupal server.'
),
default => '/sites/default/files/documentation/',
},
);
# Setup localisation ASAP
BEGIN {
if ( !$LOCALISE ) {
$LOCALISE = Publican::Localise->get_handle()
|| croak("Could not create a Publican::Localise object");
$LOCALISE->encoding("UTF-8");
$LOCALISE->textdomain("publican");
}
}
=head1 NAME
Publican - Used to control settings for sub modules.
=head1 VERSION
This document describes Publican version $VERSION
=head1 SYNOPSIS
use Publican;
my $publican = Publican->new({DEBUG => 1});
=head1 DESCRIPTION
Handles general configuration of all sub modules.
=head1 INTERFACE
=cut
# Module implementation here
=head2 _load_config
Private method for loading a config file
=cut
sub _load_config {
my ( $self, $args ) = @_;
my $configfile = ( delete( $args->{configfile} )
|| croak( maketext("configfile is a mandatory argument") ) );
my $common_config = delete( $args->{common_config} );
my $common_content = delete( $args->{common_content} );
my $brand_dir = delete( $args->{brand_dir} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
if ( not -f $configfile ) {
croak( maketext( "Config file not found: [_1].", $configfile ) );
}
my $real_config = new Config::Simple();
$real_config->syntax('http');
$real_config->read($configfile)
|| croak(
maketext( "Failed to load config file: [_1]", $configfile ) );
my %Config = $real_config->vars();
my $config = new Config::Simple();
$config->syntax('http');
foreach my $key ( keys(%Config) ) {
unless ( defined $PARAMS{$key} ) {
logger(
maketext(
"WARNING: Unknown config key [_1], ignoring.\n", $key
),
RED
);
next;
}
}
foreach my $key ( keys(%PARAMS) ) {
if ( defined $Config{$key}
&& defined $PARAMS{$key}->{limit_to}
&& (lc( ( $Config{'type'} || 'book' ) ) ne
lc( $PARAMS{$key}->{limit_to} ) )
)
{
logger(
maketext(
"WARNING: config key [_1] is not valid for this type of object, ignoring.\n",
$key
),
RED
);
next;
}
# Output alerts about a parameter
if ( defined $Config{$key} && defined $PARAMS{$key}->{alert} ) {
_alert( $PARAMS{$key}->{alert} . "\n" );
}
# skip any bogus or empty fields
my $tmp = $Config{$key};
if ( defined $tmp ) {
if ( ref $tmp eq "ARRAY" ) {
if ( $#{$tmp} >= 0 ) {
$config->param( $key,
decode_utf8( join( ',', @{ $Config{$key} } ) ) );
}
}
elsif ( $tmp ne "" ) {
$config->param( $key, decode_utf8($tmp) );
}
}
elsif ( defined $PARAMS{$key}->{default} ) {
$config->param( $key, $PARAMS{$key}->{default} );
}
}
$config->param( 'common_config', $common_config ) if $common_config;
$config->param( 'common_content', $common_content ) if $common_content;
$config->param( 'brand_dir',
decode_utf8( abs_path( encode_utf8($brand_dir) ) ) )
if $brand_dir;
$self->{configfile} = $configfile;
$self->{config} = $config;
my $type = $config->param('type');
my $xml_lang = $config->param('xml_lang');
my $brand = $config->param('brand');
# don't try and load version info for brand files
if ( $type ne 'brand' ) {
my $info_file = "$xml_lang/$type" . '_Info.xml';
$info_file = "$xml_lang/" . $config->param('info_file')
if ( $config->param('info_file') );
croak( maketext( "Can't locate required file: [_1]", $info_file ) )
if ( !-f $info_file );
## BUGBUG DocBook specific stuff should be moved to the DocBook sub classes
my $xml_doc = XML::TreeBuilder->new();
eval { $xml_doc->parse_file($info_file); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak(
maketext( "FATAL ERROR: [_1]: [_2]", $info_file, $@ ) );
}
}
my $docname = $config->param('docname');
eval {
$docname
= $xml_doc->root()->look_down( "_tag", "title" )->as_text();
}
unless defined($docname);
if ($@) {
croak maketext("title not found in Info file");
}
$docname =~ s/\s/_/g;
my $product = $config->param('product');
eval {
$product
= $xml_doc->root()->look_down( "_tag", "productname" )
->as_text();
}
unless defined($product);
if ($@) {
croak maketext("productname not found in Info file");
}
$product =~ s/\s/_/g;
my $version = $config->param('version');
eval {
$version
= $xml_doc->root()->look_down( "_tag", "productnumber" )
->as_text();
}
unless defined($version);
if ($@) {
croak maketext("productnumber not found in Info file");
}
my ( $edition, $release )
= $self->get_ed_rev( { lang => $xml_lang } );
if ( not defined( $self->{config}->param('mainfile') ) ) {
$self->{config}->param( 'mainfile', $docname );
}
$self->{config}->param( 'docname', $docname );
$self->{config}->param( 'product', $product );
$self->{config}->param( 'version', $version );
$self->{config}->param( 'release', $release );
$self->{config}->param( 'edition', $edition );
my $brand_path = $self->{config}->param('brand_dir')
|| $self->{config}->param('common_content') . "/$brand";
$brand_path =~ s/\"//g;
# Override publican defaults with brand defaults
if ( -f "$brand_path/defaults.cfg"
&& ( !-z "$brand_path/defaults.cfg" ) )
{
my $tmp_cfg = new Config::Simple("$brand_path/defaults.cfg")
|| croak(
maketext("Failed to load brand defaults.cfg file") );
my %Config = $tmp_cfg->vars();
foreach my $cfg ( keys(%Config) ) {
# If a book key is unset or equals the publican default, Override it
if ( ( !$self->{config}->param($cfg) )
or ( !defined( $PARAMS{$cfg}->{default} ) )
or ( $self->{config}->param($cfg) eq
$PARAMS{$cfg}->{default} )
)
{
$self->{config}->param( $cfg, $Config{$cfg} );
}
}
}
# Enforce Brand Overrides
if ( -f "$brand_path/overrides.cfg"
&& ( !-z "$brand_path/overrides.cfg" ) )
{
my $tmp_cfg = new Config::Simple("$brand_path/overrides.cfg")
|| croak(
maketext("Failed to load brand overrides.cfg file") );
my %Config = $tmp_cfg->vars();
foreach my $cfg ( keys(%Config) ) {
$config->param( $cfg, $Config{$cfg} );
}
}
# Brand Settings
my $brand_cfg = new Config::Simple("$brand_path/publican.cfg")
|| croak(
maketext(
"Failed to load brand file: [_1]",
"$brand_path/publican.cfg"
)
);
$self->{brand_config} = $brand_cfg;
$config->param( 'ec_name', "$product $docname" )
unless defined $config->param('ec_name');
$config->param( 'ec_id', "org.$product.$docname" )
unless defined $config->param('ec_id');
$config->param( 'ec_provider', "Publican-$VERSION" )
unless defined $config->param('ec_provider');
}
$DEBUG = $self->{config}->param('debug') if ( !$DEBUG );
return;
}
=head2 _validate_config
Private method for validating configuration
=cut
sub _validate_config {
my ( $self, $args ) = @_;
foreach my $key ( keys(%PARAMS) ) {
my $value = $self->{config}->param($key);
if (( defined( $PARAMS{$key}->{not_for} ) )
&& (lc( $PARAMS{$key}->{not_for} ) eq
lc( $self->{config}->param('type') ) )
)
{
if ( defined($value) ) {
croak(
maketext(
"Parameter [_1] is not permitted in a [_2].", $key,
$self->{config}->param('type')
)
);
}
else {
next;
}
}
if ( defined $PARAMS{$key}->{constraint} ) {
my $constraint = $PARAMS{$key}->{constraint};
if ( defined($value) && ( $value !~ /$constraint/ ) ) {
croak(
maketext(
"Invalid format for [_1]. Value ([_2]) does not conform to constraint ([_3])",
$key, $value, $constraint
)
);
}
}
}
return;
}
=head2 new
Create a Publican object.
my $publican = Publican->new({debug => 1});
=head3 Parameters:
configfile Override Configuration file to use.
debug Use debug mode for messages.
common_config Override path to coomo configuration files.
common_content Override path to common content files.
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $self;
if ($SINGLETON) {
$self = $SINGLETON;
}
else {
my $configfile
= ( delete( $args->{configfile} ) || $DEFAULT_CONFIG_FILE );
$DEBUG = ( delete( $args->{debug} ) || $DEBUG );
my $common_config = delete( $args->{common_config} );
my $common_content = delete( $args->{common_content} );
$QUIET = delete( $args->{QUIET} );
$NOCOLOURS = delete( $args->{NOCOLOURS} );
my $brand_dir = delete( $args->{brand_dir} );
my $allow_network = delete( $args->{allow_network} );
my $no_clean = delete( $args->{no_clean} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]",
join( ", ", keys %{$args} )
)
);
}
$self = bless {}, $class;
$SINGLETON = $self;
$self->{allow_network} = $allow_network;
$self->{no_clean} = $no_clean;
# BUGBUG this should be replaced by Publican::Config
if ( $^O eq 'MSWin32' ) {
eval { require Win32::TieRegistry; };
croak(
maketext(
"Failed to load Win32::TieRegistry module. Error: [_1]",
$@
)
) if ($@);
$ENV{ANSI_COLORS_DISABLED} = 1;
my $key = new Win32::TieRegistry( "LMachine\\Software\\Publican",
{ Delimiter => "\\" } );
if ( $key and $key->GetValue("") ) {
if ( !$common_config ) {
$common_config = $key->GetValue("");
$common_config =~ s/\\/\//g;
}
$common_content = "$common_config/Common_Content"
if ( !$common_content );
}
$common_config = qq{"$common_config"} if ($common_config);
$common_content = qq{"$common_content"} if ($common_content);
}
elsif ( $^O eq 'darwin' ) {
if ( !$common_config ) {
$common_config = '/opt/local/share/publican';
}
if ( !$common_content ) {
$common_content = "$common_config/Common_Content";
}
}
$self->_load_config(
{ configfile => $configfile,
common_config => $common_config,
common_content => $common_content,
brand_dir => $brand_dir,
}
);
debug_msg( maketext("config loaded") . "\n" );
$self->_validate_config();
}
return $self;
}
=head2 debug_msg
Print out debugging information.
=cut
sub debug_msg {
my ($arg) = @_;
my ( $caller, $func, $line, @rest ) = caller(1); # caller(0) eg
# Complete, caller(1)
# eg readline
# bail ASAP if not debugging
if ( !$DEBUG ) {
return;
}
($caller) = caller(0);
# $caller =~ s/.*:://;
$arg = "" unless defined $arg;
$func = "" unless defined $func;
$line = "" unless defined $line;
my $rest = join "|", map { defined $_ ? $_ : "UNDEF" } @rest;
logger( "\nDEBUG: ", RED );
if ( 0 and $arg and ref $arg ) {
eval { require Data::Dumper };
if ($@) {
logger( $arg->as_string, RED );
}
else {
logger( Data::Dumper::Dumper($arg), RED );
}
}
else {
## logger( "$caller: $func, $line\n\t$arg\n", RED );
logger( "$caller: $arg", RED );
}
return;
}
sub _alert {
my ($msg) = @_;
logger( $msg, RED );
return;
}
=head2 param
Return the current value of a configuration parameter
$publican->param('debug');
=cut
sub param {
my ( $self, $name ) = @_;
return $self->{config}->param($name)
if defined( $self->{config}->param($name) );
return $PARAMS{$name}->{default} if defined $PARAMS{$name}->{default};
return;
}
=head2 help_config
Display a list of config file parameters and a short description of them.
=cut
sub help_config {
my ( $self, $name ) = @_;
logger( maketext("Parameters used in the config file:") . "\n" );
foreach my $param ( sort( keys(%PARAMS) ) ) {
logger( "\t$param:\n\t\t" . $PARAMS{$param}->{descr} . "\n" );
logger( "\t\t"
. maketext( "Default: [_1]", $PARAMS{$param}->{default} )
. "\n" )
if ( defined( $PARAMS{$param}->{default} ) );
logger( "\t\t"
. maketext( "Constraint: [_1]",
$PARAMS{$param}->{constraint} )
. "\n" )
if ( defined( $PARAMS{$param}->{constraint} ) );
logger("\n");
}
return;
}
=head2 dir_list
list all the files in a directory, and its sub-directories, matching the supplied regex.
=cut
sub dir_list {
my ( $dir, $regex, $clean_images ) = @_;
croak( maketext("dir is a required argument") ) unless ($dir);
unless ( -d $dir ) {
logger( maketext( "skipping non existent directory: [_1]", $dir ) );
return;
}
croak( maketext("regex is a required argument") )
if ( !$regex || $regex eq "" );
my @filelist;
my $rule = File::Find::Rule->new;
if ( $regex =~ m/[|()]/ ) {
$rule->file->name(qr/$regex/);
}
else {
$rule->file->name($regex);
}
$rule->start($dir);
my $extras = $SINGLETON->param('extras_dir');
my $images = $SINGLETON->param('img_dir');
while ( my $file = $rule->match ) {
utf8::decode($file); ## BUGBUG blowing up Archive::Tar.
push( @filelist, $file )
unless ( $clean_images
and $file =~ m{(/$extras/|/icons/|$images/icon.svg)} );
}
return @filelist;
}
=head2 get_all_langs
Get all valid language directories.
=cut
sub get_all_langs {
my $no_src_lang = shift;
my ( $handle, %filelist, @langs );
my $tmp_dir = $SINGLETON->param('tmp_dir');
my $xml_lang = $SINGLETON->param('xml_lang');
opendir( $handle, '.' )
|| croak( maketext( "Can't open directory: [_1]", $@ ) );
my @dirs = sort( readdir($handle) );
closedir($handle);
foreach my $dir (@dirs) {
if ( -d $dir ) {
next
if ( $dir
=~ /^(\.|\.\.|pot|$tmp_dir|xsl|\..*|CVS|publish|book_templates|trans_drop|rpm_templates)$/
);
if ( valid_lang($dir) ) {
push( @langs, $dir )
unless ( $no_src_lang && ( $dir eq $xml_lang ) );
}
else {
logger( maketext( "Skipping unknown language: [_1]", $dir )
. "\n" );
}
}
}
return ( join( ',', @langs ) );
}
=head2 logger
Log something, currently emits to STDOUT
TODO: consider using Log::Dispatch or similar
=cut
sub logger {
my ( $msg, $colour ) = @_;
return if ($QUIET);
if ( $colour && !$NOCOLOURS ) {
print( STDOUT $colour, $msg, RESET );
}
else {
print( STDOUT $msg );
}
return;
}
=head2 valid_lang
Is the requested language valid according to I18N::LangTags::List
=cut
sub valid_lang {
my $lang = shift;
my $name = ( I18N::LangTags::List::name($lang) || '' );
return ( I18N::LangTags::List::is_decent($lang) && ( $name ne '' ) );
}
=head2 maketext
Get localised strings
=cut
sub maketext {
my $string = shift();
my @params = @_;
if ($LOCALISE) {
return ( decode_utf8( $LOCALISE->maketext( $string, @params ) ) );
}
else {
carp( RED, "Warning localisation not enabled!\n", RESET );
}
return ($string);
}
=head2 run_xslt
Apply the supplied xslt file to the supplied XML and return a string of the output.
=cut
sub run_xslt {
my ( $self, $args ) = @_;
my $xml_file = delete( $args->{xml_file} )
|| croak( maketext("xml_file is a mandatory argument") );
my $xsl_file = delete( $args->{xsl_file} )
|| croak( maketext("xsl_file is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $parser = XML::LibXML->new(no_network => !$self->{allow_network});
my $xslt = XML::LibXSLT->new();
$parser->expand_entities(1);
my $source;
eval { $source = $parser->parse_file($xml_file); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak( maketext( "FATAL ERROR: [_1]: [_2]", $xml_file, $@ ) );
}
}
my $style_doc;
eval { $style_doc = $parser->parse_file($xsl_file); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak( maketext( "FATAL ERROR: [_1]: [_2]", $xsl_file, $@ ) );
}
}
if ( $^O eq 'MSWin32' ) {
eval { require Win32::TieRegistry; };
croak(
maketext(
"Failed to load Win32::TieRegistry module. Error: [_1]", $@
)
) if ($@);
my $defualt_href
= 'http://docbook.sourceforge.net/release/xsl/current';
my $key = new Win32::TieRegistry( "LMachine\\Software\\Publican",
{ Delimiter => "\\" } );
my $new_href = 'file:///D:/Data/temp/Publican/docbook-xsl-1.75.2';
if ( $key and $key->GetValue("xsl_path") ) {
$new_href = 'file:///' . $key->GetValue("xsl_path");
$new_href =~ s/ /%20/g;
$new_href =~ s/\\/\//g;
}
my @nodelist = $style_doc->getElementsByTagName('xsl:import');
foreach my $node (@nodelist) {
my $href = $node->getAttribute('href');
debug_msg("changing $defualt_href to $new_href\n");
$href =~ s|$defualt_href|$new_href|;
$node->setAttribute( 'href', $href );
}
}
my $stylesheet = $xslt->parse_stylesheet($style_doc);
my $results = $stylesheet->transform($source);
my $value;
eval { $value = $stylesheet->output_string($results) };
return ($value);
}
=head2 new_tree
Create a new XML::TreeBuilder object with the required attributes for DocBook.
TODO: Make XmlClean use this.
=cut
sub new_tree {
my $store_comments = ( shift() || 0 );
my $noexpand = shift();
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => !$noexpand, 'ErrorContext' => "2" } );
$xml_doc->store_pis(1);
$xml_doc->store_cdata(1);
my $empty_element_map = $xml_doc->_empty_element_map;
$empty_element_map->{'xref'} = 1;
$empty_element_map->{'index'} = 1;
$empty_element_map->{'imagedata'} = 1;
$empty_element_map->{'area'} = 1;
$empty_element_map->{'ulink'} = 1;
$empty_element_map->{'xi:include'} = 1;
$xml_doc->store_comments(1) if ($store_comments);
return ($xml_doc);
}
=head2 dtd_string
Returns a valid DTD for the DocBook tag supplied.
Parameters:
tag The root tag for this file
dtdver The DTD version
ent_file An entity file to include (optional)
## BUGBUG this should be moved to the DocBook sub classes
=cut
sub dtd_string {
my ($args) = @_;
my $tag = delete( $args->{tag} )
|| croak( maketext("tag is a mandatory argument") );
my $dtdver = delete( $args->{dtdver} )
|| croak( maketext("dtdver is a mandatory argument") );
my $ent_file = delete( $args->{ent_file} );
my $cleaning = delete( $args->{cleaning} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $uri = qq|http://www.oasis-open.org/docbook/xml/$dtdver/docbookx.dtd|;
my $dtd_type = qq|-//OASIS//DTD DocBook XML V$dtdver//EN|;
# TODO Maynot be necessary
if ( $^O eq 'MSWin32' ) {
eval { require Win32::TieRegistry; };
croak(
maketext(
"Failed to load Win32::TieRegistry module. Error: [_1]", $@
)
) if ($@);
my $key = new Win32::TieRegistry( "LMachine\\Software\\Publican",
{ Delimiter => "\\" } );
$uri = 'file:///C:/publican/DTD/docbookx.dtd';
if ( $key and $key->GetValue("dtd_path") ) {
$uri = 'file:///' . $key->GetValue("dtd_path") . '/docbookx.dtd';
}
$uri =~ s/ /%20/g;
$uri =~ s/\\/\//g;
}
$dtd_type = $SINGLETON->param('dtd_type')
if ( $SINGLETON && $SINGLETON->param('dtd_type') );
$uri = $SINGLETON->param('dtd_uri')
if ( $SINGLETON && $SINGLETON->param('dtd_uri') );
my $dtd = <
%DOCBOOK_ENTS;
DTDHEAD
}
# handle entity file
if ($ent_file) {
$dtd .= <
%BOOK_ENTITIES;
ENT
}
if ( $before == 0 && $dtdver =~ m/^5/ ) {
# make sure docbook4 entities still work
$dtd .= <
%DOCBOOK_ENTS;
DTDHEAD
}
$dtd .= <
DTDTAIL
return ($dtd);
}
=head2 print_banned_tags
Print a list of tags that are not supported.
=cut
sub print_banned_tags {
my $self = shift();
print "\n"
. maketext(
"NOTE: These lists of tags and attributes are brand specific and are not part of Publican itself."
) . "\n\n";
print "\n" . maketext("Banned tags:") . "\n";
foreach my $key (
sort( split( /,/, ( $self->param('banned_tags') || "" ) ) ) )
{
print("\t$key\n");
}
print "\n" . maketext("Banned attributes:") . "\n";
foreach my $attr (
sort( split( /,/, ( $self->param('banned_attrs') || "" ) ) ) )
{
print("\t$attr\n");
}
print "\n";
return;
}
=head2 add_revision
Add a full entry in to the revision history.
## BUGBUG this should be moved to the DocBook sub classes
=cut
sub add_revision {
my ( $self, $args ) = @_;
my $members = delete( $args->{members} )
|| croak(
maketext( "[_1] is a required option for add_revision", 'members' ) );
my $revnumber = delete( $args->{revnumber} );
my $date = delete( $args->{date} );
my $firstname = delete( $args->{firstname} )
|| croak(
maketext( "[_1] is a required option for add_revision", 'firstname' )
);
my $surname = delete( $args->{surname} )
|| croak(
maketext( "[_1] is a required option for add_revision", 'surname' ) );
my $email = delete( $args->{email} )
|| croak(
maketext( "[_1] is a required option for add_revision", 'email' ) );
my $lang = delete( $args->{lang} )
|| croak(
maketext( "[_1] is a required option for add_revision", 'lang' ) );
unless ($revnumber) {
my ( $edition, $release )
= $self->get_ed_rev( { lang => $lang, bump => 1 } );
$revnumber = "$edition-$release";
}
unless ($date) {
$date = DateTime->now()->strftime("%a %b %e %Y");
}
my $lc_lang = $lang;
$lc_lang =~ s/-/_/g;
my $locale = Publican::Localise->get_handle($lc_lang)
|| croak(
"Could not create a Publican::Localise object for language: [_1]",
$lang );
$locale->encoding("UTF-8");
$locale->textdomain("publican");
my $revision = XML::Element->new_from_lol(
[ 'revision',
[ 'revnumber', $revnumber ],
[ 'date', $date ],
[ 'author',
[ 'firstname', $firstname ],
[ 'surname', $surname ],
[ 'email', $email ],
],
[ 'revdescription', ['simplelist'], ],
],
);
my $list = $revision->root()->look_down( "_tag", 'simplelist' );
foreach my $member ( @{$members} ) {
my $mem = XML::TreeBuilder->new(
{ 'NoExpand' => "1",
'ErrorContext' => "2"
}
);
$mem->parse("$member");
$list->push_content($mem);
}
my $dtdver = $self->param('dtdver');
my $ent_file = undef;
my $main_file = $self->param('mainfile');
if ( -e "$lang/$main_file.ent" ) {
$ent_file = "$lang/$main_file.ent";
}
my $rev_file = "$lang/Revision_History.xml";
$rev_file = "$lang/" . $self->param('rev_file')
if ( $self->param('rev_file') );
my $node;
my $rev_doc = new_tree();
if ( -f $rev_file ) {
eval { $rev_doc->parse_file($rev_file); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak( maketext( "FATAL ERROR: [_1]: [_2]", $rev_file, $@ ) );
}
}
}
else {
$rev_doc->root()->tag('appendix');
my $rev_hist = XML::Element->new_from_lol(
[ 'title', decode_utf8( $locale->maketext('Revision History') ) ],
);
$rev_doc->root()->push_content($rev_hist);
$rev_hist
= XML::Element->new_from_lol( [ 'simpara', ['revhistory'], ], );
$rev_doc->root()->push_content($rev_hist);
}
eval { $node = $rev_doc->root()->look_down( "_tag", "revhistory" ); };
if ($@) {
croak( maketext( "revhistory not found in [_1]", $rev_file ) );
}
if ( $self->param('rev_dir') && $self->param('rev_dir') =~ /^asc/i ) {
$node->push_content($revision);
}
else {
$node->unshift_content($revision);
}
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", "$rev_file" )
|| croak( maketext( "Could not open [_1] for output!", $rev_file ) );
print( $OUTDOC dtd_string(
{ tag => 'appendix',
dtdver => $dtdver,
ent_file => $ent_file,
cleaning => 1
}
)
);
print( $OUTDOC $rev_doc->root()->as_XML() );
close($OUTDOC);
$rev_doc->root()->delete();
my $cleaner = Publican::XmlClean->new( { exclude_ent => 1 } );
$cleaner->process_file( { file => $rev_file, out_file => $rev_file } );
return;
}
=head2 get_ed_rev
Get the current edition (version) and release from the Revision History file.
Parameters: language, bump.
If bump is set the returned revision will increment before it's returned.
## BUGBUG this should be moved to the DocBook sub classes
=cut
sub get_ed_rev {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak( maketext("'lang' is a required option for get_ed_rev") );
my $bump = delete( $args->{bump} );
my $rev_file = "$lang/Revision_History.xml";
$rev_file = "$lang/" . $self->param('rev_file')
if ( $self->param('rev_file') );
croak( maketext( "Can't locate required file: [_1]", $rev_file ) )
if ( !-f $rev_file );
my $rev_doc = XML::TreeBuilder->new();
eval { $rev_doc->parse_file($rev_file); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak( maketext( "FATAL ERROR: [_1]: [_2]", $rev_file, $@ ) );
}
}
my @revs = map { $_->as_text() }
sort { versioncmp( $b->as_text(), $a->as_text() ) }
( $rev_doc->root()->look_down( "_tag", "revnumber" ) );
my $VR = shift(@revs);
croak(
maketext(
"FATAL ERROR: revnumber missing or empty, it must match the required format of '[_1]'",
'^([0-9.]*)-([0-9.]*)$/'
)
) if ( !$VR || $VR eq '' );
$VR =~ /^([0-9.]*)-([0-9.]*)$/ || croak(
maketext(
"FATAL ERROR: revnumber ([_1]) does not match the required format of '[_2]'",
$VR,
'^([0-9.]*)-([0-9.]*)$/'
)
);
my $edition = $1;
my $release = $2;
$release =~ s/(\d+)$/(1+$1)/e if ($bump);
return ( ( $edition, $release ) );
}
=head2 fcopy
UTF8 escape calls to File::Copy::Recursive
=cut
sub fcopy {
my ( $from, $to ) = @_;
File::Copy::Recursive::fcopy( encode_utf8($from), encode_utf8($to) )
|| croak(
maketext(
"Can not copy file [_1] to [_2] due to error: [_3]",
$from, $to, $@
)
);
return;
}
=head2 fmove
UTF8 escape calls to File::Copy::Recursive
=cut
sub fmove {
my ( $from, $to ) = @_;
File::Copy::Recursive::fmove( encode_utf8($from), encode_utf8($to) )
|| croak(
maketext(
"Can not move file [_1] to [_2] due to error: [_3]",
$from, $to, $@
)
);
return;
}
=head2 rcopy
UTF8 escape calls to File::Copy::Recursive
=cut
sub rcopy {
my ( $from, $to ) = @_;
File::Copy::Recursive::rcopy( encode_utf8($from), encode_utf8($to) )
|| croak(
maketext(
"Can not copy files [_1] to [_2] due to error: [_3]",
$from, $to, $@
)
);
return;
}
=head2 rcopy_glob
UTF8 escape calls to File::Copy::Recursive
=cut
sub rcopy_glob {
my ( $from, $to ) = @_;
my @files
= File::Copy::Recursive::rcopy_glob( encode_utf8($from),
encode_utf8($to) )
|| croak(
maketext(
"Can not copy files [_1] to [_2] due to error: [_3]",
$from, $to, $@
)
);
return (@files);
}
=head2 dircopy
UTF8 escape calls to File::Copy::Recursive
=cut
sub dircopy {
my ( $from, $to ) = @_;
File::Copy::Recursive::dircopy( encode_utf8($from), encode_utf8($to) )
|| croak(
maketext(
"Can not copy directory [_1] to [_2] due to error: [_3]",
$from, $to, $@
)
);
return;
}
=head2 dirmove
UTF8 escape calls to File::Copy::Recursive
=cut
sub dirmove {
my ( $from, $to ) = @_;
File::Copy::Recursive::dirmove( encode_utf8($from), encode_utf8($to) )
|| croak(
maketext(
"Can not move directory [_1] to [_2] due to error: [_3]",
$from, $to, $@
)
);
return;
}
=head2 params_as_docbook
Returns DocBook chunks describing all the configuration options. Used to generate autodocs.
=cut
sub params_as_docbook {
my ( $gen_list, $brand_list, $web_list ) = @_;
foreach my $key ( sort( keys(%PARAMS) ) ) {
my $entry = XML::Element->new_from_lol(
[ 'varlistentry', {id => $key},[ 'term', "$key" ] ] );
if ( defined( $PARAMS{$key}->{limit_to} )
&& $PARAMS{$key}->{limit_to} eq 'brand' )
{
$brand_list->push_content($entry);
}
elsif ( defined( $PARAMS{$key}->{limit_to} )
&& $PARAMS{$key}->{limit_to} eq 'site' )
{
$web_list->push_content($entry);
}
else {
$gen_list->push_content($entry);
}
my $item = XML::Element->new_from_lol(
[ 'listitem', [ 'para', $PARAMS{$key}->{descr} ] ] );
$entry->push_content($item);
if ( defined( $PARAMS{$key}->{default} ) ) {
my $def = XML::Element->new_from_lol(
[ 'para',
maketext(
"The default value for this parameter is: [_1]",
$PARAMS{$key}->{default}
)
]
);
$item->push_content($def);
}
if ( defined( $PARAMS{$key}->{constraint} ) ) {
my $constraint = XML::Element->new_from_lol(
[ 'para',
maketext(
"This parameter is constrained with the following regular expression: [_1]",
$PARAMS{$key}->{constraint}
)
]
);
$item->push_content($constraint);
}
if ( defined( $PARAMS{$key}->{not_for} ) ) {
my $info = XML::Element->new_from_lol(
[ 'tip',
[ 'para',
maketext(
"This field is not supported for: [_1].",
$PARAMS{$key}->{not_for}
)
]
]
);
$item->push_content($info);
}
if ( defined( $PARAMS{$key}->{alert} ) ) {
my $warn = XML::Element->new_from_lol(
[ 'warning', [ 'para', $PARAMS{$key}->{alert} ] ] );
$item->push_content($warn);
}
}
}
1; # Magic true value required at end of module
__END__
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=item C<< Config file not found: %s >>
publican can not find the named configuration file.
=item C<< Failed to load config file: %s >>
The named configuration file could not be loaded.
=item C<< Can't locate required file: %s >>
A file required for processing could not be found.
=item C<< title not found in Info file >>
The _Info.xml file does not contain a title tag.
=item C<< productname not found in Info file >>
The _Info.xml file does not contain a productname tag.
=item C<< productnumber not found in Info file >>
The _Info.xml file does not contain a productnumber tag.
=item C<< pubsnumber not found in Info file >>
The _Info.xml file does not contain a pubsnumber tag.
=item C<< Failed to load brand default config file >>
A detected defaults.cfg for the current brand could not be loaded.
=item C<< Failed to load brand overrides config file >>
A detected overrides.cfg for the current brand could not be loaded.
=item C<< Could not create a Publican::Localise object >>
Could not create a Publican::Localise object
=item C<< Can't open directory >>
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
version
Config::Simple
XML::TreeBuilder
I18N::LangTags::List
Term::ANSIColor
File::Find::Rule;
Publican::Localise;
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
Publican 000755 041472 041472 0 12555605450 16245 5 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib XmlClean.pm 000444 041472 041472 125103 12555605450 20505 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::XmlClean;
use strict;
use warnings;
use 5.008;
use Carp;
use XML::TreeBuilder 5.1;
use Config::Simple '-strict';
use Publican;
use File::Path;
use Term::ANSIColor qw(:constants);
use Publican::Builder;
use File::Inplace;
use DBI;
use Data::Dumper;
use File::Basename;
=head1 NAME
Publican::XmlClean - A module to reformat XML to Publican standards
=head1 SYNOPSIS
use Publican::XmlClean;
my $cleaner = Publican::XmlClean->new( { clean_id => 1 } );
foreach my $xml_file ( sort(@xml_files) ) {
$cleaner->process_file( { file => $xml_file, out_file => $xml_file } );
}
=head1 DESCRIPTION
Publican::XmlClean tidies XML formatting and filters structure based on input rules.
=head1 INTERFACE
=cut
my %UPDATED_IDS;
my %MAX_CONFORMANCE;
my %MAP_OUT = (
section => { block => 1, },
refsection => { block => 1, no_id => 1 },
chapter => { block => 1 },
preface => { block => 1 },
bibliography => { block => 1 },
bibliodiv => { block => 1 },
biblioentry => { block => 1 },
othercredit => { block => 1 },
legalnotice => { block => 1 },
address => { block => 1, verbatim => 1 },
book => { block => 1 },
article => { block => 1 },
part => { block => 1 },
partintro => { block => 1 },
para => { block => 1 },
formalpara => { block => 1 },
simpara => { block => 1 },
itemizedlist => { block => 1 },
orderedlist => { block => 1 },
variablelist => { block => 1 },
seglistitem => { block => 1 },
segtitle => { newline_after => 1 },
seg => { newline_after => 1 },
segmentedlist => { block => 1 },
simplelist => { block => 1 },
qandaset => { block => 1 },
qandaentry => { block => 1 },
question => { block => 1 },
answer => { block => 1 },
member => { newline_after => 1 },
remark => { newline_after => 1 },
userinput => {},
listitem => { block => 1, keep_id => 1 },
title => { newline_after => 1 },
refentrytitle => { newline_after => 1 },
refpurpose => { newline_after => 1 },
refname => { newline_after => 1 },
refnamediv => { block => 1, id_node => 'refname' },
manvolnum => { newline_after => 1 },
street => {},
city => {},
state => {},
postcode => {},
country => {},
phone => {},
fax => {},
pob => {},
subtitle => { newline_after => 1 },
screen => { block => 1, verbatim => 1 },
programlisting => { block => 1, verbatim => 1 },
programlistingco => { block => 1, newline_after => 1 },
xref => { force_empty => 1 },
footnoteref => { force_empty => 1 },
important => { block => 1, no_id => 1 },
note => { block => 1, no_id => 1 },
warning => { block => 1, no_id => 1 },
figure => { block => 1 },
mediaobject => { block => 1 },
imageobject => { block => 1 },
imagedata => {},
'xi:include' => { newline_after => 1 },
'xi:fallback' => { newline_after => 1 },
glossary => { block => 1 },
glossentry => { block => 1, id_node => 'glossterm' },
glossdiv => { block => 1 },
glossdef => { block => 1 },
glossterm => { newline_after => 1 },
glosssee => { newline_after => 1 },
glossseealso => { newline_after => 1 },
table => { block => 1 },
informaltable => { block => 1 },
thead => { block => 1 },
tgroup => { block => 1 },
tbody => { block => 1 },
tr => { block => 1 },
td => { block => 1 },
row => { block => 1 },
entry => { newline_after => 1 },
refentry => { block => 1 },
refmeta => { block => 1 },
refentryinfo => { block => 1, no_id => 1 },
reference => { block => 1 },
indexterm => { block => 1, mixed_mode => 1 },
primary => { newline_after => 1, mixed_mode => 1 },
secondary => { newline_after => 1, mixed_mode => 1 },
tertiary => { newline_after => 1, mixed_mode => 1 },
bookinfo => { block => 1 },
articleinfo => { block => 1 },
abstract => { block => 1 },
inlinemediaobject => { block => 1 },
publisher => { block => 1 },
copyright => { block => 1 },
authorgroup => { block => 1 },
author => { block => 1 },
editor => { block => 1 },
corpauthor => { block => 1 },
revision => { block => 1 },
revhistory => { block => 1 },
revdescription => { block => 1 },
publishername => { block => 1 },
affiliation => { block => 1 },
year => { newline_after => 1 },
holder => { newline_after => 1 },
revnumber => { newline_after => 1 },
date => { newline_after => 1 },
honorific => { newline_after => 1 },
firstname => { newline_after => 1 },
surname => { newline_after => 1 },
email => { newline_after => 1, mixed_mode => 1 },
isbn => { newline_after => 1 },
issuenum => { newline_after => 1 },
edition => { newline_after => 1 },
pubdate => { newline_after => 1 },
productname => { mixed_mode => 1, newline_after => 1 },
productnumber => { newline_after => 1 },
pubsnumber => { newline_after => 1 },
contrib => { newline_after => 1 },
shortaffil => { newline_after => 1 },
jobtitle => { newline_after => 1 },
orgname => { newline_after => 1 },
orgdiv => { newline_after => 1 },
citetitle => {},
trademark => {},
ulink => {},
firstterm => {},
menuchoice => {},
acronym => {},
abbrev => {},
command => {},
filename => {},
'index' => {},
application => {},
'package' => {},
guimenu => {},
sgmltag => {},
guilabel => {},
guibutton => {},
emphasis => {},
phrase => {},
replaceable => {},
computeroutput => {},
guimenuitem => {},
textobject => { block => 1 },
varlistentry => { block => 1, id_node => 'term' },
term => { newline_after => 1 },
colspec => { newline_after => 1 },
areaspec => { block => 1 },
areaset => { block => 1, keep_id => 1 },
area => { newline_after => 1, keep_id => 1 },
calloutlist => { block => 1 },
callout => { block => 1 },
procedure => { block => 1 },
appendix => { block => 1 },
appendixinfo => { block => 1 },
cmdsynopsis => { block => 1 },
arg => { block => 1 },
group => { block => 1 },
accel => {},
blockquote => { block => 1 },
classname => {},
code => {},
colophon => { block => 1 },
envar => {},
example => { block => 1 },
footnote => { keep_id => 1 },
guisubmenu => {},
interface => {},
keycap => {},
keycombo => {},
literal => {},
literallayout => { block => 1, verbatim => 1 },
option => {},
parameter => {},
prompt => {},
property => {},
see => { newline_after => 1, },
seealso => { newline_after => 1, },
step => { block => 1, keep_id => 1 },
substeps => { block => 1 },
stepalternatives => { block => 1 },
systemitem => {},
wordasword => {},
citerefentry => {},
manvolnum => {},
function => {},
uri => {},
mousebutton => {},
hardware => {},
type => {},
methodname => {},
exceptionname => {},
varname => {},
interfacename => {},
othername => { newline_after => 1 },
'~comment' => {},
foreignphrase => {},
chapterinfo => { block => 1 },
info => { block => 1 },
keywordset => { block => 1 },
keyword => { newline_after => 1 },
subjectset => { block => 1 },
subject => { block => 1 },
subjectterm => { newline_after => 1 },
superscript => {},
'~cdata' => { verbatim => 1 },
);
=head2 new
Create a new Publican::XmlClean object.
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $config = new Config::Simple();
$config->syntax('simple');
$config->param( 'lang', delete( $args->{lang} ) ) if ( $args->{lang} );
$config->param( 'update_includes', delete( $args->{update_includes} ) )
if ( $args->{update_includes} );
$config->param( 'clean_id', ( delete( $args->{clean_id} ) ) || 0 );
$config->param( 'unique_id', ( delete( $args->{unique_id} ) ) || 0 );
$config->param( 'donotset_lang',
( delete( $args->{donotset_lang} ) ) || 0 );
$config->param( 'distributed_set',
( delete( $args->{distributed_set} ) ) || 0 );
$config->param( 'exclude_ent', ( delete( $args->{exclude_ent} ) ) || 0 );
$config->param( 'cleaning',
( delete( $args->{cleaning} ) ) || $config->param('clean_id') );
$config->param( 'id_attr', ( delete( $args->{id_attr} ) ) || 'id' );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $self = bless {}, $class;
$self->{config} = $config;
my $publican = Publican->new();
$self->{publican} = $publican;
return $self;
}
=head2 print_known_tags
Print a list of tags that have had their output QA'd.
=cut
sub print_known_tags {
my $self = shift();
foreach my $key ( sort( keys(%MAP_OUT) ) ) {
print("$key\n");
}
return;
}
=head2 prune_xml($node)
Remove unwanted nodes. i.e. 'profile' in DocBook speak.
=cut
sub prune_xml {
my ( $self, $xml_doc ) = @_;
my $original_tag = $xml_doc->root()->{'_tag'};
my @prune_attrs
= qw/arch audience condition conformance lang os revision revisionflag role security status userlevel vendor wordsize/;
if ($xml_doc) {
foreach my $attr (@prune_attrs) {
my $cond = $self->{publican}->param($attr);
$cond = $self->{config}->param($attr)
if ( $attr eq 'lang' ); ## Always prune on language
if ($cond) {
$xml_doc->pos( $xml_doc->root() );
$cond =~ s/;/|/g;
my $regex = qr/(?:$cond)/;
while (
my $node = $xml_doc->look_down(
sub {
$_[0]->attr($attr)
&& $_[0]->attr($attr) !~ /^$regex$/
&& $_[0]->attr($attr) !~ /^$regex;/
&& $_[0]->attr($attr) !~ /;$regex$/
&& $_[0]->attr($attr) !~ /;$regex;/;
}
)
)
{
croak(
maketext(
"FATAL ERROR: profiling would prune root node. Do NOT set attributes to prune on in a root node. Offending attibute: [_1]",
$attr
)
) if ( $node->same_as( $xml_doc->root() ) );
$node->delete();
}
}
}
}
return;
}
=head2 Clean_ID
Rename ID's and update xrefs.
If this node has a title as a child set it's ID else remove the ID
=cut
sub Clean_ID {
my ( $self, $node ) = @_;
my $my_id = "";
my $docname = $self->{publican}->param('docname');
my $product = $self->{publican}->param('product');
if ($node) {
my $tag = $node->{'_tag'};
# keep_id means keep the current ID without modification.
if ( $MAP_OUT{$tag}->{keep_id} ) {
$my_id = $node->attr( $self->{config}->param('id_attr') ) || "";
}
elsif ( !$MAP_OUT{$tag}->{no_id} ) {
## TODO this doesn;t work when teh title is in an info. ...
foreach my $child ( $node->content_refs_list() ) {
if ( ref $$child
&& $$child->{'_tag'} eq
( $MAP_OUT{$tag}->{id_node} || 'title' ) )
{
$my_id = $$child->as_text;
$my_id =~ s/[- ]/_/g;
$my_id =~ s/[^a-zA-Z0-9\._]//g;
$my_id =~ s/_+/_/g;
# Must start with a letter!
if ( $my_id =~ /^\d/ ) {
$my_id = 'a' . $my_id;
}
if ( $node->parent() ) {
my $par_title = $node->parent()
->look_up( sub { $_[0]->attr('id'); } );
if ( $my_id ne "" && $par_title ) {
my $my_p_id = $par_title->attr('id');
$my_p_id =~ s/^.*-//;
$my_id = "$my_p_id-$my_id";
}
}
last;
}
}
}
# prepend product & book name (to avoid problems in sets)
# prepend tag type for translations BZ #427312
# If $product is unset then we are dealing with common content, so don't do the above.
if ( $my_id ne "" && $product ) {
$my_id = "$product-$docname-$my_id";
$my_id = substr( $tag, 0, 4 ) . "-$my_id";
}
$my_id = $node->attr( $self->{config}->param('id_attr') ) if ( !$my_id || ($my_id eq "" ));
if ( $node->attr( $self->{config}->param('id_attr') )
&& $node->attr( $self->{config}->param('id_attr') ) ne $my_id )
{
$UPDATED_IDS{ $node->attr( $self->{config}->param('id_attr') ) }
= $my_id;
}
if ( !$my_id || ( $my_id eq "") ) {
$my_id = undef;
}
$node->attr( $self->{config}->param('id_attr'), $my_id );
}
return;
}
=head2 print_xml
Print out utf8 XML files
Have to output xml/DTD header
=cut
sub print_xml {
my ( $self, $args ) = @_;
my $xml_doc = delete( $args->{xml_doc} )
|| croak( maketext("xml_doc is a mandatory argument") );
my $out_file = delete( $args->{out_file} )
|| croak( maketext("out_file is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $dtdver = $self->{publican}->param('dtdver');
my $docname = $self->{publican}->param('docname');
my $lang = $self->{config}->param('lang');
my $main_file = $self->{publican}->param('mainfile');
my $clean_id = $self->{config}->param('clean_id');
my $cleaning = $self->{config}->param('cleaning');
if ($xml_doc) {
my $file = $out_file;
my $path = '';
# handle nested directories
if ( $file =~ m|^(.*/xml)/(.*\/)[^\/]*\.xml| ) {
$path = $2;
mkpath("$1/$path") if ( !-d $path );
$path =~ s|[^/]*/|\.\./|g;
}
$xml_doc->pos( $xml_doc->root() );
if ( !$self->{config}->param('clean_id')
&& !$self->{config}->param('update_includes')
&& !$self->{config}->param('donotset_lang') )
{
if ( $dtdver !~ m/^5/ ) {
$xml_doc->attr( 'lang', $lang );
}
}
if ( $dtdver =~ m/^5/ ) {
$xml_doc->attr( 'xmlns', 'http://docbook.org/ns/docbook' );
$xml_doc->attr( 'xmlns:xlink', 'http://www.w3.org/1999/xlink' );
$xml_doc->attr( 'version', $dtdver );
$xml_doc->attr( 'xml:lang', $lang );
}
my $doctype;
foreach my $node ( $xml_doc->look_down( '_tag', '~declaration' ) ) {
$node->detach();
unless ($docname) {
if ( $node->attr('type') && $node->attr('type') eq 'DOCTYPE' )
{
$doctype = q|attr('mytag');
$doctype .= q| PUBLIC "| . $node->attr('pid') . q|"|
if ( $node->attr('pid')
&& $node->attr('pid') ne 'pid' );
$doctype .= q| "| . $node->attr('uri') . q|"|
if ( $node->attr('uri')
&& $node->attr('uri') ne 'uri' );
$doctype .= qq| [\n|;
}
else {
$doctype
.= q|attr('name') . q| "|
. $node->attr('value')
. qq|">\n|;
}
}
## print(STDERR Dumper($node));
}
$doctype .= qq|]>\n| if ($doctype);
my $type = $xml_doc->attr("_tag");
$file =~ m|^(.*/xml/)|;
my $text = $self->my_as_XML(
{ xml_doc => $xml_doc, path => ( $1 || './' ) } );
## BUGBUG revert to upstream as_XML?
## my $text = $xml_doc->as_XML();
# $text =~ s/"/"/g;
# $text =~ s/'/'/g;
# $text =~ s/"/"/g;
# $text =~ s/'/'/g;
$xml_doc->root()->delete();
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", "$out_file" )
|| croak(
maketext( "Could not open [_1] for output!", $out_file ) );
my $ent_file = undef;
# Will be unset when processing common files outside books
if ( $docname && !$self->{config}->param('exclude_ent') ) {
my $xml_lang = $self->{publican}->param('xml_lang');
if ( -e "$xml_lang/$main_file.ent" ) {
$ent_file = "$main_file.ent";
$ent_file = "$path$main_file.ent" if ($path);
}
}
if ($doctype) {
print( $OUTDOC $doctype );
}
else {
print( $OUTDOC Publican::dtd_string(
{ tag => $type,
dtdver => $dtdver,
ent_file => $ent_file,
cleaning => $cleaning,
}
)
);
}
#debug_msg("is utf8: " . utf8::is_utf8($text) . "\n");
print( $OUTDOC $text );
close($OUTDOC);
}
return;
}
=head2 my_as_XML
Traverse tree and output xml as text. Overrides traverse ... evil stuff.
=cut
sub my_as_XML {
my ( $self, $args ) = @_;
my $xml_doc = delete( $args->{xml_doc} )
|| croak( maketext("'xml_doc' is a mandatory argument") );
my $path = delete( $args->{path} )
|| croak( maketext("'path' is a mandatory argument") );
# based on as_HTML
my $tree = $xml_doc->root();
my @xml = ();
my $empty_element_map = $tree->_empty_element_map;
my %banned_tags = ();
foreach my $btag (
split( /,/, ( $self->{publican}->param('banned_tags') || "" ) ) )
{
$banned_tags{$btag} = 1;
}
my %banned_attrs = ();
foreach my $battr (
split( /,/, ( $self->{publican}->param('banned_attrs') || "" ) ) )
{
$banned_attrs{$battr} = 1;
}
my $clean_id = $self->{config}->param('clean_id');
my $unique_id = $self->{config}->param('unique_id');
my $lang = $self->{config}->param('lang');
# This flags tags that use /> instead of end tags IF they are empty.
$empty_element_map->{xref} = 1;
$empty_element_map->{footnoteref} = 1;
$empty_element_map->{'index'} = 1;
$empty_element_map->{'xi:include'} = 1;
$empty_element_map->{ulink} = 1;
$empty_element_map->{imagedata} = 1;
$empty_element_map->{area} = 1;
my $depth = 0;
my $indent = "\t";
my ( $tag, $node, $start ); # per-iteration scratch
# $_[0] = node
# $_[1] = startflag
# $_[2] = depth
# $_[3] = parent
# $_[4] = text node index
$tree->traverse(
sub {
( $node, $start ) = @_;
if ( ref $node ) { # it's an element
# delete internal attrs
$node->attr( 'depth', undef );
$node->attr( 'name', undef );
$tag = $node->{'_tag'};
#print(STDERR "tag: $tag\n");
if ($start) { # on the way in
if ( $banned_tags{$tag} ) {
croak(
maketext(
"ERROR: Banned tag ([_1]) detected. Discuss this with your brands owners if you think this is in error.",
$tag
)
. "\n"
);
}
foreach my $attr ( keys(%banned_attrs) ) {
if ( $node->attr($attr) ) {
croak(
maketext(
"ERROR: Banned attribute ([_1]) detected. Discuss this with your brands owners if you think this is in error.",
$attr
)
. "\n\n"
);
}
}
if ($clean_id) {
$self->Clean_ID($node);
}
if (( $MAP_OUT{$tag}->{'newline'} )
&& ( ( not defined $MAP_OUT{$tag}->{mixed_mode} )
|| ( not $MAP_OUT{$tag}->{mixed_mode} )
|| (not $node->look_up( '_tag', qr/para|entry/ ) )
)
)
{
push( @xml, "\n", $indent x $depth );
}
if ( $MAP_OUT{$tag}->{verbatim} && $tag ne '~cdata' ) {
push( @xml, "\n" );
}
elsif ( $MAP_OUT{$tag}->{block} ) {
# Check to make sure the block is starting on it's own line
# If not add a new line and indent
if (( $xml[$#xml] && $xml[$#xml] =~ /\S/ )
&& (( not defined $MAP_OUT{$tag}->{mixed_mode} )
|| ( not $MAP_OUT{$tag}->{mixed_mode} )
|| (not $node->look_up( '_tag',
qr/para|entry/ ) )
)
)
{
push( @xml, "\n", $indent x $depth );
}
$depth++;
}
if ( $tag eq 'imagedata' || $tag eq 'graphic' ) {
$node->attr('fileref') =~ m/(...)$/;
my $format = uc($1);
if ( !$node->attr('format') && $format ) {
$node->attr( 'format', $format );
}
my $img_file = "$path" . $node->attr('fileref');
$img_file
= $self->{publican}->param('xml_lang') . "/"
. $img_file
if ($clean_id || $unique_id);
if ( -f $img_file ) {
#nop
}
elsif ( $img_file !~ /Common_Content/ ) {
logger(
"\t"
. maketext(
"WARNING: Image missing: [_1]",
$img_file )
. "\n",
RED
);
}
# when building distrubuted sets, we need to prepend the
# books name to the image path to prevent image name clashes
my $preptxt
= $self->{publican}->param('img_dir') . '/'
. $self->{publican}->param('docname');
if ( $self->{config}->param('distributed_set')
&& $node->attr('fileref') !~ /^$preptxt/ )
{
$node->attr( 'fileref',
"$preptxt/" . $node->attr('fileref') );
}
}
if ( $tag eq '~cdata' ) {
push( @xml, '{$tag}
and !@{ $node->content_array_ref() } )
{
push( @xml, $node->starttag_XML( undef, 1 ) );
if ($MAP_OUT{$tag}->{newline_after}
&& (( not defined $MAP_OUT{$tag}->{mixed_mode} )
|| ( not $MAP_OUT{$tag}->{mixed_mode} )
|| (not $node->look_up( '_tag',
qr/para|entry/ ) )
)
)
{
push( @xml, "\n", $indent x $depth );
}
}
else {
push( @xml, $node->starttag_XML(undef) );
}
if ( $MAP_OUT{$tag}->{block} ) {
if ( $node->parent()
&& $MAP_OUT{ $node->parent()->{'_tag'} }
->{'line_wrap'} )
{
push( @xml, "\n" );
}
elsif (
( not $MAP_OUT{$tag}->{verbatim} )
&& (( not defined $MAP_OUT{$tag}->{mixed_mode} )
|| ( not $MAP_OUT{$tag}->{mixed_mode} )
|| (not $node->look_up( '_tag',
qr/para|entry/ ) )
)
)
{
push( @xml, "\n", $indent x $depth );
}
}
}
else { # on the way out
if ( $MAP_OUT{$tag}->{block} ) {
# remove empty lines
if ( $xml[$#xml] =~ /^[\t ]*$/s ) {
pop(@xml);
if ( $xml[$#xml] =~ /^[\t ]*$/s ) {
pop(@xml);
}
}
# remove trailing space
if ( $xml[$#xml] =~ /[\t ]*$/ ) # ||
{
$xml[$#xml] =~ s/[\t ]*$//;
}
if ( $MAP_OUT{$tag}->{block} ) {
if ( $MAP_OUT{$tag}->{verbatim} ) {
## BZ #604465 don't add trailing newline.
## push( @xml, "\n" );
}
elsif (( defined $MAP_OUT{$tag}->{mixed_mode} )
&& ( $MAP_OUT{$tag}->{mixed_mode} )
&& ($node->look_up( '_tag', qr/para|entry/ ) )
)
{
$depth--;
}
elsif ($node->parent()
&& $MAP_OUT{ $node->parent()->{'_tag'} }
->{'line_wrap'} )
{
$depth--;
push( @xml, "\n" );
}
else {
$depth--;
push( @xml, "\n", $indent x $depth );
}
}
}
unless ( $empty_element_map->{$tag}
and !@{ $node->content_array_ref() } )
{
if ( $tag eq '~cdata' ) {
push( @xml, qq|]]>| );
}
else {
push( @xml, $node->endtag_XML() );
}
} # otherwise it will have been an <... /> tag.
if (( $MAP_OUT{$tag}->{newline_after} )
&& ( ( not defined $MAP_OUT{$tag}->{mixed_mode} )
|| ( not $MAP_OUT{$tag}->{mixed_mode} )
|| (not $node->look_up( '_tag', qr/para|entry/ ) )
)
)
{
push( @xml, "\n", $indent x $depth );
}
if (( $MAP_OUT{$tag}->{block} )
&& ( ( not defined $MAP_OUT{$tag}->{mixed_mode} )
|| ( not $MAP_OUT{$tag}->{mixed_mode} )
|| (not $node->look_up( '_tag', qr/para|entry/ ) )
)
)
{
push( @xml, "\n", $indent x $depth );
}
}
}
else { # it's just text
my $parent = $_[3];
# Remove extra space from non-verbatim tags
if ( $parent
&& !( $MAP_OUT{ $parent->{'_tag'} }->{verbatim} ) )
{
# Don't out put empty tags
# BZ #453067 but spaces between inline tags should be output
if ( $node !~ /^[\t ]*$/ || $node !~ /\n/ ) {
# Truncate leading space
$node =~ s/[\n\r\f\t ]+/ /g;
if ( $MAP_OUT{ $parent->{'_tag'} }->{block} ) {
# for the first child, remove leading space and indent it
if ( $_[4] == 0 ) {
$node =~ s/^ //g;
}
}
$tree->_xml_escape($node);
$node =~ s/"/"/g;
$node =~ s/'/'/g;
$node =~ s/"/"/g;
$node =~ s/'/'/g;
push( @xml, $node );
}
}
else { # Verbatim
if ( $parent->{'_tag'} ne '~cdata' ) {
$tree->_xml_escape($node);
$node =~ s/"/"/g;
$node =~ s/'/'/g;
$node =~ s/"/"/g;
$node =~ s/'/'/g;
}
push( @xml, $node );
}
}
1; # keep traversing
}
);
return ( join( '', @xml, "\n" ) );
}
=head2 validate_tables
Ensure Tables comply to requirements not enforceable in XML validation.
1. tgroup attribute cols must match the number of entries in every row.
=cut
sub validate_tables {
my ( $self, $xml_doc ) = @_;
if ($xml_doc) {
$xml_doc->pos( $xml_doc->root() );
foreach my $node ( $xml_doc->look_down( "_tag", "tgroup" ) ) {
# TODO this should report the line number
# until then it try's to determine the Tables title or id
my $table = $node->look_up( "_tag", qr/table|informaltable/ );
if ( !$table ) {
logger(
maketext(
"WARNING: table validation failed. Could not determine table for tgroup, column numbers cannot be validated"
)
);
next;
}
my $title = $table->look_down( "_tag", "title" );
if ($title) {
$title = $title->as_text();
}
else {
$title = ( $table->attr('id') || "Can't identify table" );
}
my $cols = $node->attr('cols')
|| croak maketext(
"*ERROR: Fatal Table Error* Table ([_1]) contains invalid data\nAttribute cols is mandatory for tgroup",
$title
) . "\n";
foreach my $row ( $node->look_down( "_tag", "row" ) ) {
my @entries = $row->look_down( "_tag", qr/(?:entry|entrytbl)/,
sub { $_[0]->depth() == ( $row->depth() + 1 ) } );
## BUGBUG this is incomplete, it should check colwidths
if ( @entries > $cols ) {
croak maketext(
"*ERROR: Fatal Table Error* Table ([_1]) contains invalid data\nAttribute cols ([_2]) does not match number of entry elements ([_3])",
$title, $cols, scalar @entries
) . "\n";
}
}
}
}
return;
}
=head2 process_file
Create XML::TreeBuilder object and perform operations.
=cut
sub process_file {
my ( $self, $args ) = @_;
my $file = delete( $args->{file} )
|| croak( maketext("file is a mandatory argument") );
my $out_file = delete( $args->{out_file} )
|| croak( maketext("out_file is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
logger( "\t"
. maketext( "Processing file [_1] -> [_2]", $file, $out_file )
. "\n" );
my $clean_id = $self->{config}->param('clean_id');
my $update_includes = $self->{config}->param('update_includes');
my $xml_lang = $self->{publican}->param('xml_lang');
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
$xml_doc->store_comments(1);
$xml_doc->store_pis(1);
$xml_doc->store_cdata(1);
$xml_doc->store_declarations(1);
##debug_msg("here 1");
eval { $xml_doc->parse_file($file); };
croak( maketext( "Can't open file '[_1]' [_2]", $file, $@ ) ) if ($@);
##debug_msg("here 2");
$self->validate_tables($xml_doc);
if ($update_includes) {
$self->update_include($xml_doc);
}
elsif ( !$clean_id ) {
$self->prune_xml($xml_doc);
}
$self->print_xml( { xml_doc => $xml_doc, out_file => $out_file } );
if ($clean_id) {
# Update links in xml
foreach my $xml_file ( dir_list( $xml_lang, '*.xml' ) ) {
my $editor = new File::Inplace( file => $xml_file );
my $perm = ( stat $editor->{infh} )[2] & 07777;
my $uid = ( stat $editor->{infh} )[4];
my $gid = ( stat $editor->{infh} )[5];
while ( my ($line) = $editor->next_line ) {
foreach my $key ( keys(%UPDATED_IDS) ) {
$line =~ s/linkend="$key"/linkend="$UPDATED_IDS{$key}"/g;
}
$editor->replace_line($line);
}
$editor->commit;
$editor = undef;
chmod( $perm | 0600, $xml_file ) || logger(
maketext(
"WARNING: Could not reset file permissions for [_1] because [_2]",
$xml_file,
$!
)
);
chown( $uid, $gid, $xml_file ) || logger(
maketext(
"WARNING: Could not reset file ownership for [_1] because [_2]",
$xml_file,
$!
)
);
}
# update links in PO files
foreach my $dir ( split( /,/, get_all_langs() ) ) {
next if ( $dir eq $xml_lang );
foreach my $po_file ( dir_list( $dir, '*.po' ) ) {
my $editor = new File::Inplace( file => $po_file );
while ( my ($line) = $editor->next_line ) {
foreach my $key ( keys(%UPDATED_IDS) ) {
# all of string on one line
$line =~ s/=\\"$key\\"/=\\"$UPDATED_IDS{$key}\\"/g;
# tail of string line wrapped
$line =~ s/=\\"$key"/=\\"$UPDATED_IDS{$key}"/g;
# string line wrapped after '='
$line =~ s/\\"$key\\"/\\"$UPDATED_IDS{$key}\\"/g;
}
$editor->replace_line($line);
}
$editor->commit;
}
}
# clear out changes ... might be better to save them up and do a single pass...
%UPDATED_IDS = ();
}
return;
}
=head2 set_unique_ids
Set unique ids for every nodes which have id
=cut
sub set_unique_ids {
my ( $self, $args ) = @_;
my $xml_lang = $self->{publican}->param('xml_lang');
# create database to track section id changes
my $db_file = "$xml_lang/max_unique_id.db";
$self->{dbh}
= DBI->connect( "dbi:SQLite:dbname=$db_file", "", "",
{ RaiseError => 1 } )
|| croak( maketext($DBI::errstr) );
$self->create_db();
my $sql = "select max_unique_id from max_unique_id";
my $sth = $self->{dbh}->prepare($sql);
$sth->execute();
my $result = $sth->fetchrow_hashref();
my $unique_id = $result->{max_unique_id} || 0;
$sth->finish();
my @xml_files;
@xml_files = dir_list( $xml_lang, '*.xml' );
my $conformance = 0;
foreach my $xml_file ( sort(@xml_files) ) {
next if ( $xml_file =~ m{/extras/} );
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
$xml_doc->store_comments(1);
$xml_doc->store_pis(1);
$xml_doc->store_cdata(1);
$xml_doc->store_declarations(1);
$xml_doc->parse_file($xml_file);
# based on as_HTML
my $tree = $xml_doc->root();
my $empty_element_map = $tree->_empty_element_map;
# This flags tags that use /> instead of end tags IF they are empty.
$empty_element_map->{xref} = 1;
$empty_element_map->{footnoteref} = 1;
$empty_element_map->{'index'} = 1;
$empty_element_map->{'xi:include'} = 1;
$empty_element_map->{ulink} = 1;
$empty_element_map->{imagedata} = 1;
$empty_element_map->{area} = 1;
my ( $tag, $node, $start ); # per-iteration scratch
# $_[0] = node
# $_[1] = startflag
# $_[2] = depth
# $_[3] = parent
# $_[4] = text node index
$tree->traverse(
sub {
( $node, $start ) = @_;
if ( ref $node ) {
$tag = $node->{'_tag'};
if ( $start
&& $node->attr( $self->{config}->param('id_attr') )
&& !$node->attr('conformance') )
{ # on the way in
$node->attr( 'conformance', ++$unique_id );
}
}
1; # keep traversing
}
);
$self->print_xml( { xml_doc => $tree, out_file => $xml_file } );
}
eval {
my $update_sql = <{dbh}->do($update_sql);
};
if ($@) {
$self->{dbh}->rollback();
$self->{dbh}->disconnect();
croak( maketext("Error setting max id: $@") );
}
$self->{dbh}->disconnect();
return;
}
=head2 create_db
Create a database to track the max unique id
=cut
sub create_db {
my $self = shift;
my $sql;
eval {
my $check_table_sql = <{dbh}->selectrow_hashref($check_table_sql);
return if ( defined $table->{name} );
$self->{dbh}->do($create_table_sql);
# create first row and set value to 0
my $insert_sql = <{dbh}->do($insert_sql);
};
if ($@) {
$self->{dbh}->rollback();
croak( maketext("Failed to create table: $@") );
}
return;
}
1; # Magic true value required at end of module
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=item C<< Could not open %s for output! >>
The named file could not be opened.
=item C<< Can't calculate image size of %s >>
Images are automatically scaled if thy are to wide, this check could not be
performed due to either access permissions or file weirdness.
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican::XmlClean requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
version
XML::TreeBuilder
Text::Wrap
Config::Simple
Publican
File::Path
Term::ANSIColor
Cwd
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
CreateBrand.pm 000444 041472 041472 24420 12555605450 21134 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::CreateBrand;
use strict;
use warnings;
use 5.008;
use Carp;
use Config::Simple '-strict';
use File::Path;
use File::pushd;
use DateTime;
use Publican;
use Publican::Builder;
use Term::ANSIColor qw(:constants uncolor);
use vars qw( $MAX_COUNT );
$MAX_COUNT = 29;
my $INIT_VERSION = '0.1';
## NOTE Change this for betas
my $PUBLICAN_NAME = 'publican';
=head1 NAME
Publican::CreateBrand - A module for generating new brand boilerplate.
=head1 SYNOPSIS
use Publican::CreateBrand;
my $creator = Publican::CreateBrand->new({name => 'foo'});
$creator->create();
=head1 DESCRIPTION
Creates a new Brand for use with the publican package
=head1 INTERFACE
=cut
=head2 new
Create a Publican object set.
=head3 Parameters:
name Brand Name (Required)
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $config = new Config::Simple();
$config->syntax('http');
$config->param( 'brand',
delete( $args->{name} )
|| croak( maketext("name is a required parameter") ) );
$config->param( 'xml_lang',
delete( $args->{lang} )
|| croak( maketext("lang is a required parameter") ) );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
$config->param( 'type', 'brand' );
$config->param( 'version', $INIT_VERSION );
my $self = bless {}, $class;
$self->{config} = $config;
return $self;
}
=head2 create
Create all the required files.
=cut
sub create {
my ($self) = @_;
my ( $OUT, $out_file );
my $name = $self->{config}->param('brand');
my $lang = $self->{config}->param('xml_lang');
croak( maketext( "Invalid language supplied: [_1]", $lang ) . "\n" )
unless ( Publican::valid_lang($lang) );
croak(
maketext(
"Can't create brand, directory 'publican-[_1]' exists!", $name
)
) if ( -d "publican-$name" );
mkpath("publican-$name")
|| croak( maketext( "Can't create directory: [_1]", $@ ) );
my $dir = pushd("publican-$name");
mkpath("$lang/images")
|| croak( maketext( "Can't create directory: [_1]", $@ ) );
$self->conf_files();
$self->{publican} = Publican->new( { configfile => 'publican.cfg', } );
$self->xml_files();
$self->images();
mkpath("$lang/css");
$out_file = "$lang/css/overrides.css";
open( $OUT, ">:encoding(UTF-8)", $out_file )
|| croak(
maketext( "Could not open [_1] for output: [_2]", $out_file, $@ ) );
print $OUT <{config}->param('xml_lang');
my %files = (
'Feedback' => {
'type' => 'section',
'node' => XML::Element->new_from_lol(
[ 'section',
[ 'title', 'We Need Feedback!' ],
[ 'indexterm',
[ 'primary', 'feedback1' ],
[ 'secondary', 'contact information for this brand' ],
],
[ 'para',
'SETUP: You should change this text to reflect the default contact information for this brand. e.g. mail list, ticketing system etc.'
],
],
),
},
'Legal_Notice' => {
'type' => 'legalnotice',
'node' => XML::Element->new_from_lol(
[ 'legalnotice',
[ 'para',
'Copyright &YEAR; &HOLDER;'
],
[ 'para',
'SETUP: Enter the blurb for your license here. Often a short description of the license with a URL linking to the full text.'
],
],
),
},
);
foreach my $file ( keys(%files) ) {
my $xml_doc = $files{$file}->{node};
my $type = $files{$file}->{type};
$xml_doc->pos( $xml_doc->root() );
my $text = $xml_doc->as_XML($xml_doc);
my $out_file = "$lang/$file" . ".xml";
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", $out_file )
|| croak(
maketext( "Could not open file [_1] for output!", $out_file ) );
print( $OUTDOC Publican::Builder::dtd_string(
{ tag => $type, dtdver => '4.5', cleaning => 1 }
)
);
print( $OUTDOC $text );
close($OUTDOC);
$xml_doc->root()->delete();
}
return;
}
=head2 conf_files
Create configuration files.
=cut
sub conf_files {
my ($self) = @_;
my ( $OUT, $out_file );
my $brand = $self->{config}->param('brand');
my $lcbrand = lc($brand);
my $cfg_file = 'publican.cfg';
# publican.cfg
$self->{config}->write($cfg_file)
|| croak(
maketext(
"Can't write to [_1]: [_2]", $cfg_file,
Config::Simple->error()
)
);
debug_msg("TODO: conf_files: COPYING - URL for where to wget it\n");
debug_msg("TODO: conf_files: TODO README\n");
my $config = new Config::Simple();
$config->syntax('http');
$config->param( 'prod_url', 'http://www.SETUP.example.com' );
$config->param( 'doc_url', 'http://www.SETUP.example.com/docs' );
$config->write('defaults.cfg')
|| croak(
maketext(
"Can't write to defaults.cfg: [_1]",
Config::Simple->error()
)
);
$config->close();
$config = new Config::Simple();
$config->syntax('http');
$config->write('overrides.cfg')
|| croak(
maketext(
"Can't write to overrides.cfg: [_1]",
Config::Simple->error()
)
);
$config->close();
# spec file
my $date = DateTime->today()->strftime("%a %b %e %Y");
$out_file = "publican-$lcbrand.spec";
open( $OUT, ">:encoding(UTF-8)", $out_file )
|| croak(
maketext( "Could not open file [_1] for output!", $out_file ) );
print $OUT < 0.1
- Created Brand
SPEC
close($OUT);
open( $OUT, ">:encoding(UTF-8)", 'README' )
|| croak( maketext("Could not open file README for output!") );
print( $OUT
"SETUP This file should be a short description of your project" );
close($OUT);
open( $OUT, ">:encoding(UTF-8)", 'COPYING' )
|| croak( maketext("Could not open file COPYING for output!") );
print( $OUT "SETUP This file should contain your COPYRIGHT License" );
close($OUT);
return;
}
=head2 images
Create images dir and all the default images in svg and png format.
=cut
sub images {
my ($self) = @_;
my ( $OUT, $out_file );
my $lang = $self->{config}->param('xml_lang');
my $common_content = $self->{publican}->param('common_content');
rcopy_glob( $common_content . "/brand-template/images/*",
"$lang/images" );
return;
}
1; # Magic true value required at end of module
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required parameter >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=item C<< "Can't create brand, directory %s exists! >>
When creating a Brand a directory is created with the same name as the
brand. If a directory with that name is in the current directory the
creation will fail.
=item C<< Invalid language supplied: %s >>
The language supplied is not a valid language.
=item C<< Can't create directory: %s >>
=item C<< Could not open %s for output! >>
=item C<< Can't write file >>
=item C<< Can't open SVG file %s >>
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican::CreateBrand requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
version
Config::Simple
File::Path
File::pushd
DateTime
Publican
Term::ANSIColor
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
None reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
CreateBook.pm 000444 041472 041472 77051 12555605450 21010 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::CreateBook;
use strict;
use warnings;
use 5.008;
use Carp;
use Config::Simple '-strict';
use XML::TreeBuilder;
use File::Path;
use DateTime;
use Term::ANSIColor qw(:constants);
use Publican;
use Publican::Builder;
# Icon used for menu
my $icon = q{
};
=head1 NAME
Publican::CreateBook - A module for generating documentation boilerplate
=head1 SYNOPSIS
use Publican::CreateBook;
my $creator = Publican::CreateBook->new({name => 'foo'});
$creator->create();
=head1 DESCRIPTION
Creates a new Book, Article or Set for use with the publican package
=head1 INTERFACE
=cut
=head2 new
Create a Publican object set.
=head3 Parameters:
docname Book Name (Required)
version Product Version (default: 0.1)
edition Edition (default: 0)
product Product Name (default: Documentation)
brand Brand (default: common)
xml_lang Source Language (default: en-US)
type Book|Set|Article (default: Book)
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $config = new Config::Simple();
$config->syntax('http');
$config->param( 'docname',
delete( $args->{name} )
|| croak( maketext("name is a required parameter") ) );
$config->param( 'version', delete( $args->{version} ) || '0.1' );
$config->param( 'edition', delete( $args->{edition} ) || '0' );
$config->param( 'product',
delete( $args->{product} ) || 'Documentation' );
$config->param( 'brand', delete( $args->{brand} ) || 'common' );
$config->param( 'xml_lang', delete( $args->{lang} ) || 'en-US' );
$config->param( 'type', delete( $args->{type} ) || 'Book' );
$config->param( 'dtdver', delete( $args->{dtdver} ) || '4.5' );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
if ( $config->param('type') !~ m/^(Book|Set|Article)$/i ) {
croak( maketext("type must be book, set, or article") );
}
my $self = bless {}, $class;
$config->param( 'type', ucfirst( $config->param('type') ) );
$self->{config} = $config;
return $self;
}
=head2 create
Try embedding templates in perl to avoid licensing rubbish
=cut
sub create {
my ($self) = @_;
my $name = $self->{config}->param('docname');
my $version = $self->{config}->param('version');
my $edition = $self->{config}->param('edition');
my $product = $self->{config}->param('product');
my $brand = $self->{config}->param('brand');
my $lang = $self->{config}->param('xml_lang');
my $type = $self->{config}->param('type');
my $dtdver = $self->{config}->param('dtdver');
my $lctype = lc($type);
my $bookname = $self->{config}->param('docname');
$bookname =~ s/_/ /g;
croak( maketext( "directory [_1] exists!", $name ) ) if ( -e $name );
mkpath("$name/$lang/images");
my %files;
if ( $dtdver =~ /^5/ ) {
if ( $brand eq 'common' ) {
$brand = 'common-db5';
$self->{config}->param( 'brand', 'common-db5' );
}
%files = (
'Author_Group' => {
types => 'Book Set Article',
node => XML::Element->new_from_lol(
[ 'authorgroup',
[ 'author',
[ 'personname',
[ 'firstname',
maketext('Enter your first name here.')
],
[ 'surname',
maketext('Enter your surname here.')
],
],
[ 'affiliation',
[ 'orgname',
maketext(
q|Enter your organisation's name here.|
)
],
[ 'orgdiv',
maketext(
'Enter your organisational division here.'
)
],
],
[ 'email',
maketext('Enter your email address here.')
],
],
],
),
},
'Book' => {
types => 'Book',
node => XML::Element->new_from_lol(
[ 'book',
[ 'xi:include',
{ href => 'Book_Info.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Preface.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Chapter.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Revision_History.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
['index'],
],
),
},
'Article' => {
types => 'Article',
node => XML::Element->new_from_lol(
[ 'article',
[ 'xi:include',
{ href => 'Article_Info.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'para', maketext('This is a test paragraph') ],
[ 'xi:include',
{ href => 'Revision_History.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
['index'],
],
),
},
'Set' => {
types => 'Set',
node => XML::Element->new_from_lol(
[ 'set',
[ 'xi:include',
{ href => 'Set_Info.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'remark',
maketext(
'NOTE: the href does not contain a language! This is CORRECT!'
)
],
[ 'remark',
''
],
['setindex'],
],
),
},
"$type"
. "_Info" => {
types => 'Book Set Article',
node => XML::Element->new_from_lol(
[ 'info',
[ 'title', $bookname ],
[ 'subtitle',
maketext('Enter a short description here.')
],
[ 'productname', $product ],
[ 'productnumber', $version ],
[ 'edition', $edition ],
[ 'abstract',
[ 'para',
maketext(
q|A short overview and summary of the book's subject and purpose, traditionally no more than one paragraph long. Note: the abstract will appear in the front matter of your book and will also be placed in the description field of the book's RPM spec file.|
)
],
],
[ 'orgname',
[ 'inlinemediaobject',
[ 'imageobject',
[ 'imagedata',
{ format => 'SVG',
fileref =>
'Common_Content/images/title_logo.svg'
}
],
],
],
],
[ 'xi:include',
{ href => 'Common_Content/Legal_Notice.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Author_Group.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
],
),
},
'Revision_History' => {
types => 'Book Set Article',
node => XML::Element->new_from_lol(
[ 'appendix',
[ 'title', maketext('Revision History') ],
[ 'revhistory',
[ 'revision',
[ 'revnumber', '0.0-0' ],
[ 'date',
DateTime->today()->strftime("%a %b %e %Y")
],
[ 'author',
[ 'personname',
[ 'firstname',
maketext(
'Enter your first name here.')
],
[ 'surname',
maketext(
'Enter your surname here.')
],
],
[ 'email',
maketext(
'Enter your email address here.'
)
],
],
[ 'revdescription',
[ 'simplelist',
[ 'member',
maketext(
'Initial creation by publican'
)
],
],
],
],
],
],
),
},
'Chapter' => {
types => 'Book',
node => XML::Element->new_from_lol(
[ 'chapter',
[ 'title', maketext('Test Chapter') ],
[ 'para', maketext('This is a test paragraph') ],
[ 'section',
[ 'title', maketext('Test Section 1') ],
[ 'para',
maketext(
'This is a test paragraph in a section')
],
],
[ 'section',
[ 'title', maketext('Test Section 2') ],
[ 'para',
maketext(
'This is a test paragraph in Section 2'),
[ 'orderedlist',
[ 'listitem',
[ 'para',
maketext(
'This is a test listitem.')
],
],
],
],
],
],
),
},
'Preface' => {
types => 'Book Set',
node => XML::Element->new_from_lol(
[ 'preface',
[ 'title', maketext('Preface') ],
[ 'xi:include',
{ href => 'Common_Content/Conventions.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Feedback.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
},
[ 'xi:fallback',
{ 'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
},
[ 'xi:include',
{ href => 'Common_Content/Feedback.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
},
],
],
],
],
),
},
);
}
else {
%files = (
'Author_Group' => {
types => 'Book Set Article',
node => XML::Element->new_from_lol(
[ 'authorgroup',
[ 'author',
[ 'firstname',
maketext('Enter your first name here.')
],
[ 'surname',
maketext('Enter your surname here.')
],
[ 'affiliation',
[ 'orgname',
maketext(
q|Enter your organisation's name here.|
)
],
[ 'orgdiv',
maketext(
'Enter your organisational division here.'
)
],
],
[ 'email',
maketext('Enter your email address here.')
],
],
],
),
},
'Book' => {
types => 'Book',
node => XML::Element->new_from_lol(
[ 'book',
[ 'xi:include',
{ href => 'Book_Info.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Preface.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Chapter.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Revision_History.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
['index'],
],
),
},
'Article' => {
types => 'Article',
node => XML::Element->new_from_lol(
[ 'article',
[ 'xi:include',
{ href => 'Article_Info.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'para', maketext('This is a test paragraph') ],
[ 'xi:include',
{ href => 'Revision_History.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
['index'],
],
),
},
'Set' => {
types => 'Set',
node => XML::Element->new_from_lol(
[ 'set',
[ 'xi:include',
{ href => 'Set_Info.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'remark',
maketext(
'NOTE: the href does not contain a language! This is CORRECT!'
)
],
[ 'remark',
''
],
['setindex'],
],
),
},
"$type"
. "_Info" => {
types => 'Book Set Article',
node => XML::Element->new_from_lol(
[ $lctype . 'info',
[ 'title', $bookname ],
[ 'subtitle',
maketext('Enter a short description here.')
],
[ 'productname', $product ],
[ 'productnumber', $version ],
[ 'edition', $edition ],
[ 'pubsnumber', '0' ],
[ 'abstract',
[ 'para',
maketext(
q|A short overview and summary of the book's subject and purpose, traditionally no more than one paragraph long. Note: the abstract will appear in the front matter of your book and will also be placed in the description field of the book's RPM spec file.|
)
],
],
[ 'corpauthor',
[ 'inlinemediaobject',
[ 'imageobject',
[ 'imagedata',
{ format => 'SVG',
fileref =>
'Common_Content/images/title_logo.svg'
}
],
],
],
],
[ 'xi:include',
{ href => 'Common_Content/Legal_Notice.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Author_Group.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
],
),
},
'Revision_History' => {
types => 'Book Set Article',
node => XML::Element->new_from_lol(
[ 'appendix',
[ 'title', maketext('Revision History') ],
[ 'simpara',
[ 'revhistory',
[ 'revision',
[ 'revnumber', '0.0-0' ],
[ 'date',
DateTime->today()
->strftime("%a %b %e %Y")
],
[ 'author',
[ 'firstname',
maketext(
'Enter your first name here.')
],
[ 'surname',
maketext(
'Enter your surname here.')
],
[ 'email',
maketext(
'Enter your email address here.'
)
],
],
[ 'revdescription',
[ 'simplelist',
[ 'member',
maketext(
'Initial creation by publican'
)
],
],
],
],
],
],
],
),
},
'Chapter' => {
types => 'Book',
node => XML::Element->new_from_lol(
[ 'chapter',
[ 'title', maketext('Test Chapter') ],
[ 'para', maketext('This is a test paragraph') ],
[ 'section',
[ 'title', maketext('Test Section 1') ],
[ 'para',
maketext(
'This is a test paragraph in a section')
],
],
[ 'section',
[ 'title', maketext('Test Section 2') ],
[ 'para',
maketext(
'This is a test paragraph in Section 2'),
[ 'orderedlist',
[ 'listitem',
[ 'para',
maketext(
'This is a test listitem.')
],
],
],
],
],
],
),
},
'Preface' => {
types => 'Book Set',
node => XML::Element->new_from_lol(
[ 'preface',
[ 'title', maketext('Preface') ],
[ 'xi:include',
{ href => 'Common_Content/Conventions.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
}
],
[ 'xi:include',
{ href => 'Feedback.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
},
[ 'xi:fallback',
{ 'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
},
[ 'xi:include',
{ href => 'Common_Content/Feedback.xml',
'xmlns:xi' =>
'http://www.w3.org/2001/XInclude'
},
],
],
],
],
),
},
);
}
debug_msg("TODO: consolidate XML methods with Builder\n");
# formatting
foreach my $file ( keys(%files) ) {
if ( $files{$file}->{types} !~ /$type/ ) {
next;
}
my $xml_doc = $files{$file}->{node};
$xml_doc->pos( $xml_doc->root() );
my $node_type = $xml_doc->{'_tag'};
my $text = $xml_doc->as_XML($xml_doc);
my $out_file = "$name/$lang/$file" . ".xml";
if ( $file =~ m/^(Book|Set|Article)$/ ) {
$out_file = "$name/$lang/$name" . ".xml";
}
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", $out_file )
|| croak(
maketext( "Could not open [_1] for output!", $out_file, $@ ) );
print( $OUTDOC Publican::Builder::dtd_string(
{ tag => $node_type, dtdver => $dtdver, cleaning => 1 }
)
);
print( $OUTDOC $text );
close($OUTDOC);
$xml_doc->root()->delete();
}
# remove these from the default configuration file
# so that by default only the XML requires changing.
$self->{config}->delete('docname');
$self->{config}->delete('version');
$self->{config}->delete('edition');
$self->{config}->delete('product');
$self->{config}->write("$name/publican.cfg");
my $year = DateTime->today()->year();
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", "$name/$lang/$name" . ".ent" )
|| croak( maketext( "Could not open entity file. [_1]", $@ ) );
my $holder_text
= maketext(
'You need to change the HOLDER entity in the [_1]/[_2].ent file',
$lang, $name );
print $OUTDOC <
EOL
close($OUTDOC);
open( $OUTDOC, ">:encoding(UTF-8)", "$name/$lang/images/icon.svg" )
|| croak( maketext( "Could not open icon file. [_1]", $@ ) );
print( $OUTDOC $icon );
close($OUTDOC);
return;
}
1; # Magic true value required at end of module
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=item C<< directory %s exists >>
When creating a book a directory is created named publican-. If a directory with that name is in the current directory the creation will fail.
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican::CreateBook requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
Config::Simple
XML::TreeBuilder
File::Path
DateTime
Term::ANSIColor
Publican
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
Localise.pm 000444 041472 041472 11341 12555605450 20513 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican use strict;
use warnings;
package Publican::Localise;
use base qw(Locale::Maketext::Gettext);
=head1 NAME
Publican::Localise - Publican localisation utilities.
#...any methods you might want all your languages to share...
# And, assuming you want the base class to be an _AUTO lexicon,
# as is discussed a few sections up:
=head2 fallback_language_classes
fallback to en for unknown locales
=cut
sub fallback_language_classes {
return "en";
}
1;
package Publican::Localise::C;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::as;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::bg;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::bn_in;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::bs;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ca;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::cs;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::da;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::de;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::el;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::en;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::es;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::fi;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::fr;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::gu;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::he;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::hi;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::hr;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::hu;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::id;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::it;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ja;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::kn;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ko;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::lv;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ml;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::mr;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ms;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::nb;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::nl;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::or;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::pa;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::pl;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::pt;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::pt_br;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ru;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::sk;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::sr_latn;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::sr;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::sv;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::ta;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::te;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::uk;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::zh_cn;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::zh_tw;
use base qw(Locale::Maketext::Gettext);
return 1;
=head1
package Publican::Localise::de_de;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::zh_tw;
use base qw(Locale::Maketext::Gettext);
return 1;
package Publican::Localise::zh_cn;
use base qw(Locale::Maketext::Gettext);
return 1;
=cut
=head1 BUGS AND LIMITATIONS
None reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
WebSite.pm 000444 041472 041472 245531 12555605450 20354 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::WebSite;
use utf8;
use warnings;
use strict;
use 5.008;
use Carp qw(cluck croak confess);
use Config::Simple '-strict';
use DBI;
use Template;
use Template::Constants;
use Locale::Language;
use File::Find::Rule;
use DateTime;
use Publican;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
use Time::localtime;
use XML::Simple;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use Publican::ConfigData;
use HTML::TreeBuilder;
use File::pushd;
my $DB_NAME = 'books';
my $DEFAULT_LANG = 'en-US';
my $DEFAULT_TMPL_PATH = Publican::ConfigData->config('templates');
my $DEFAULT_CONFIG_FILE
= Publican::ConfigData->config('etc') . '/publican-website.cfg';
my $DEFAULT_DUMP_FILE = '/var/www/html/DUMP.xml';
my %LANG_NAME = (
'ar-SA' => 'иЇйиЙиБиЈйиЉ',
'as-IN' => 'рІ рІИрІЎрЇрЇрІО',
'ast-ES' => 'Asturianu',
'bg-BG' => 'аБбаЛаГаАббаКаИ',
'bn-IN' => 'рІЌрІОрІрІВрІО',
'bs-BA' => 'Bosanski',
'ca-ES' => 'CatalУ ',
'cs-CZ' => 'ФeХЁtina',
'da-DK' => 'Dansk',
'de-CH' => 'Schweizerdeutsch',
'de-DE' => 'Deutsch',
'el-GR' => 'ЮЮЛЮЛЮЗЮНЮЙЮКЮЌ',
'en-US' => 'English',
'es-ES' => 'EspaУБol',
'fa-IR' => 'йиЇиБиГл',
'fi-FI' => 'Suomi',
'fr-FR' => 'FranУЇais',
'gu-IN' => 'рЊрЋрЊрЊАрЊОрЊЄрЋ',
'he-IL' => 'зЂззЈззЊ',
'hi-IN' => 'рЄЙрЄПрЄЈрЅрЄІрЅ',
'hr-HR' => 'Hrvatski',
'hu-HU' => 'Magyar',
'id-ID' => 'Indonesia',
'is-IS' => 'Уslenska',
'it-IT' => 'Italiano',
'ja-JP' => 'цЅцЌшЊ',
'kn-IN' => 'рВрВЈрГрВЈрВЁ',
'ko-KR' => 'эъЕьД',
'ml-IN' => 'рДЎрДВрДЏрДОрДГрД',
'mr-IN' => 'рЄЎрЄАрЄОрЄ рЅ',
'ms-MY' => 'Melayu',
'nb-NO' => 'Norsk (bokmУЅl)',
'nds-DE' => 'PlattdУМУМtsch',
'nl-NL' => 'Nederlands',
'or-IN' => 'рЌрЌЁрЌМрЌПрЌ',
'pa-IN' => 'рЈЊрЉАрЈрЈОрЈЌрЉ',
'pl-PL' => 'Polski',
'pt-BR' => 'PortuguУЊs Brasileiro',
'pt-PT' => 'PortuguУЊs',
'ru-RU' => 'а бббаКаИаЙ',
'si-LK' => 'рЗрЗрЖрЗрЖН',
'sk-SK' => 'SlovenХЁФina',
'sr-RS' => 'аЁбаПбаКаИ',
'sr-Latn-RS' => 'Srpski (latinica)',
'sv-SE' => 'Svenska',
'ta-IN' => 'рЎЄрЎЎрЎПрЎДрЏ',
'te-IN' => 'рАЄрБрАВрБрАрБ',
'uk-UA' => 'аЃаКбаАбаНббаКаА',
'zh-CN' => 'чЎфНфИц',
'zh-TW' => 'чЙщЋфИц',
);
my %PARAMS = (
toc_path => {
descr => maketext(
"The path to the directory in which to create the top-level index.html file."
),
mandatory => 1
},
tmpl_path => {
descr => maketext("Full path to the template directory."),
default => $DEFAULT_TMPL_PATH
},
def_lang => {
descr => maketext(
"The default language for this website. Tables of contents for languages other than the default language will link to documents in the default language when translations are not available."
),
default => $DEFAULT_LANG
},
db_file => {
descr => maketext(
"The name of the SQLite database file for your site, with the filename extension .db"
),
mandatory => 1
},
host => {
descr =>
maketext("The web host, may be a full URI or a relative path."),
default => "/docs"
},
search => {
descr => maketext("The HTML to inject in as the site serach."),
default => maketext("Google site search")
},
title => {
descr => maketext("Title used for all site navigation pages."),
default => maketext("Documentation")
},
dump =>
{ descr => maketext("Dump the publican database to an XML file.") },
dump_file => {
descr => maketext(
"The name of the file to dump the publican database to."),
default => $DEFAULT_DUMP_FILE
},
zip_dump => {
descr => maketext("Zip up the dump file after dumping it"),
default => 0
},
toc_type => {
descr => maketext(
"Template to use for generagting the web style 1 toc file."),
default => "toc",
alert => maketext(
'This field is deprecated and will be removed from Publican in the future.'
),
},
toc_js => {
descr =>
maketext("The source file to use for JavaScript functionality."),
default => "default.js"
},
manual_toc_update => {
descr => maketext(
"Stop publican from automatically rebuilding teh web site everytime a book is installed, updated or removed."
),
default => "0"
},
debug => {
descr => maketext("Output extra messages when running publican."),
default => "0"
},
footer => {
descr => maketext(
"HTML to inject in to the footer of every page on the website."),
default => ""
},
web_style => {
descr => maketext(
"Publican supports mutliple base styles for websites, this picks one."
),
constraint => '[1-2]',
default => "1",
alert => maketext(
'This field is deprecated and will be removed from Publican in the future.'
)
},
home_link => {
descr => maketext(
"HTML anchor to inject in to the start of site navigation menu."),
},
);
# This is required to ensure that the correct localised strings are found when running
# the commands on an non en-US command line
my $locale = Publican::Localise->get_handle('en-US')
|| croak(
"Could not create a Publican::Localise object for language: en-US");
$locale->encoding("UTF-8");
$locale->textdomain("publican");
my %tmpl_strings = (
toc_nav => $locale->maketext('toc nav'),
Welcome => $locale->maketext('Welcome'),
collapse_all => $locale->maketext('collapse all'),
Language => $locale->maketext('Language'),
nocookie => $locale->maketext(
'The Navigation Menu below will automatically collapse when pages are loaded. Enable cookies to fix the Navigation Menu functionality.'
),
nojs => $locale->maketext(
'
The Navigation Menu above requires JavaScript to function.
Enable JavaScript to allow the Navigation Menu to function.
Disable CSS to view the Navigation options without JavaScript enabled
'
),
iframe => $locale->maketext(
'This is an iframe, to view it upgrade your browser or enable iframe display.'
),
Code => $locale->maketext('Code'),
Products => $locale->maketext('Products'),
Books => $locale->maketext('Books'),
Versions => $locale->maketext('Versions'),
Packages => $locale->maketext('Packages'),
Total_Languages => $locale->maketext('Total Languages'),
Total_Packages => $locale->maketext('Total Packages'),
Untranslated => $locale->maketext('Untranslated'),
index_javascript => $locale->maketext(
'This web site requires JavaScript and cookies to be enabled to function correctly.'
),
index_toc =>
$locale->maketext('Click here to view a static Table of Contents'),
ProductLinkTitle => $locale->maketext('Information'),
ProductList => $locale->maketext('Product List'),
Hide_Menu => $locale->maketext('Hide Menu'),
Show_Menu => $locale->maketext('Show Menu'),
Formats => $locale->maketext('Formats'),
Knowledge => $locale->maketext('Knowledge'),
Document => $locale->maketext('Document'),
Document_Language => $locale->maketext('Document Language'),
Document_Home => $locale->maketext('Document Home'),
Product_Documentation => $locale->maketext('Product Documentation'),
Support => $locale->maketext('Support'),
SrcIsNewer => $locale->maketext('English is newer'),
SelectYourVersion => $locale->maketext('Select a version'),
SelectYourCategory => $locale->maketext('Select a category'),
ScrollToCategory => $locale->maketext('Scroll to category'),
html_label => $locale->maketext('HTML (Recommended)'),
'html-single_label' => $locale->maketext('Single-page HTML'),
pdf_label => $locale->maketext('PDF'),
epub_label => $locale->maketext('EPUB'),
RssProdTitle =>
$locale->maketext('Subcribe to the RSS feed for this product'),
All => $locale->maketext('All'),
);
sub new {
my ( $class, $arg ) = @_;
my $create = delete $arg->{create} || undef;
my $site_config = delete $arg->{site_config} || $DEFAULT_CONFIG_FILE;
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $config = new Config::Simple();
$config->syntax('http');
$config->read($site_config)
|| croak("Failed to load config file: $site_config");
my $toc_path = $config->param('toc_path')
|| croak(
maketext(
"[_1] is a mandatory field in a site configuration file",
'toc_path'
)
);
my $tmpl_path = $config->param('tmpl_path') || $DEFAULT_TMPL_PATH;
$tmpl_path .= ":$DEFAULT_TMPL_PATH" if ( $config->param('tmpl_path') );
my $def_lang = $config->param('def_lang') || $DEFAULT_LANG;
my $db_file = $config->param('db_file') || croak(
maketext(
"[_1] is a mandatory field in a site configuration file. Check [_2] for validity.",
'db_file',
$site_config
)
);
my $host = $config->param('host') || '/docs';
my $search = $config->param('search') || undef;
my $title = $config->param('title') || 'Documentation';
my $dump = $config->param('dump') || undef;
my $dump_file = $config->param('dump_file') || $DEFAULT_DUMP_FILE;
my $zip_dump = $config->param('zip_dump') || undef;
my $toc_type = $config->param('toc_type') || 'toc';
my $toc_js = $config->param('toc_js') || 'default.js';
my $manual_toc_update = $config->param('manual_toc_update') || 0;
my $debug = $config->param('debug') || 0;
my $footer = $config->param('footer') || "";
my $web_style = $config->param('web_style') || 1;
my $home_link = $config->param('home_link') || undef;
my $self = bless { db_file => $db_file }, $class;
if ($create) {
$self->_create_db();
}
$self->_load_db;
$self->{toc_path} = $toc_path;
$self->{tmpl_path} = $tmpl_path;
$self->{def_lang} = $def_lang;
$self->{host} = $host;
$self->{search} = $search;
$self->{footer} = $footer;
$self->{title} = $title;
$self->{dump} = $dump;
$self->{dump_file} = $dump_file;
$self->{zip_dump} = $zip_dump;
$self->{toc_type} = $toc_type;
$self->{toc_js} = $toc_js;
$self->{manual_toc_update} = $manual_toc_update;
$self->{debug} = $debug;
$self->{web_style} = $web_style;
$self->{home_link} = $home_link;
my $conf = { INCLUDE_PATH => $tmpl_path, ENCODING => 'utf8', };
$conf->{DEBUG} = Template::Constants::DEBUG_VARS if ($debug);
# create Template object
$self->{Template} = Template->new($conf) or croak( Template->error() );
return $self;
}
sub _dbh {
my $self = shift;
return $self->{dbh} if $self->{dbh};
my $db_file = $self->{db_file};
my $attr = { AutoCommit => 1, RaiseError => 0, PrintError => 1 };
my $dbh = DBI->connect( "dbi:SQLite:dbname=$db_file", "", "", $attr );
if ( not( $dbh and ref $dbh ) ) {
croak "Failed to load db file '$db_file'.";
}
## cluck("Connected to DB $db_file\n");
$dbh->{sqlite_unicode} = 1;
$self->{dbh} = $dbh;
}
sub toc_path {
my $self = shift;
return ( $self->{toc_path} );
}
sub _create_db {
my ( $self, $arg ) = @_;
my $force = delete $arg->{force};
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $db_file = $self->{db_file};
if ( -f $db_file && !$force ) {
print("DB file '$db_file' exists, skipping creation.");
return;
}
$self->_dbh->do(<{db_file};
if ( not -f $db_file ) {
croak "DB file '$db_file' not found.";
}
$self->_dbh;
return;
}
sub update_or_add_entry {
my ( $self, $arg ) = @_;
my $language = delete $arg->{language} || croak "language required";
my $product = delete $arg->{product} || croak "product required";
my $version
= defined $arg->{version}
? delete $arg->{version}
: croak "update_or_add_entry: version required";
my $name = delete $arg->{name} || croak "name required";
my $formats = delete $arg->{formats} || croak "formats required";
my $product_label = delete $arg->{product_label};
my $version_label = delete $arg->{version_label};
my $name_label = delete $arg->{name_label};
my $subtitle = delete $arg->{subtitle};
my $abstract = delete $arg->{abstract};
my $sort_order = delete $arg->{sort_order};
my $book_version = delete $arg->{book_version};
my $book_src_lang = delete $arg->{book_src_lang};
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $rc;
my $id = $self->get_entry_id(
{ language => $language,
product => $product,
version => $version,
name => $name,
}
);
if ($id) {
$rc = $self->update_entry(
{ ID => $id,
language => $language,
product => $product,
version => $version,
name => $name,
formats => $formats,
product_label => $product_label,
version_label => $version_label,
name_label => $name_label,
subtitle => $subtitle,
abstract => $abstract,
sort_order => $sort_order,
book_version => $book_version,
book_src_lang => $book_src_lang,
}
);
}
else {
$rc = $self->add_entry(
{ language => $language,
product => $product,
version => $version,
name => $name,
formats => $formats,
product_label => $product_label,
version_label => $version_label,
name_label => $name_label,
subtitle => $subtitle,
abstract => $abstract,
sort_order => $sort_order,
book_version => $book_version,
book_src_lang => $book_src_lang,
}
);
}
return ($rc);
}
sub add_entry {
my ( $self, $arg ) = @_;
my $language = delete $arg->{language} || croak "language required";
my $product = delete $arg->{product} || croak "product required";
my $version
= defined $arg->{version}
? delete $arg->{version}
: croak "add_entry: version required";
my $name = delete $arg->{name} || croak "name required";
my $formats = delete $arg->{formats} || croak "formats required";
my $product_label = delete $arg->{product_label};
my $version_label = delete $arg->{version_label};
my $name_label = delete $arg->{name_label};
my $subtitle = delete $arg->{subtitle};
my $abstract = delete $arg->{abstract};
my $sort_order = delete $arg->{sort_order};
my $book_version = delete $arg->{book_version};
my $book_src_lang = delete $arg->{book_src_lang};
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
# $formats = lc $formats;
$abstract =~ s/\n/ /gm;
my $sql = <_dbh->do(
$sql, undef, $language, $product,
$version, $name, $formats, $product_label,
$version_label, $name_label, $subtitle, $abstract,
$sort_order, $book_version, $book_src_lang
);
}
sub update_entry {
my ( $self, $arg ) = @_;
my $ID = delete $arg->{ID} || croak "ID required";
my $language = delete $arg->{language} || croak "language required";
my $product = delete $arg->{product} || croak "product required";
my $version
= defined $arg->{version}
? delete $arg->{version}
: croak "update_entry: version required";
my $name = delete $arg->{name} || croak "name required";
my $formats = delete $arg->{formats} || croak "formats required";
my $product_label = delete $arg->{product_label};
my $version_label = delete $arg->{version_label};
my $name_label = delete $arg->{name_label};
my $subtitle = delete $arg->{subtitle};
my $abstract = delete $arg->{abstract};
my $sort_order = delete $arg->{sort_order};
my $book_version = delete $arg->{book_version};
my $book_src_lang = delete $arg->{book_src_lang};
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
# $formats = lc $formats;
$abstract =~ s/\n/ /gm;
my $sql = <_dbh->do(
$sql, undef, $language, $product,
$version, $name, $formats, $product_label,
$version_label, $name_label, $subtitle, $abstract,
$sort_order, $book_version, $book_src_lang
);
}
sub del_entry {
my ( $self, $arg ) = @_;
my $language = delete $arg->{language} || croak "language required";
my $product = delete $arg->{product} || croak "product required";
my $version
= defined $arg->{version}
? delete $arg->{version}
: croak "del_entry: version required";
my $name = delete $arg->{name} || croak "name required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $sql = <_dbh->do( $sql, undef, $language, $product, $version,
$name );
}
sub get_entry_id {
my ( $self, $arg ) = @_;
my $language = delete $arg->{language} || croak "language required";
my $product = delete $arg->{product} || croak "product required";
my $version
= defined $arg->{version}
? delete $arg->{version}
: croak "get_entry_id version required";
my $name = delete $arg->{name} || croak "name required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $sql = <_dbh->prepare($sql);
$sth->execute( $language, $product, $version, $name );
my $result = $sth->fetchrow();
return $result;
}
# return a hash of records
sub get_hash_ref {
my ( $self, $arg ) = @_;
my $language = delete $arg->{language}
|| confess "get_hash_ref: language required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $def_lang = $self->{def_lang};
my $direction = 'DESC';
$direction = 'ASC' if ( $def_lang gt $language );
my $sql = <_dbh->prepare($sql);
$sth->execute( $language, $def_lang );
my %list;
while (
my ($id, $lang, $product, $version,
$name, $formats, $product_label, $version_label,
$name_label, $update_date, $subtitle, $abstract,
$sort_order, $book_version, $orig_ver
)
= $sth->fetchrow()
)
{
next
if ( defined $list{$product}{$version}{$name}
and $list{$product}{$version}{$name}{language} ne $lang );
## BUGBUG where to handle this?
foreach my $format ( split( /,/, $formats ) ) {
$list{$product}{$version}{$name}{formats}{$format} = 1;
}
$list{$product}{$version}{$name}{language} = $lang;
$list{$product}{$version}{$name}{version_label} = $version_label
if $version_label;
$list{$product}{$version}{$name}{name_label} = $name_label
if $name_label;
$list{$product}{$version}{$name}{product_label} = $product_label
if $product_label;
$list{$product}{$version}{$name}{update_date} = $update_date
|| '2000-01-01';
$list{$product}{$version}{$name}{subtitle} = $subtitle;
$list{$product}{$version}{$name}{abstract} = $abstract;
$list{$product}{$version}{$name}{sort_order} = ( $sort_order || 50 );
$list{$product}{$version}{$name}{srcnewer}
= !( ( defined($orig_ver) )
&& ( $orig_ver ne '' )
&& ( version_sort( $a = $orig_ver, $b = $book_version ) > 0 ) );
}
$sth->finish();
return ( \%list );
}
sub get_lang_list {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $langs;
my $sql
= qq|SELECT DISTINCT language FROM $DB_NAME where language <> "$self->{def_lang} ORDER BY language "|;
$langs = $self->_dbh->selectall_arrayref($sql);
unless ( $langs->[0] ) {
# No languages found, using default language: [_1]\n
my @langs = ( $self->{def_lang} );
$langs->[0] = \@langs;
}
else {
unshift( @{$langs}, [ $self->{def_lang} ] );
}
return ($langs);
}
sub regen_all_toc {
my ( $self, $arg ) = @_;
my $OUT;
my $force = delete $arg->{force};
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
return if ( $self->{manual_toc_update} && !$force );
my $langs = $self->get_lang_list();
my @fulltoc = ();
my @toc_names = ();
my @urls = ();
my @opds_lang_list = ();
foreach my $lang ( @{$langs} ) {
my %toc;
my @prods = ();
my $products = $self->_regen_toc(
{ language => qq|$lang->[0]|, urls => \@urls } );
# Remove untranslated content from map page.
foreach my $product ( @{$products} ) {
my @versions = ();
foreach my $version ( @{ $product->{versions} } ) {
delete( $version->{untrans_books} );
push( @versions, $version )
if defined( $version->{books} )
&& scalar @{ $version->{books} };
}
if ( scalar @versions ) {
$product->{versions} = \@versions;
push( @prods, $product );
}
}
$toc{products} = \@prods;
$lang->[0] =~ m/^([^-_]*)/;
my $lang_name = code2language($1) || "unknown $1";
if ( $LANG_NAME{ $lang->[0] } ) {
$lang_name = $LANG_NAME{ $lang->[0] };
}
$toc{name} = $lang_name;
$toc{langloc} = $lang->[0];
push( @fulltoc, \%toc );
my %toc_name = ( toc_name => $lang_name );
push( @toc_names, \%toc_name );
my %opds_lang = (
url => qq|$lang->[0]| . '/opds.xml',
id => $self->{host} . '/' . qq|$lang->[0]| . '/opds.xml',
lang => $lang->[0],
title => $lang_name,
content => "",
img => "",
update_date => DateTime->now(),
);
$opds_lang{img}
= $self->{host} . '/'
. qq|$lang->[0]|
. '/images/cover_thumbnail.png'
if ( -f $self->{toc_path} . '/'
. qq|$lang->[0]|
. '/images/cover_thumbnail.png' );
push( @opds_lang_list, \%opds_lang );
}
my $vars = {
static_langs => \@fulltoc,
static_langs_toc => \@toc_names,
};
$self->{Template}->process(
$self->{toc_type} . '.tmpl',
$vars,
$self->{toc_path} . '/toc.html',
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
$vars = ();
$vars = { urls => \@urls, };
$self->{Template}->process(
'Sitemap.tmpl', $vars,
$self->{toc_path} . "/Sitemap",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
# regenerate main index.html
$vars = ();
my $locales = join( ",", map( qq|"$_->[0]"|, @{$langs} ) );
$vars = {
locales => $locales,
title => $self->{title},
def_lang => $self->{def_lang},
index_javascript => $tmpl_strings{index_javascript},
index_toc => $tmpl_strings{index_toc},
};
$self->{Template}->process(
'index.tmpl', $vars,
$self->{toc_path} . "/index.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
# This file contains all the languages.
my $opds_vars;
$opds_vars->{langs} = \@opds_lang_list;
$opds_vars->{update_date} = DateTime->now();
$opds_vars->{self} = $self->{host} . "/opds.xml";
$opds_vars->{id} = $self->{host} . "/opds.xml";
$opds_vars->{title} = $self->{title};
## $opds_vars->{} = ;
$self->{Template}->process(
'opds-langs.tmpl', $opds_vars,
$self->{toc_path} . "/opds.xml",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
$self->xml_dump() if ( $self->{dump} );
$self->splash_pages() if ( $self->{web_style} == 2 );
my $dir = pushd( $self->{toc_path} );
unlink('toc.js');
symlink( $self->{toc_js}, 'toc.js' );
$dir = undef;
return;
}
sub version_sort {
# X or X.Y
if ( $a =~ /^(?:\d+|\d+\.\d+)$/ && $b =~ /^(?:\d+|\d+\.\d+)$/ ) {
return $a <=> $b;
}
# X or X.Y Vs X.Y.Z
elsif ( $a =~ /^(?:\d+|\d+\.\d+)$/ && $b =~ /^(\d+\.\d+)(.+)$/ ) {
if ( $a gt $1 ) {
return 1;
}
else {
return -1;
}
}
# X.Y.Z Vs X or X.Y
elsif ( $b =~ /^(?:\d+|\d+\.\d+)$/ && $a =~ /^(\d+\.\d+)(.+)$/ ) {
if ( $1 ge $b ) {
return 1;
}
else {
return -1;
}
}
# X.Y.Z Vs X.Y.Z
else {
return $a cmp $b;
}
}
sub insensitive_sort {
return ( lc($a) cmp lc($b) );
}
sub _regen_toc {
my ( $self, $arg ) = @_;
my $language = delete $arg->{language}
|| croak "_regen_toc: language required";
my $urls = delete $arg->{urls}
|| croak "_regen_toc: urls required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $vars = {};
$vars->{publican_version} = $Publican::VERSION;
my $default_search = <
SEARCH
my $host = $self->{host};
if ($host) {
$default_search .= <
SEARCH
}
else {
$host = '.';
}
$default_search .= <
SEARCH
my $langs = $self->get_lang_list();
my @tmpl_langs = ();
foreach my $lang ( @{$langs} ) {
my %row_data;
$lang->[0] =~ m/^([^-_]*)/;
my $lang_name = code2language($1) || "unknown $1";
my $selected = '';
if ( $LANG_NAME{ $lang->[0] } ) {
$lang_name = $LANG_NAME{ $lang->[0] };
}
if ( $language eq $lang->[0] ) {
$selected = 'selected="selected"';
}
$row_data{selected} = $selected;
$row_data{lang} = $lang->[0];
$row_data{lang_name} = $lang_name;
push( @tmpl_langs, \%row_data );
}
$vars->{langs} = \@tmpl_langs;
my $list2 = $self->get_hash_ref( { language => "$language" } );
my @products = ();
my $lc_lang = $language;
$lc_lang =~ s/-/_/g;
my $locale = Publican::Localise->get_handle($lc_lang)
|| croak(
"Could not create a Publican::Localise object for language: [_1]",
$language );
$locale->encoding("UTF-8");
$locale->textdomain("publican");
my $search = ( $self->{search} || $default_search );
my $string = $locale->maketext("Search");
$search =~ s/###Search###/$string/g;
$vars->{search} = $search;
foreach my $string ( sort( keys(%tmpl_strings) ) ) {
$vars->{$string} = $locale->maketext( $tmpl_strings{$string} );
$vars->{$string} = decode_utf8( $vars->{$string} )
unless ( is_utf8( $vars->{$string} ) );
}
$vars->{untrans_lang} = $self->{def_lang};
my @opds_prod_list;
foreach my $product ( sort( insensitive_sort keys( %{$list2} ) ) ) {
my @opds_list;
my $product_label = $product;
my %prod_data;
my @versions = ();
if ( -f "$self->{toc_path}/$language/$product/splash.html" ) {
$prod_data{product_icon} = 1;
my $url = {
url => qq|$host/$language/$product/splash.html|,
update_date => ctime(
( stat(
"$self->{toc_path}/$language/$product/splash.html"
)
)[9]
),
};
push( @{$urls}, $url );
}
# else {
$prod_data{product_icon} = 0;
# }
foreach my $version (
reverse( sort( version_sort keys( %{ $list2->{$product} } ) ) ) )
{
my $version_label = $version;
my %ver_data;
my @books = ();
my @untrans_books = ();
my $category = $version_label;
## BUGBUG TODO labels
## It makes more sense to do an SQL query here for the labels instead of
## doing it in the book loop.
if ( -f "$self->{toc_path}/$language/$product/$version/index.html"
)
{
$ver_data{ver_icon} = 1;
my $url = {
url => qq|$host/$language/$product/$version/index.html|,
update_date => ctime(
( stat(
"$self->{toc_path}/$language/$product/$version/index.html"
)
)[9]
),
};
push( @{$urls}, $url );
}
foreach my $book ( i_sort( $list2->{$product}{$version} ) ) {
my $book_label = $book;
my %book_data;
my @types = ();
my $lang = $list2->{$product}{$version}{$book}{language};
## BUGBUG could split formats here
foreach my $type (
sort
keys %{ $list2->{$product}{$version}{$book}{formats} }
)
{
$book_label
= $list2->{$product}{$version}{$book}{name_label}
if ($list2->{$product}{$version}{$book}{name_label}
and $list2->{$product}{$version}{$book}{name_label}
ne $book );
$book_label = decode_utf8($book_label)
unless ( is_utf8($book_label) );
$version_label
= $list2->{$product}{$version}{$book}{version_label}
if (
$list2->{$product}{$version}{$book}{version_label}
and
$list2->{$product}{$version}{$book}{version_label} ne
$version );
$version_label = decode_utf8($version_label)
unless ( is_utf8($version_label) );
$product_label
= $list2->{$product}{$version}{$book}{product_label}
if (
$list2->{$product}{$version}{$book}{product_label}
and
$list2->{$product}{$version}{$book}{product_label} ne
$product );
$product_label = decode_utf8($product_label)
unless ( is_utf8($product_label) );
## debug_msg( "product: $product, version: $version, book: $book, book_label: $book_label, version_label: $version_label, product_label: $product_label \n" );
my %type_data;
$type_data{type} = $type;
$type_data{prep} = './';
$type_data{onclick} = 1;
$type_data{ext} = 'index.html';
if ( $type eq 'pdf' ) {
my @filelist
= File::Find::Rule->file->relative()
->name('*.pdf')
->in(
"$self->{toc_path}/$lang/$product/$version/$type/$book"
);
$type_data{ext} = pop(@filelist);
}
elsif ( $type eq 'txt' ) {
my @filelist
= File::Find::Rule->file->relative()
->name('*.txt')
->in(
"$self->{toc_path}/$lang/$product/$version/$type/$book"
);
$type_data{ext} = pop(@filelist);
}
elsif ( $type eq 'epub' ) {
my @filelist
= File::Find::Rule->file->relative()
->name('*.epub')
->in(
"$self->{toc_path}/$lang/$product/$version/$type/$book"
);
$type_data{ext} = pop(@filelist);
if ( $type_data{ext} ) {
my %opds_url = (
title => "$book_label",
id =>
"$host/$lang/$product/$version/$type/$book/"
. $type_data{ext},
lang => $language,
update_date =>
$list2->{$product}{$version}{$book}
{update_date},
url =>
"$host/$lang/$product/$version/$type/$book/"
. $type_data{ext},
category => $category,
summary => (
$list2->{$product}{$version}{$book}
{subtitle} || ""
),
content => (
$list2->{$product}{$version}{$book}
{abstract} || ""
),
);
$category = "";
$opds_url{title} =~ s/_/ /g;
my $img
= "/$lang/$product/$version/html/$book/images/cover_thumbnail.png";
$opds_url{img} = $self->{host} . $img
if ( -f $self->{toc_path} . $img );
push( @opds_list, \%opds_url );
}
## hmm epub link for safari ...
## $type_data{prep} = "epub://$host/docs/$lang/";
$type_data{onclick} = 0;
}
if ( defined $type_data{ext} and $type_data{ext} ) {
my $url = {
url =>
qq|$host/$lang/$product/$version/$type/$book/|
. $type_data{ext},
update_date => $list2->{$product}{$version}{$book}
{update_date},
};
push( @{$urls}, $url ) if ( $lang eq $language );
}
else {
print( STDERR
"ERROR: bogus entry found in DB: $lang/$product/$version/$type/$book\n"
) if ( $self->{debug} );
}
push( @types, \%type_data );
}
$book_data{book} = $book;
$book_data{book_clean} = $book_label;
$book_data{book_clean} =~ s/_/ /g;
$book_data{types} = \@types;
foreach my $format (
sort( insensitive_sort keys(
%{ $list2->{$product}{$version}{$book}{formats}
}
) )
)
{
$book_data{base_format} = $format;
if ( $format =~ m/^html/ ) {
last;
}
}
if ( $lang eq $language ) {
push( @books, \%book_data );
}
else {
push( @untrans_books, \%book_data );
}
}
$ver_data{version} = $version;
$ver_data{version_label} = $version_label;
$ver_data{books} = \@books;
$ver_data{untrans_books} = \@untrans_books
if scalar @untrans_books;
push( @versions, \%ver_data );
}
$prod_data{prod_link_title} = $tmpl_strings{ProductLinkTitle};
$prod_data{product} = $product;
$prod_data{product_clean} = $product_label;
$prod_data{product_clean} =~ s/_/ /g;
$prod_data{versions} = \@versions;
push( @products, \%prod_data );
# This file contains books for all versions of a product.
my $opds_vars;
$opds_vars->{urls} = \@opds_list;
$opds_vars->{update_date} = DateTime->now();
$opds_vars->{self} = "$host/$language/opds-$product.xml";
$opds_vars->{id} = "$host/$language/opds-$product.xml";
$opds_vars->{title} = $prod_data{product_clean};
## $opds_vars->{} = ;
$self->{Template}->process(
'opds.tmpl', $opds_vars,
$self->{toc_path} . "/$language/opds-$product.xml",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
my %opds_p_url = (
title => $prod_data{product_clean},
id => "$host/$language/$product/opds-$product.xml",
lang => $language,
update_date => DateTime->now(),
url => "opds-$product.xml",
content => "",
);
my $img = "/$language/$product/images/cover_thumbnail.png";
$opds_p_url{img} = $self->{host} . $img
if ( -f $self->{toc_path} . $img );
push( @opds_prod_list, \%opds_p_url );
}
$vars->{products} = \@products;
if ( $self->{web_style} == 1 ) {
$self->{Template}->process(
'toc.tmpl', $vars,
$self->{toc_path} . "/$language/toc.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
}
else {
unlink( $self->{toc_path} . "/$language/toc.html" )
if ( -f $self->{toc_path} . "/$language/toc.html" );
}
# This file contains all products for this language.
my $opds_vars;
$opds_vars->{products} = \@opds_prod_list;
$opds_vars->{update_date} = DateTime->now();
$opds_vars->{self} = "$host/$language/opds.xml";
$opds_vars->{id} = "$host/$language/opds.xml";
$opds_vars->{title} = $tmpl_strings{ProductList};
## $opds_vars->{} = ;
$self->{Template}->process(
'opds-prods.tmpl', $opds_vars,
$self->{toc_path} . "/$language/opds.xml",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
if ( $self->{web_style} == 1 ) {
$vars->{splash}
= $self->get_splash(
{ path => $self->{toc_path} . "/$language" } );
$vars->{host} = $host;
$vars->{lang} = $language;
$vars->{title} = $self->{title};
$self->{Template}->process(
'language_index_style_1.tmpl', $vars,
$self->{toc_path} . "/$language/index.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
}
return \@products;
}
sub get_splash {
my ( $self, $arg ) = @_;
my $path = delete $arg->{path}
|| croak "get_splash: file required";
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $html;
my $file = $path . "/splash.html";
if ( -f ($file) ) {
my $tree = HTML::TreeBuilder->new();
my $fh;
open( $fh, "<:encoding(UTF-8)", $file )
|| croak(
maketext( "Can't open file for html input: [_1]", $! ) );
$tree->parse_file($fh);
my $node = $tree->look_down( 'class', qr/article/ );
$html = $node->as_HTML() if ($node);
}
return ($html);
}
sub report {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $sql = <_dbh->selectall_arrayref($sql)->[0];
my $report = "\nThe database contains books that cover ";
$report .= $counts->[1] . " languages, ";
$report .= $counts->[2] . " products, ";
$report .= " totaling " . $counts->[0] . " packages\n";
return ($report);
}
sub validate {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
## Validate database entries have RPMs
my $sql = <_dbh->prepare($sql);
$sth->execute();
while ( my ( $product, $name, $version, $language ) = $sth->fetchrow() ) {
my $package = sprintf( '%s-%s-%s-web-%s', $product, $name, $version,
$language );
system( 'rpm', '-q', $package, '--queryformat=""' );
}
## Validate RPMs have database entries
my $command = 'rpm -q --whatrequires publican-website';
foreach my $rpm (`$command`) {
chomp($rpm);
$rpm =~ /^([^-]*)-([^-]*)-([^-]*)-web-(..-..)/;
my ( $product, $name, $version, $language );
$product = $1;
$name = $2;
$version = $3;
$language = $4;
my $sql = <_dbh->prepare($sql);
$sth->execute( $product, $name, $version, $language );
my $count = $sth->fetchrow();
print "Missing database entry for $rpm\n" unless ($count);
}
return;
}
sub xml_dump {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $results = $self->_dbh->selectall_arrayref( 'SELECT * FROM books',
{ Columns => {} } );
my %site = (
host => $self->{host},
def_lang => $self->{def_lang},
);
my $xml = XMLout( { site => \%site, record => $results }, NoAttr => 1 );
my $OUT_FILE;
open( $OUT_FILE, '>:encoding(UTF-8)', $self->{dump_file} )
|| croak(
maketext( "Could not open dump file for output: [_1]", $@ ) );
print( $OUT_FILE "\n" );
print( $OUT_FILE $xml );
close($OUT_FILE);
my $zip_file = $self->{dump_file} . '.zip';
unlink $zip_file if ( -f $zip_file );
if ( $self->{zip_dump} ) {
my $zip = Archive::Zip->new();
my $member = $zip->addFile( $self->{dump_file} );
$member->desiredCompressionLevel(9);
$zip->writeToFileNamed($zip_file) == AZ_OK
|| croak( maketext("dump file zip creation failed.") );
}
return;
}
sub splash_pages {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $host = $self->{host};
my $langs = $self->get_lang_list();
my $def_lang = $self->{def_lang};
my @all_lang_array;
# remove duplicate ...
shift @$langs;
foreach my $lang_t (@$langs) {
my %lang_hash = (
lang => $lang_t->[0],
lang_name => $self->lang_name( { lang => $lang_t->[0] } )
);
push( @all_lang_array, \%lang_hash );
}
foreach my $lang ( @{$langs} ) {
my $language = $lang->[0];
my $direction = 'DESC';
$direction = 'ASC' if ( $def_lang lt $language );
my $sql = < ?
AND books2.language <> books.language
)
ORDER BY books2.language
) as langs
FROM books
LEFT JOIN books as b2 ON
books.book_src_lang = b2.language
AND books.product = b2.product
AND books.version = b2.version
AND books.name =b2.name
WHERE books.language = ? OR books.language = ?
GROUP BY books.product, books.version, books.name, books.language
ORDER BY books.product, books.version, books.name, books.language $direction
)
GROUP BY product, version, name
ORDER BY product, version desc, name
SQL
## BUGBUG cache this query?
my $sth = $self->_dbh->prepare($sql);
$sth->execute( $language, $def_lang, $language );
my %book_list;
my $product = "";
my $product_label = "";
my $version = "";
my $version_label = "";
my %book_ver_list;
my %labels;
my $lc_lang = $language;
$lc_lang =~ s/-/_/g;
my $locale = Publican::Localise->get_handle($lc_lang)
|| croak(
"Could not create a Publican::Localise object for language: [_1]",
$lang
);
$locale->encoding("UTF-8");
$locale->textdomain("publican");
my $OUT_FILE;
open( $OUT_FILE, '>', $self->{toc_path} . '/search.html' )
|| croak(
maketext( "Could not open search file for output: [_1]", $@ ) );
print( $OUT_FILE $self->search_string() );
close($OUT_FILE);
open( $OUT_FILE, '>', $self->{toc_path} . '/footer.html' )
|| croak(
maketext( "Could not open footer file for output: [_1]", $@ ) );
print( $OUT_FILE $self->{footer} );
close($OUT_FILE);
my $vars;
foreach my $string ( sort( keys(%tmpl_strings) ) ) {
$vars->{$string} = $locale->maketext( $tmpl_strings{$string} );
$vars->{$string} = decode_utf8( $vars->{$string} )
unless ( is_utf8( $vars->{$string} ) );
}
while ( my $record = $sth->fetchrow_hashref ) {
# Bash UTF8 into DB fields
foreach my $key (
qw(product version name language name_label version_label product_label abstract subtitle )
)
{
$record->{$key} = decode_utf8( $record->{$key} )
unless ( is_utf8( $record->{$key} ) );
}
if ( $product ne '' and ( $product ne $record->{product} ) ) {
# write our books_index.tmpl
## BUGBUG might be better off looping again at end to ensure translated labels are in place
# write our versions_index.tmpl & books_menu.tmpl
$self->write_version_index(
{ lang => $language,
product => $product,
version => $version,
langs => \@all_lang_array,
book_list => $book_list{$product}{$version},
labels => \%labels,
trans_strings => $vars,
book_ver_list => \%book_ver_list,
}
);
# write our products_index.tmpl & versions_menu.tmpl
$self->write_product_index(
{ lang => $language,
product => $product,
book_list => $book_list{$product},
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
book_ver_list => \%book_ver_list,
}
);
# write out products_menu.tmpl
$self->write_product_menu(
{ lang => $language,
book_list => \%book_list,
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
}
);
}
elsif ( $version ne '' and ( $version ne $record->{version} ) ) {
# write our versions_index.tmpl & books_menu.tmpl
$self->write_version_index(
{ lang => $language,
product => $product,
version => $version,
book_list => $book_list{$product}{$version},
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
book_ver_list => \%book_ver_list,
}
);
}
$product = $record->{product};
if ( $record->{product_label} ) {
$product_label = $record->{product_label};
$product_label =~ s/_/ /g;
$labels{$product}{label} = $product_label;
}
else {
$product_label = $record->{product};
$product_label =~ s/_/ /g;
}
$labels{$product}{label} = $product_label
if ( !defined( $labels{$product}{label} ) );
$version = $record->{version};
if ( $record->{version_label} ) {
$version_label = $record->{version_label};
$version_label =~ s/_/ /g;
$labels{$product}{$version}{label} = $version_label;
}
else {
$version_label = $record->{version};
$version_label =~ s/_/ /g;
}
$labels{$product}{$version}{label} = $version_label
if ( !defined( $labels{$product}{$version}{label} ) );
my @lang_array;
if ( $record->{langs} ) {
foreach my $trans ( sort( split( /,/, $record->{langs} ) ) ) {
my %lang_hash = (
lang => $trans,
lang_name => $self->lang_name( { lang => $trans } )
);
push( @lang_array, \%lang_hash );
}
}
# write out book_lang_menu.tmpl
my $book_lang_vars;
$book_lang_vars->{host} = $host;
$book_lang_vars->{toc_path} = $self->{toc_path};
$book_lang_vars->{toc_path} = $self->{toc_path};
$book_lang_vars->{product} = $record->{product};
$book_lang_vars->{product_label}
= ( $record->{product_label} || $record->{product} );
$book_lang_vars->{version} = $record->{version};
$book_lang_vars->{version_label}
= ( $record->{version_label} || $record->{version} );
$book_lang_vars->{lang} = $record->{language};
$book_lang_vars->{lang_name}
= $self->lang_name( { lang => $language } );
$book_lang_vars->{book} = $record->{name};
$book_lang_vars->{book_label}
= ( $record->{name_label} || $record->{name} );
$book_lang_vars->{abstract} = $record->{abstract};
$book_lang_vars->{trans_strings} = $vars;
$book_lang_vars->{subtitle} = $record->{subtitle};
$book_lang_vars->{book_label} =~ s/_/ /g;
$book_lang_vars->{sort_order} = ( $record->{sort_order} || 50 );
foreach my $format (
sort ( insensitive_sort split( /,/, $record->{formats} ) ) )
{
$book_lang_vars->{base_format} = $format;
if ( $format =~ m/^html/ ) {
last;
}
}
if ( defined $record->{name_label}
&& $record->{name_label} ne "" )
{
$book_lang_vars->{book_clean} = $record->{name_label};
}
else {
$book_lang_vars->{book_clean} = $record->{name};
}
$book_lang_vars->{book_clean} =~ s/_/ /g;
$book_lang_vars->{book_clean} =~ s/^\s*//g;
$book_lang_vars->{langs} = \@lang_array;
if ( ( defined( $record->{orig_ver} ) )
&& ( $record->{orig_ver} ne '' ) )
{
my $val = version_sort(
$a = $record->{orig_ver},
$b = $record->{book_version}
);
$book_lang_vars->{srcnewer} = ( $val > 0 );
}
$self->{Template}->process(
'books_lang_menu.tmpl',
$book_lang_vars,
$self->{toc_path}
. "/$language/$record->{product}/$record->{version}/$record->{name}/lang_menu.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
$book_list{$product}{$version}{ $record->{name} }
= $book_lang_vars;
my %formats;
map( $formats{$_} = 1, split( /,/, $record->{formats} ) );
my @forder = qw(html html-single epub pdf);
foreach my $format (@forder) {
if ( defined( $formats{$format} ) ) {
push(
@{ $book_ver_list{$product}{ $record->{name} }
{$version}{formats}
},
$format
);
delete( $formats{$format} );
}
}
push(
@{ $book_ver_list{$product}{ $record->{name} }{$version}
{formats}
},
keys(%formats)
);
$book_list{$product}{$version}{ $record->{name} }{formats}
= $book_ver_list{$product}{ $record->{name} }{$version}
{formats};
}
# write our books_index.tmpl
$self->write_books_index(
{ lang => $language,
book_ver_list => \%book_ver_list,
book_list => \%book_list,
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
}
);
# write our versions_index.tmpl & books_menu.tmpl
$self->write_version_index(
{ lang => $language,
product => $product,
version => $version,
book_list => $book_list{$product}{$version},
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
book_ver_list => \%book_ver_list,
}
);
# write our products_index.tmpl & versions_menu.tmpl
$self->write_product_index(
{ lang => $language,
product => $product,
book_list => $book_list{$product},
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
book_ver_list => \%book_ver_list,
}
);
# write out products_menu.tmpl
$self->write_product_menu(
{ lang => $language,
book_list => \%book_list,
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
}
);
# write our language_index.tmpl
$self->write_language_index(
{ lang => $language,
book_list => \%book_list,
langs => \@all_lang_array,
labels => \%labels,
trans_strings => $vars,
}
);
# write our labels.tmpl
$self->write_language_labels(
{ lang => $language,
labels => \%labels,
trans_strings => $vars,
book_list => \%book_list,
}
);
}
return;
}
sub write_version_index {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang}
|| croak "write_version_index: lang required";
my $book_list = delete $arg->{book_list}
|| croak "write_version_index: book_list required";
my $product = delete $arg->{product}
|| croak "write_version_index: product required";
my $version = delete $arg->{version}
|| croak "write_version_index: version required";
my $langs = delete $arg->{langs}
|| croak "write_version_index: langs required";
my $labels = delete $arg->{labels}
|| croak "write_version_index: labels required";
my $trans_strings = delete $arg->{trans_strings}
|| croak "write_version_index: trans_strings required";
my $book_ver_list = delete $arg->{book_ver_list}
|| croak "write_version_index: book_ver_list required";
# my $ = delete $arg->{} || croak "_regen_toc: required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $file = Publican::ConfigData->config('templates')
. "/groups/$lang/$product/External_Links.xml";
if ( -f $file ) {
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
eval { $xml_doc->parse_file($file); };
croak( maketext( "Can't open file '[_1]' [_2]", $file, $@ ) ) if ($@);
foreach my $node (
$xml_doc->look_down( '_tag' => 'member', version => $version ) )
{
my $book_lang_vars;
$book_lang_vars->{product} = $product;
$book_lang_vars->{version} = $version;
$book_lang_vars->{lang} = $lang;
$book_lang_vars->{name} = $node->attr('title');
$book_lang_vars->{subtitle} = $node->as_trimmed_text();
$book_lang_vars->{sort_order} = ( $node->attr('role') || 50 );
$book_lang_vars->{external} = 1;
$book_lang_vars->{uri} = $node->attr('href');
$book_list->{ $node->attr('title') } = $book_lang_vars;
}
}
my $host = $self->{host};
my $index_vars;
$index_vars->{style} = $self->{web_style};
$index_vars->{v_sort} = \&v_sort;
$index_vars->{i_sort} = \&i_sort;
$index_vars->{product} = $product;
$index_vars->{version} = $version;
$index_vars->{host} = $host;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{book_list} = $book_list;
$index_vars->{lang} = $lang;
$index_vars->{langs} = $langs;
$index_vars->{search} = $self->search_string();
$index_vars->{labels} = $labels;
$index_vars->{publican_version} = $Publican::VERSION;
$index_vars->{trans_strings} = $trans_strings;
$index_vars->{footer} = $self->{footer};
$index_vars->{site_title} = $self->{title};
$index_vars->{book_ver_list} = $book_ver_list;
$index_vars->{splash} = $self->get_splash(
{ path => $self->{toc_path} . "/$lang/$product/$version" } );
$index_vars->{home_link} = $self->{home_link};
$self->{Template}->process(
'versions_index.tmpl', $index_vars,
$self->{toc_path} . "/$lang/$product/$version/index.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
my @books = sort( insensitive_sort keys( %{$book_list} ) );
$index_vars->{books} = \@books;
$self->{Template}->process(
'books_menu.tmpl', $index_vars,
$self->{toc_path} . "/$lang/$product/$version/books_menu.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
return;
}
sub write_product_index {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang}
|| croak "write_product_index: lang required";
my $book_list = delete $arg->{book_list}
|| croak "write_product_index: book_list required";
my $product = delete $arg->{product}
|| croak "write_product_index: product required";
my $langs = delete $arg->{langs}
|| croak "write_product_index: langs required";
my $labels = delete $arg->{labels}
|| croak "write_product_index: labels required";
my $trans_strings = delete $arg->{trans_strings}
|| croak "write_product_index: trans_strings required";
my $book_ver_list = delete $arg->{book_ver_list}
|| croak "write_product_index: book_ver_list required";
# my $ = delete $arg->{} || croak "_regen_toc: required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $host = $self->{host};
my $index_vars;
$index_vars->{style} = $self->{web_style};
$index_vars->{product} = $product;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{host} = $host;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{book_list} = $book_list;
$index_vars->{lang} = $lang;
$index_vars->{v_sort} = \&v_sort;
$index_vars->{i_sort} = \&i_sort;
$index_vars->{search} = $self->search_string();
$index_vars->{langs} = $langs;
$index_vars->{labels} = $labels;
$index_vars->{trans_strings} = $trans_strings;
$index_vars->{footer} = $self->{footer};
$index_vars->{site_title} = $self->{title};
$index_vars->{book_ver_list} = $book_ver_list;
$index_vars->{splash}
= $self->get_splash(
{ path => $self->{toc_path} . "/$lang/$product" } );
$index_vars->{categories}
= ( -d "$DEFAULT_TMPL_PATH/groups/$lang/$product" );
$index_vars->{home_link} = $self->{home_link};
$self->{Template}->process(
'products_index.tmpl', $index_vars,
$self->{toc_path} . "/$lang/$product/index.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
my @versions = reverse( sort( version_sort keys( %{$book_list} ) ) );
$index_vars->{versions} = \@versions;
$self->{Template}->process(
'versions_menu.tmpl', $index_vars,
$self->{toc_path} . "/$lang/$product/versions_menu.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
return;
}
sub write_product_menu {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang}
|| croak "write_product_menu: lang required";
my $book_list = delete $arg->{book_list}
|| croak "write_product_menu: book_list required";
my $langs = delete $arg->{langs}
|| croak "write_product_menu: langs required";
my $labels = delete $arg->{labels}
|| croak "write_product_menu: labels required";
my $trans_strings = delete $arg->{trans_strings}
|| croak "write_product_menu: trans_strings required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $host = $self->{host};
my @products = sort( insensitive_sort keys( %{$book_list} ) );
my $index_vars;
$index_vars->{style} = $self->{web_style};
$index_vars->{host} = $host;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{book_list} = $book_list;
$index_vars->{lang} = $lang;
$index_vars->{products} = \@products;
$index_vars->{search} = $self->search_string();
$index_vars->{langs} = $langs;
$index_vars->{labels} = $labels;
$index_vars->{trans_strings} = $trans_strings;
$index_vars->{footer} = $self->{footer};
$index_vars->{site_title} = $self->{title};
$index_vars->{home_link} = $self->{home_link};
## BUGBUG handle product labels
$self->{Template}->process(
'products_menu.tmpl', $index_vars,
$self->{toc_path} . "/$lang/products_menu.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
return;
}
sub v_sort {
my $hash = shift;
return ( reverse( sort( version_sort keys( %{$hash} ) ) ) );
}
sub i_sort {
my $hash = shift;
return (
sort( { if ( ( $hash->{$a}->{sort_order} || 50 )
!= ( $hash->{$b}->{sort_order} || 50 ) )
{
( $hash->{$a}->{sort_order} || 50 )
<=> ( $hash->{$b}->{sort_order} || 50 );
}
else { lc($a) cmp lc($b) }
} keys( %{$hash} ) )
);
}
sub write_language_index {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang}
|| croak "write_language_index: lang required";
my $book_list = delete $arg->{book_list}
|| croak "write_language_index: book_list required";
my $langs = delete $arg->{langs}
|| croak "write_language_index: langs required";
my $labels = delete $arg->{labels}
|| croak "write_language_index: labels required";
my $trans_strings = delete $arg->{trans_strings}
|| croak "write_language_index: trans_strings required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $host = $self->{host};
my @products = sort( insensitive_sort keys( %{$book_list} ) );
my $index_vars;
$index_vars->{style} = $self->{web_style};
$index_vars->{host} = $host;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{book_list} = $book_list;
$index_vars->{lang} = $lang;
$index_vars->{products} = \@products;
$index_vars->{v_sort} = \&v_sort;
$index_vars->{i_sort} = \&i_sort;
$index_vars->{title} = $self->{title};
$index_vars->{search} = $self->search_string();
$index_vars->{langs} = $langs;
$index_vars->{labels} = $labels;
$index_vars->{trans_strings} = $trans_strings;
$index_vars->{footer} = $self->{footer};
$index_vars->{site_title} = $self->{title};
$index_vars->{splash}
= $self->get_splash( { path => $self->{toc_path} . "/$lang" } );
$index_vars->{home_link} = $self->{home_link};
$self->{Template}->process(
'language_index.tmpl', $index_vars,
$self->{toc_path} . "/$lang/index.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
return;
}
sub write_language_labels {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang}
|| croak "write_language_labels: lang required";
my $labels = delete $arg->{labels}
|| croak "write_language_labels: labels required";
my $book_list = delete $arg->{book_list}
|| croak "write_language_labels: book_list required";
my $trans_strings = delete $arg->{trans_strings}
|| croak "write_language_index: trans_strings required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $host = $self->{host};
my $index_vars;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{style} = $self->{web_style};
$index_vars->{lang} = $lang;
$index_vars->{labels} = $labels;
$index_vars->{trans_strings} = $trans_strings;
$index_vars->{book_list} = $book_list;
$index_vars->{site_title} = $self->{title};
$index_vars->{home_link} = $self->{home_link};
## BUGBUG handle product labels
$self->{Template}->process(
'labels.tmpl', $index_vars,
$self->{toc_path} . "/$lang/labels.js",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
return;
}
sub write_books_index {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang}
|| croak "write_language_index: lang required";
my $book_ver_list = delete $arg->{book_ver_list}
|| croak "write_language_index: book_ver_list required";
my $book_list = delete $arg->{book_list}
|| croak "write_language_index: book_list required";
my $langs = delete $arg->{langs}
|| croak "write_language_index: langs required";
my $labels = delete $arg->{labels}
|| croak "write_language_index: labels required";
my $trans_strings = delete $arg->{trans_strings}
|| croak "write_language_index: trans_strings required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $host = $self->{host};
foreach my $product ( keys( %{$book_ver_list} ) ) {
foreach my $book ( keys( %{ $book_ver_list->{$product} } ) ) {
my @versions
= reverse(
sort( version_sort
keys( %{ $book_ver_list->{$product}{$book} } ) ) );
foreach my $version (@versions) {
my $index_vars;
$index_vars->{style} = $self->{web_style};
$index_vars->{host} = $host;
$index_vars->{toc_path} = $self->{toc_path};
$index_vars->{book} = $book_list->{$product}{$version}{$book};
$index_vars->{lang} = $lang;
$index_vars->{langs} = $langs;
$index_vars->{product} = $product;
$index_vars->{version} = $version;
$index_vars->{versions} = \@versions;
$index_vars->{formats}
= $book_ver_list->{$product}{$book}{$version}{formats};
$index_vars->{search} = $self->search_string();
$index_vars->{labels} = $labels;
$index_vars->{trans_strings} = $trans_strings;
$index_vars->{footer} = $self->{footer};
$index_vars->{site_title} = $self->{title};
$index_vars->{home_link} = $self->{home_link};
$self->{Template}->process(
'books_index.tmpl',
$index_vars,
$self->{toc_path}
. "/$lang/$product/$version/$book/index.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
$self->{Template}->process(
'books_format_menu.tmpl',
$index_vars,
$self->{toc_path}
. "/$lang/$product/$version/$book/format_menu.html",
binmode => ':encoding(UTF-8)'
) or croak( $self->{Template}->error() );
}
}
}
return;
}
sub lang_name {
my ( $self, $arg ) = @_;
my $lang = delete $arg->{lang} || croak "_regen_toc: lang required";
if ( %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
$lang =~ m/^([^-_]*)/;
my $lang_name = code2language($1) || "unknown $1";
if ( $LANG_NAME{$lang} ) {
$lang_name = $LANG_NAME{$lang};
}
return ($lang_name);
}
sub search_string {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $default_search = <
SEARCH
my $host = $self->{host};
if ($host) {
$default_search .= <
SEARCH
}
else {
$host = '.';
}
$default_search .= <
SEARCH
my $search = ( $self->{search} || $default_search );
my $string = $locale->maketext("Search");
$search =~ s/###Search###/$string/g;
return ($search);
}
sub MigrateDB {
my ( $self, $arg ) = @_;
if ( $arg && %{$arg} ) {
croak "unknown args: " . join( ", ", keys %{$arg} );
}
my $tmpname = $DB_NAME . "_bak";
$self->_dbh->do("ALTER TABLE $DB_NAME RENAME TO $tmpname");
$self->_create_db( { force => 1 } );
my $sql = <_dbh->do($sql);
return;
}
sub site_params_as_docbook {
my ($web_list) = @_;
foreach my $key ( sort( keys(%PARAMS) ) ) {
my $entry = XML::Element->new_from_lol(
[ 'varlistentry', { id => "site_$key" }, [ 'term', "$key" ] ] );
$web_list->push_content($entry);
my $item = XML::Element->new_from_lol(
[ 'listitem', [ 'para', $PARAMS{$key}->{descr} ] ] );
$entry->push_content($item);
if ( defined( $PARAMS{$key}->{default} ) ) {
my $def = XML::Element->new_from_lol(
[ 'para',
maketext(
"The default value for this parameter is: [_1]",
$PARAMS{$key}->{default}
)
]
);
$item->push_content($def);
}
if ( defined( $PARAMS{$key}->{constraint} ) ) {
my $constraint = XML::Element->new_from_lol(
[ 'para',
maketext(
"This parameter is constrained with the following regular expression: [_1]",
$PARAMS{$key}->{constraint}
)
]
);
$item->push_content($constraint);
}
if ( defined( $PARAMS{$key}->{not_for} ) ) {
my $info = XML::Element->new_from_lol(
[ 'tip',
[ 'para',
maketext(
"This field is not supported for: [_1].",
$PARAMS{$key}->{not_for}
)
]
]
);
$item->push_content($info);
}
if ( defined( $PARAMS{$key}->{alert} ) ) {
my $warn = XML::Element->new_from_lol(
[ 'warning', [ 'para', $PARAMS{$key}->{alert} ] ] );
$item->push_content($warn);
}
}
}
1; # Magic true value required at end of module
__END__
=encoding utf8
=head1 NAME
Publican::WebSite - Manage a documentation website
=head1 SYNOPSIS
use Publican::WebSite;
=head1 DESCRIPTION
Builds the static navgation content for a Publican Web Site.
=head1 INTERFACE
=head2 new
Create a Publican::WebSite object...
=head2 add_entry
Add an entry to the current Publican::WebSite DB...
Returns number of rows added. Should be 1 for success, 0 for failure.
=head2 update_entry
Update an existing entry in the current Publican::WebSite DB...
Returns number of rows added. Should be 1 for success, 0 for failure.
=head2 update_or_add_entry
Update an existing entry if it esists, else create a new entry.
=head2 del_entry
Delete an entry from the current Publican::WebSite DB...
Returns number of rows deleted. Should be 1 for success, 0 for failure.
=head2 get_entry_id
Get the ID of a book from the Publican::WebSite DB.
Returns the ID or NULL.
=head2 get_hash_ref
Returns a reference to a has of all books for the selected language.
=head2 get_lang_list
Returns an array ref of distinct, sorted, languages.
=head2 regen_all_toc
Update the toc html files for every language.
=head2 report
Returns a string containing the current database statistics.
=head2 validate
Validate the database entries against the RPM database.
TODO should also/instead compare entires aginst web site files?
=head2 v_sort
Sort version strings in to correct order, handles X, X.Y, and X.Y.Z formats.
=head2 i_sort
Sort strings case insensitvly.
=head2 toc_path
Return the full toc path.
=head2 xml_dump
Generate an XML dump, and a zip of the dump if required, of the Database.
=head2 search_string
Returns a string for the web page search box.
=head2 lang_name
Returns a string of the localise name for a language. e.g. fr-FR => FranУЇais
=head2 splash_pages
Main function for generating splash pages for web 2 style.
=head2 write_books_index
Writes an index page for a book for web 2 style.
=head2 write_language_index
Writes an index page for a language for web 2 style.
=head2 write_product_index
Writes an index page for a product for web 2 style.
=head2 write_product_menu
Writes a menu page for a product for web 2 style.
=head2 write_version_index
Writes an index page for a for web 2 style.
=head2 write_language_labels
Writes a javascript file with an associative array of labels.
=head2 MigrateDB
Migrate a website DataBase from Publican < 3 to Publican 3.
=head2 insensitive_sort
Sort strings in a case insensitive order.
=head2 version_sort
Sort version strings in correct order. Handles X Vs X.Y Vs X.Y.Z.
=head2 get_splash
Returns the splash page header as a HTML chunk.
=head2 site_params_as_docbook
Returns the site paramaters as a docbook chunk, used for documeting options.
=head1 AUTHOR
Jeff Fearn C<< >>
=head1 LICENCE AND COPYRIGHT
Copyright (c) 2007, Jeff Fearn C<< >>. All rights reserved.
This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L.
=head1 DISCLAIMER OF WARRANTY
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
NECESSARY SERVICING, REPAIR, OR CORRECTION.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
Translate.pm 000444 041472 041472 106510 12555605450 20740 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::Translate;
use utf8;
use strict;
use warnings;
use 5.008;
use Carp qw(carp croak cluck);
use Publican;
use Publican::Builder;
use Publican::Localise;
use File::Path;
use Term::ANSIColor qw(:constants);
use DateTime;
use Locale::PO 0.24;
use XML::TreeBuilder;
use String::Similarity;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
# What tags do we translate?
my $TRANSTAGS
= qr/^(?:ackno|bridgehead|caption|conftitle|contrib|entry|firstname|glossentry|indexterm|jobtitle|keyword|label|lastname|lineannotation|lotentry|member|orgdiv|orgname|othername|para|phrase|productname|refclass|refdescriptor|refentrytitle|refmiscinfo|refname|refpurpose|releaseinfo|revremark|screeninfo|secondaryie|seealsoie|seeie|seg|segtitle|simpara|subtitle|surname|td|term|termdef|tertiaryie|textobject|th|title|titleabbrev|screen|programlisting|literallayout|simplelist)$/;
# Blocks that contain translatable tags that need to be kept inline
my $IGNOREBLOCKS
= qr/^(?:footnote|citerefentry|indexterm|orgname|productname|phrase|textobject)$/;
# Preserve white space in these tags
my $VERBATIM = qr/^(?:screen|programlisting|literallayout|simplelist)$/;
=head1 NAME
Publican::Translate - Module for manipulating POT and PO files.
=head1 SYNOPSIS
use Publican::Translate;
my $po = Publican::Translate->new();
$po->update_pot();
$po->update_po({ langs => 'fr-FR,de-DE' });
$po->update_po({ langs => 'all' });
$po->merge_xml({ lang => 'fr-FR' });
=head1 DESCRIPTION
Creates, updates and merges POT and PO files for Publican projects.
=head1 INTERFACE
=cut
=head2 new
Create a new Publican::Translate object.
=cut
sub new {
my ( $this, $args ) = @_;
my $showfuzzy = delete( $args->{showfuzzy} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $class = ref($this) || $this;
my $self = bless {}, $class;
my $publican = Publican->new();
$self->{publican} = $publican;
$self->{showfuzzy} = $showfuzzy;
return $self;
}
=head2 trans_drop
Snapshot the source to give translation a stable base.
=cut
sub trans_drop {
my ($self) = shift();
my $trans_drop = 'trans_drop';
mkdir $trans_drop if ( !-d $trans_drop );
my $source_dir = $self->{publican}->param('xml_lang');
my @files = dir_list( $source_dir, '*' );
foreach my $file ( sort(@files) ) {
logger( "\t" . maketext( "Processing file [_1]", $file ) . "\n" );
my $new_file = $file;
$new_file =~ s/^$source_dir/$trans_drop/;
$new_file =~ m|^(.*)/[^/]+$|;
my $path = $1;
mkpath($path) if ( !-d $path );
fcopy( $file, $new_file );
}
return;
}
=head2 update_pot
Update the pot files
=cut
sub update_pot {
my ($self) = shift();
mkdir 'pot' if ( !-d 'pot' );
my $source_dir = $self->{publican}->param('xml_lang');
$source_dir = 'trans_drop' if ( -d 'trans_drop' );
my $extras = $self->{publican}->param('extras_dir');
my @xml_files = dir_list( $source_dir, '*.xml' );
foreach my $xml_file ( sort(@xml_files) ) {
next if ( $xml_file =~ m|$source_dir/$extras/| );
next if ( $xml_file =~ m|$source_dir/Legal_Notice.xml| );
logger( "\t" . maketext( "Processing file [_1]", $xml_file ) . "\n" );
my $pot_file = $xml_file;
$pot_file =~ s/\.xml/\.pot/;
$pot_file =~ s/^$source_dir/pot/;
$pot_file =~ m|^(.*)/([^/]+)$|;
my $path = $1;
my $filename = $2;
mkpath($path) if ( !-d $path );
my $xml_doc = Publican::Builder::new_tree();
$xml_doc->store_cdata(1);
$xml_doc->parse_file($xml_file)
|| croak(
maketext( "Can't open file [_1]. Error: [_2]", $xml_file, $@ ) );
$xml_doc->pos( $xml_doc->root() );
my $msg_list
= $self->get_msgs( { doc => $xml_doc, filename => $filename } );
##debug_msg( "hash: " . $msg_list->content_list() . "\n\n" );
$self->print_msgs( { msg_list => $msg_list, pot_file => $pot_file } );
# Remove pot files with no content
if ( ( -z $pot_file ) || ( $msg_list->content_list() == 0 ) ) {
unlink($pot_file);
logger(
"\t"
. maketext(
"deleted empty pot file: [_1]" . "\n", $pot_file
)
);
}
}
return;
}
=head2 po2xml
Merge XML and PO into a translated XML file.
=cut
sub po2xml {
my ( $self, $args ) = @_;
my $xml_file = delete( $args->{xml_file} )
|| croak( maketext("xml_file is a mandatory argument") );
my $po_file = delete( $args->{po_file} )
|| croak( maketext("po_file is a mandatory argument") );
my $out_file = delete( $args->{out_file} )
|| croak( maketext("out_file is a mandatory argument") );
my $ent_file = delete( $args->{ent_file} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
logger(
"\t"
. maketext( "Merging [_1] >> [_2] -> [_3]",
$po_file, $xml_file, $out_file )
. "\n"
);
my $path = undef;
if ( $out_file =~ m|^(.*/xml)/(.*\/)[^\/]*\.xml| ) {
$path = $2;
$path =~ s|[^/]*/|\.\./|g;
}
$ent_file = "$path$ent_file" if ($path);
my $dtdver = $self->{publican}->param('dtdver');
my $out_doc = Publican::Builder::new_tree();
$out_doc->parse_file($xml_file)
|| croak(
maketext( "Can't open file [_1]. Error: [_2]", $xml_file, $@ ) );
$out_doc->pos( $out_doc->root() );
my $msgids = Locale::PO->load_file_ashash( $po_file, 'UTF-8' );
foreach my $key ( keys( %{$msgids} ) ) {
my $msgref = $msgids->{$key};
if ( $msgref->obsolete() ) {
delete( $msgids->{$key} );
}
if ( $msgref->fuzzy() && !$self->{showfuzzy} ) {
$msgref->msgstr("");
}
}
$self->merge_msgs(
{ out_file => $out_file,
ent_file => $ent_file,
out_doc => $out_doc,
msgids => $msgids
}
);
$out_doc->pos( $out_doc->root() );
foreach my $node ( $out_doc->look_down( 'processed', 1 ) ) {
$node->attr( 'processed', undef );
}
$out_doc->pos( $out_doc->root() );
my $type = $out_doc->attr("_tag");
my $text = $out_doc->as_XML();
$text =~ s/&([a-zA-Z-_0-9]+;)/&$1/g;
$text =~ s/&/&/g;
$text =~ s/</</g;
$text =~ s/>/>/g;
$text =~ s/"/"/g;
$text =~ s/'/'/g;
$text =~ s/"/"/g;
$text =~ s/'/'/g;
$out_doc->root()->delete();
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", "$out_file" )
|| croak( maketext( "Could not open [_1] for output!", $out_file ) );
print $OUTDOC Publican::Builder::dtd_string(
{ tag => $type,
dtdver => $dtdver,
cleaning => 1,
ent_file => $ent_file
}
);
print( $OUTDOC $text );
close($OUTDOC);
return;
}
=head2 update_po
Update the PO files using internal process or msgmerge
=cut
sub update_po {
my ( $self, $args ) = @_;
my $langs = delete( $args->{langs} )
|| croak( maketext("langs is a mandatory argument") );
my $msgmerge = delete( $args->{msgmerge} );
my $firstname = delete( $args->{firstname} )
|| croak( maketext("firstname is a mandatory argument") );
my $surname = delete( $args->{surname} )
|| croak( maketext("surname is a mandatory argument") );
my $email = delete( $args->{email} )
|| croak( maketext("email is a mandatory argument") );
my $previous = delete( $args->{previous} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $docname = $self->{publican}->param('docname');
my $version = $self->{publican}->param('version');
my $type = $self->{publican}->param('type');
my $xml_lang = $self->{publican}->param('xml_lang');
my $source_dir = $xml_lang;
$source_dir = 'trans_drop' if ( -d 'trans_drop' );
my @pot_files = dir_list( 'pot', '*.pot' );
foreach my $lang ( sort( split( /,/, $langs ) ) ) {
next if ( $lang eq $xml_lang );
next if ( $lang eq $source_dir );
unless ( Publican::valid_lang($lang) ) {
logger(
maketext( "WARNING: Skipping invalid language: [_1]", $lang )
. "\n" );
next;
}
my $lc_lang = $lang;
$lc_lang =~ s/-/_/g;
my $locale = Publican::Localise->get_handle($lc_lang)
|| croak(
maketext(
"Could not create a Publican::Localise object for language: [_1]",
$lang
)
);
$locale->encoding("UTF-8");
$locale->textdomain("publican");
## $locale->die_for_lookup_failures(1);
# If asked to update a non-existing language, create it
mkdir $lang if ( !-d $lang );
foreach my $pot_file ( sort(@pot_files) ) {
my $po_file = $pot_file;
# remove the t from .pot
chop($po_file);
$po_file =~ s/^pot/$lang/;
logger(
"\t"
. maketext( "Processing file [_1] -> [_2]",
$pot_file, $po_file )
. "\n"
);
# handle nested directories
$pot_file =~ m|^(.*)/[^/]+$|;
my $path = $1;
mkpath($path) if ( !-d $path );
if ( !-f $po_file || -z $po_file ) {
fcopy( $pot_file, $po_file );
}
else {
if ( !$msgmerge ) {
$self->merge_po(
{ po_file => $po_file, pot_file => $pot_file } );
}
else {
my @cmd
= qw(msgmerge --no-wrap --quiet --backup=none --update);
push( @cmd, '--previous' ) if ($previous);
if ( system( @cmd, $po_file, $pot_file ) != 0 ) {
croak(
maketext(
"Fatal Error: msgmerge failed to merge updates. POT File: [_1]. Po File: [_2]",
$pot_file,
$po_file
)
);
}
}
}
my $xml_file = $pot_file;
$xml_file =~ s/^pot/$source_dir/;
$xml_file =~ s/pot$/xml/;
logger(
maketext( "WARNING: No source xml file exists for [_1]",
$pot_file )
. "\n",
CYAN
) unless ( -f $xml_file );
}
if ( $self->{publican}->param('type') ne 'brand' ) {
my ( $edition, $release )
= $self->{publican}->get_ed_rev( { lang => $source_dir } );
my @members = (
decode_utf8(
$locale->maketext(
"Translation files synchronised with XML sources [_1]-[_2]",
$edition,
$release
)
)
);
my $rev_num = "$edition-$release.1";
my ( $t_edition, $t_release );
eval {
( $t_edition, $t_release )
= $self->{publican}->get_ed_rev( { lang => $lang } );
};
if ( ( !$@ )
&& ( $t_edition eq $edition )
&& ( $t_release =~ /^$release\.(\d+)$/ ) )
{
$rev_num = "$edition-$release." . ( 1 + $1 );
}
$self->{publican}->add_revision(
{ lang => $lang,
revnumber => "$rev_num",
members => \@members,
email => $email,
firstname => $firstname,
surname => $surname
}
);
}
}
return;
}
=head2 merge_po
Merge updated POT files in to existing PO files.
=cut
sub merge_po {
my ( $self, $args ) = @_;
my $po_file = delete( $args->{po_file} )
|| croak( maketext("po_file is a mandatory argument") );
my $pot_file = delete( $args->{pot_file} )
|| croak( maketext("pot_file is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $pot_arry = Locale::PO->load_file_asarray( $pot_file, 'UTF-8' );
my $po_hash = Locale::PO->load_file_ashash( $po_file, 'UTF-8' );
my @po_keys = keys( %{$po_hash} );
my %po_start_keys = map { $_ => 1 } @po_keys;
my @out_arry = ();
POT:
foreach my $pot ( @{$pot_arry} ) {
my $pot_id = $pot->msgid();
my $matched = 0;
my %highest = ();
foreach my $po_id (@po_keys) {
my $match = $self->match_strings( $pot_id, $po_id );
if ( $match >= 1 ) {
delete( $po_start_keys{$po_id} );
$po_hash->{$po_id}->obsolete(0)
if ( $po_hash->{$po_id}->obsolete() );
$po_hash->{$po_id}->fuzzy(0)
if ( $po_hash->{$po_id}->fuzzy() );
push( @out_arry, $po_hash->{$po_id} );
next POT;
}
elsif ( $match >= 0.8 ) {
$matched = 1;
delete( $po_start_keys{$po_id} );
if ( ( !defined( $highest{match} ) )
|| ( $match > $highest{match} ) )
{
$highest{match} = $match;
$highest{pot_id} = $pot_id;
$highest{po_id} = $po_id;
}
}
}
if ( !$matched ) {
push( @out_arry, $pot );
}
else {
my $id = $highest{po_id};
$po_hash->{$id}->fuzzy(1) unless ( $po_hash->{$id}->fuzzy() );
$po_hash->{$id}->obsolete(0) if ( $po_hash->{$id}->obsolete() );
$po_hash->{$id}
->msgid( $po_hash->{$id}->dequote( $highest{pot_id} ) );
push( @out_arry, $po_hash->{$id} );
}
}
foreach my $obsolete ( keys(%po_start_keys) ) {
$po_hash->{$obsolete}->obsolete(1);
push( @out_arry, $po_hash->{$obsolete} );
}
Locale::PO->save_file_fromarray( $po_file, \@out_arry, 'UTF-8' );
return;
}
=head2 match_strings
Compare 2 strings and return how closely they match.
Returns a vlaue between 0 and 1, weighted for string length.
=cut
sub match_strings {
my ( $self, $s1, $s2 ) = @_;
croak(
maketext(
"match_strings requires 2 arguments [_1], [_2].", $s1, $s2
)
) unless ( ($s1) && ($s2) && ( $s1 ne "" ) && ( $s2 ne "" ) );
my $similarity = similarity( $s1, $s2 );
## TODO factor string length in to similarity?
return ($similarity);
}
=head2 update_po_all
Update the PO files for all languages
=cut
sub update_po_all {
my ( $self, $args ) = @_;
my $msgmerge = delete( $args->{msgmerge} );
my $previous = delete( $args->{previous} );
my $firstname = delete( $args->{firstname} );
my $surname = delete( $args->{surname} );
my $email = delete( $args->{email} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
$self->update_po(
{ langs => get_all_langs(),
msgmerge => $msgmerge,
email => $email,
firstname => $firstname,
surname => $surname,
previous => $previous,
}
);
return;
}
=head2 get_msgs
Get the strings to translate from an XML::TreeBuilder object
=cut
sub get_msgs {
my ( $self, $args ) = @_;
my $doc = delete( $args->{doc} ) || croak("doc is a mandatory argument");
my $filename = delete( $args->{filename} )
|| croak("filename is a mandatory argument");
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $trans_tree = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
my $trans_node;
# Break strings up in to translatable blocks
# some block level tags, $IGNOREBLOCKS, should be treated inline
# indexterm is special as it's both translatable and ignorable >_<
foreach my $child (
$doc->look_down(
'_tag',
qr/$TRANSTAGS/,
sub {
my $inner = $_[0];
## an index term NOT in a translatable tag should be translated as a block.
## An indexterm in a translatable tag should be translated inline
if ( $inner->tag() =~ /indexterm|orgname|productname|phrase/ )
{
not defined(
$inner->look_up(
'_tag',
qr/$IGNOREBLOCKS/,
sub {
$_[0]->tag() =~ /$TRANSTAGS/
&& $inner->look_up( '_tag',
qr/$TRANSTAGS/,
sub { $_[0]->pos() != $inner->pos() } );
},
)
);
}
## To allow External_Links to be translatable we need to translate the whole list as
## the attributes of then members need to be translated.
elsif ( $inner->tag() eq 'simplelist' ) {
$filename eq 'External_Links.pot';
}
elsif ( $filename eq 'External_Links.pot' ) {
0;
}
else {
## Other IGNOREBLOCKS tags are completely ignored for translation structure.
not defined(
$inner->look_up( '_tag', qr/$IGNOREBLOCKS/ ) );
}
}
)
)
{
next if ( $child->is_empty );
$trans_node = XML::Element->new( $child->tag() );
# Have to be inside a translatable tag here, so don't need to check again
my @matches;
if ( $filename ne 'External_Links.pot' ) {
@matches = $child->look_down(
'_tag',
qr/$TRANSTAGS/,
sub {
not defined(
$_[0]->look_up( '_tag', qr/$IGNOREBLOCKS/ ) );
}
);
}
# No Nesting so push all of this nodes content on to the output trans_tree
if ( $#matches == -1 ) {
$trans_node->push_content( $child->content_list() );
}
else {
#debug_msg("processing a $child->tag()\n");
# Nesting, need to start a new output node
$trans_tree->push_content($trans_node)
if ( !$trans_node->is_empty );
$trans_node = XML::Element->new( $child->tag() )
; # Does this dupliacte new above?
# Text nodes are not ref
# any non-matching node should be pushed on to output with text
# this catches inline tags
foreach my $nested ( $child->content_list() ) {
if (ref $nested
&& $nested->look_down(
'_tag',
qr/$TRANSTAGS/,
sub {
not defined(
$_[0]->look_up( '_tag', qr/$IGNOREBLOCKS/ ) );
}
)
)
{
$trans_tree->push_content($trans_node)
if ( !$trans_node->is_empty );
$trans_node = XML::Element->new( $child->tag() );
$trans_tree->push_content(
$self->get_msgs(
{ doc => $nested, filename => $filename }
)->content_list()
);
}
else {
$trans_node->push_content($nested);
}
}
$trans_tree->push_content($trans_node)
if ( !$trans_node->is_empty );
}
$trans_tree->push_content($trans_node)
if ( !$trans_node->is_empty );
$child->delete();
}
return ($trans_tree);
}
=head2 merge_msgs
Merge translations in to XML
=cut
sub merge_msgs {
my ( $self, $args ) = @_;
my $out_doc = delete( $args->{out_doc} )
|| croak("out_doc is a mandatory argument");
my $msgids = delete( $args->{msgids} )
|| croak("msgids is a mandatory argument");
my $ent_file = delete( $args->{ent_file} );
my $out_file = delete( $args->{out_file} )
|| croak( maketext("out_file is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
foreach my $child (
$out_doc->look_down(
'_tag',
qr/$TRANSTAGS/,
## sub { not defined( $_[0]->look_up( '_tag', qr/$IGNOREBLOCKS/ ) ) }
sub {
my $inner = $_[0];
## an index term NOT in a translatable tag should be translated as a block.
## An indexterm in a translatable tag should be translated inline
if ( $inner->tag() =~ /indexterm|productname|phrase/ ) {
not defined(
$inner->look_up(
'_tag',
qr/$IGNOREBLOCKS/,
sub {
$_[0]->tag() =~ /$TRANSTAGS/
&& $inner->parent()
&& $inner->parent()->tag()
=~ /$TRANSTAGS/;
},
)
);
}
## To allow External_Links to be translatable we need to translate the whole list as
## the attributes of then members need to be translated.
elsif ( $inner->tag() eq 'simplelist' ) {
$out_file =~ /External_Links\.xml/;
}
elsif ( $out_file =~ /External_Links\.xml/ ) {
0;
}
else {
## Other IGNOREBLOCKS tags are completely ignored for translation structure.
not defined(
$inner->look_up( '_tag', qr/$IGNOREBLOCKS/ ) );
}
}
)
)
{
next if ( $child->attr('processed') );
$child->attr( 'processed', 1 );
next if ( $child->is_empty );
# Have to be inside a translatable tag here, so don't need to check again
my @matches;
if ( $out_file !~ /External_Links\.xml/ ) {
@matches = $child->look_down(
'_tag',
qr/$TRANSTAGS/,
sub {
not defined(
$_[0]->look_up( '_tag', qr/$IGNOREBLOCKS/ ) );
}
);
}
# No Nesting so push all of this nodes content on to the output trans_tree
if ( $#matches == -1 ) {
$self->translate(
{ ent_file => $ent_file, node => $child, msgids => $msgids }
);
}
else {
my $trans_node = XML::Element->new( $child->tag() );
# have to recurse through children
# pop off all children
my @content = $child->detach_content();
foreach my $nested (@content) {
# No ref == text node
if (ref $nested
&& $nested->look_down(
'_tag',
qr/$TRANSTAGS/,
sub {
not defined(
$_[0]->look_up( '_tag', qr/$IGNOREBLOCKS/ ) );
}
)
)
{
if ( $trans_node && !$trans_node->is_empty ) {
$self->translate(
{ ent_file => $ent_file,
node => $trans_node,
msgids => $msgids
}
);
$child->push_content( $trans_node->content_list() );
$trans_node->delete();
$trans_node = XML::Element->new( $child->tag() );
}
$self->merge_msgs(
{ out_file => $out_file,
out_doc => $nested,
msgids => $msgids
}
);
$child->push_content($nested);
}
else {
$trans_node->push_content($nested);
}
}
if ( $trans_node && !$trans_node->is_empty ) {
$self->translate(
{ ent_file => $ent_file,
node => $trans_node,
msgids => $msgids
}
);
$child->push_content( $trans_node->content_list() );
$trans_node->delete();
}
}
}
return;
}
=head2 translate
Replace strings with translated strings.
=cut
sub translate {
my ( $self, $args ) = @_;
my $node = delete( $args->{node} )
|| croak("node is a mandatory argument");
my $msgids = delete( $args->{msgids} )
|| croak("msgids is a mandatory argument");
my $ent_file = delete( $args->{ent_file} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $msgid = $node->as_XML();
my $tag = $node->tag();
my $po = new Locale::PO( -msgid => detag( $msgid, $tag ), -msgstr => '' );
$msgid = $po->msgid();
my $attr_text = '';
my %attrs = $node->all_attr();
foreach my $key ( keys(%attrs) ) {
next if ( $key =~ /^_/ );
$attr_text .= qq{ $key="$attrs{$key}"};
}
# mixed mode tags, para, caption, can be empty at this point
if ( $msgid and ( $msgid eq '""' ) ) {
#nop
}
elsif ( $msgid
&& defined $msgids->{$msgid} )
{
if ( $msgids->{$msgid}{msgstr} ne '""' ) {
my $msgstr = $msgids->{$msgid}{msgstr};
debug_msg("DANGER: found obsolete msg: $msgid\n")
if ( $msgstr =~ /^#~/ );
my $repl = $po->dequote($msgstr);
my $dtd = Publican::Builder::dtd_string(
{ tag => $tag,
dtdver => $self->{publican}->param('dtdver'),
cleaning => 1,
ent_file => $ent_file
}
);
my $new_tree = Publican::Builder::new_tree();
$new_tree->parse(qq|$dtd<$tag$attr_text>$repl$tag>|);
$node->delete_content();
$node->push_content( $new_tree->content_list() );
}
else {
if ( $msgids->{$msgid}->fuzzy() )
{ # BUGBUG TEST this is still set
logger( maketext("WARNING: Fuzzy message in PO file."), RED );
}
else {
logger(
maketext("WARNING: Un-translated message in PO file."),
RED );
}
my $str = $msgid;
$str = substr( $str, 0, 64 ) . '...' if ( length($str) > 64 );
logger(
"\n" . $msgids->{$msgid}->loaded_line_number . ": $str\n\n",
RED );
}
}
else {
logger(
maketext(
"WARNING: Message missing from PO file, consider updating your POT and PO files."
),
RED
);
logger( "\n" . $msgid . "\n\n", RED );
}
return;
}
=head2 print_msgs
Print the translation strings in an XML::TreeBuilder object to a POT file
=cut
sub print_msgs {
my ( $self, $args ) = @_;
my $msg_list = delete( $args->{msg_list} )
|| croak("msg_list is a mandatory argument");
my $pot_file = delete( $args->{pot_file} )
|| croak( maketext("pot_file is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $fh;
open( $fh, ">:encoding(UTF-8)", $pot_file )
or croak(
maketext(
"Failed to open output file [_1]. Error: [_2]",
$pot_file, $@
)
);
my %msgs = ();
my $po = new Locale::PO( -msgid => '', -msgstr => $self->header() );
print( $fh $po->dump() );
$msgs{''} = $po;
foreach my $child ( $msg_list->content_list() ) {
my $msg_id = detag( $child->as_XML(), $child->tag() );
# This can be empty if a mixed mode tag only contains a block
next if ( $msg_id eq '' );
if ( !defined( $msgs{$msg_id} ) ) {
my $po = new Locale::PO( -msgid => $msg_id, -msgstr => '' );
print( $fh $po->dump() );
$msgs{$msg_id} = $po;
}
}
close($fh);
return;
}
=head2 header
Returns a valid PO header string.
=cut
sub header {
my $self = shift;
my $date
= DateTime->now( time_zone => "local" )->strftime("%Y-%m-%d %H:%M%z");
my $lang = $self->{publican}->param('xml_lang');
$lang =~ s/_/-/g;
my $pver = $self->{publican}->VERSION;
my $string = <]*>//;
# remove close tag to reduce polution
$string =~ s/<\/$name>\s*$//;
chomp($string);
}
else {
chomp($string);
# remove start tag & leading space
$string =~ s/^<$name[^>]*>[ \t]*//;
# remove close tag & trailing
$string =~ s/[ \t]*<\/$name>\s*$//;
$string =~ s/\n/ /g; # CR
$string =~ s/^[ \t]*//g; # space at start of line
$string =~ s/[ \t]*$//g; # space at end of line
$string =~ s/[ \t]+/ /g; # collapse spacing
}
$string =~ s/&/&/g;
$string =~ s/</</g;
$string =~ s/>/>/g;
$string =~ s/"/"/g;
$string =~ s/'/'/g;
$string =~ s/"/"/g;
$string =~ s/'/'/g;
return ($string);
}
=head2 po_report
Generate translation statistics for the supplied language.
=cut
sub po_report {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak( maketext("'lang' is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my @po_files = dir_list( $lang, '*.po' );
my %lang_stats = (
msg_count => 0,
fuzzy_count => 0,
trans_count => 0,
untrans_count => 0,
word_count => 0,
);
my $sep = '=' x 82;
my $rate = 250;
my $frate = $rate * 2;
my $file_name = maketext("File Name");
my $untranslated = maketext("Untranslated");
my $fuzzy = maketext("Fuzzy");
my $translated = maketext("Translated");
logger("$sep\n");
logger(
sprintf(
"%-40s %15s %10s %10s\n",
$file_name, $untranslated, $fuzzy, $translated
)
);
logger("$sep\n");
foreach my $po_file ( sort(@po_files) ) {
my $msgids = Locale::PO->load_file_ashash($po_file);
#debug_msg( "hash: " . join( "\n\n", keys( %{$msgids} ) ) . "\n\n" );
my %po_stats = (
msg_count => 0,
fuzzy_count => 0,
trans_count => 0,
untrans_count => 0,
word_count => 0,
);
foreach my $key ( keys( %{$msgids} ) ) {
my $msgref = $msgids->{$key};
$po_stats{msg_count}++;
next unless $msgref->msgid();
if ( $msgref->obsolete() ) {
$po_stats{msg_count}--;
next;
}
my $count = ()
= $msgref->msgid()
=~ /(?:\s+|<\/[a-zA-Z]+><[a-zA-Z]+>\S|-|.$)/g;
$po_stats{word_count} += $count;
if ( $msgref->msgstr() =~ /^""$/ ) {
$po_stats{untrans_count} += $count;
}
elsif ( $msgref->fuzzy() ) {
$po_stats{fuzzy_count} += $count;
}
else {
$po_stats{trans_count} += $count;
}
}
logger(
sprintf(
"%-45s %10d %10d %10d\n",
$po_file, $po_stats{untrans_count},
$po_stats{fuzzy_count}, $po_stats{trans_count}
)
);
$lang_stats{msg_count} += $po_stats{msg_count};
$lang_stats{fuzzy_count} += $po_stats{fuzzy_count};
$lang_stats{trans_count} += $po_stats{trans_count};
$lang_stats{untrans_count} += $po_stats{untrans_count};
$lang_stats{word_count} += $po_stats{word_count};
}
logger("$sep\n");
my $total = maketext( "Total for [_1]", $lang );
logger(
sprintf(
"%-45s %10d %10d %10d\n",
$total, $lang_stats{untrans_count},
$lang_stats{fuzzy_count}, $lang_stats{trans_count}
)
);
my $remaining = maketext( "Remaining hours for [_1]", $lang );
logger(
sprintf(
"%-45s %10.2f %10.2f\n",
$remaining,
( $lang_stats{untrans_count} / $rate ),
( $lang_stats{fuzzy_count} / $frate )
)
);
logger("$sep\n");
return;
}
1; # Magic true value required at end of module
__END__
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
version
Publican
File::Path
Term::ANSIColor
DateTime
Locale::PO
XML::TreeBuilder
String::Similarity
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
Builder.pm 000444 041472 041472 71776 12555605450 20370 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::Builder;
use utf8;
use strict;
use warnings;
use 5.008;
use Carp;
use Config::Simple '-strict';
use Publican;
use Publican::XmlClean;
use Publican::Translate;
use File::Path;
use File::pushd;
use File::Find;
use Cwd qw(abs_path);
use Archive::Tar;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use DateTime;
use DateTime::Format::DateParse;
use Syntax::Highlight::Engine::Kate;
use HTML::TreeBuilder;
use HTML::FormatText;
## BUGBUG test for BZ #697363
## BUGBUG HTML::FormatText::WithLinks::AndTables requires patches from
# https://rt.cpan.org/Public/Bug/Display.html?id=63555
# https://rt.cpan.org/Public/Bug/Display.html?id=55919
use HTML::FormatText::WithLinks::AndTables;
use HTML::FormatText::WithLinks;
use Term::ANSIColor qw(:constants);
use POSIX qw(floor :sys_wait_h);
use Locale::Language;
use List::Util qw(max);
use Text::Wrap qw(fill $columns);
use IO::String;
use File::Which;
use Text::CSV_XS;
use Publican::ConfigData;
use Sort::Versions;
use Template;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
use vars qw(@ISA @EXPORT @EXPORT_OK);
our ( $INVALID, %LANG_MAP );
@EXPORT = qw($INVALID %LANG_MAP del_unwanted_dirs del_unwanted_xml);
@ISA = qw(Exporter);
$INVALID = 1;
my $DEFAULT_WRAP = 82;
$columns = $DEFAULT_WRAP;
%LANG_MAP = (
ar => 'ar-SA',
as => 'as-IN',
bg => 'bg-BG',
bn => 'bn-IN',
bs => 'bs-BA',
ca => 'ca-ES',
cs => 'cs-CZ',
da => 'da-DK',
de => 'de-DE',
el => 'el-GR',
en => 'en-US',
es => 'es-ES',
fa => 'fa-IR',
fi => 'fi-FI',
fr => 'fr-FR',
gu => 'gu-IN',
he => 'he-IL',
hi => 'hi-IN',
hr => 'hr-HR',
hu => 'hu-HU',
id => 'id-ID',
is => 'is-IS',
it => 'it-IT',
ja => 'ja-JP',
kn => 'kn-IN',
ko => 'ko-KR',
lv => 'lv-LV',
ml => 'ml-IN',
mr => 'mr-IN',
ms => 'ms-MY',
nb => 'nb-NO',
nl => 'nl-NL',
or => 'or-IN',
pa => 'pa-IN',
pl => 'pl-PL',
pt => 'pt-PT',
ru => 'ru-RU',
si => 'si-LK',
sk => 'sk-SK',
sr => 'sr-Latn-RS',
sv => 'sv-SE',
ta => 'ta-IN',
te => 'te-IN',
th => 'th-TH',
tr => 'tr-TR',
uk => 'uk-UA',
);
=head1 NAME
Publican::Builder - A module to Convert XML to various output formats
=head1 SYNOPSIS
use Publican::Builder;
my $builder = Publican::Builder->new();
$builder->clean_ids();
=head1 DESCRIPTION
Manipulate XML and convert to other formats.
=head1 INTERFACE
=cut
=head2 new
Create a new Publican::Builder object.
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $novalid = delete( $args->{novalid} ) || 0;
my $showfuzzy = delete( $args->{showfuzzy} ) || undef;
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $self = bless {}, $class;
$self->{publican} = Publican->new();
$self->{translator} = Publican::Translate->new({showfuzzy => $showfuzzy});
$self->{validate} = !$novalid;
$self->{id_attr} = "id";
my $common_content = $self->{publican}->param('common_content');
my $common_config = $self->{publican}->param('common_config');
my $brand = $self->{publican}->param('brand');
my $brand_path = $self->{publican}->param('brand_dir')
|| $common_content . "/$brand";
my $tmpl_path = Publican::ConfigData->config('rpm_templates');
$tmpl_path = "$brand_path/rpm_templates:$tmpl_path"
if ( -d "$brand_path/rpm_templates" );
my $conf = { INCLUDE_PATH => $tmpl_path, };
# $conf->{DEBUG} = Template::Constants::DEBUG_ALL;# if ($debug);
# create Template object
$self->{template} = Template->new($conf) or croak( Template->error() );
return $self;
}
=head2 build
Transform the source in to another format.
Valid formats: eclipse epub html html-single html-desktop man pdf txt
=cut
sub build {
my ( $self, $args ) = @_;
logger( "build should be sub-classed!" . "\n", RED );
return;
}
=head2 del_unwanted_dirs
Callback that deletes all unwanted directories from the given directory tree. Used to delete CVS and SVN files from the working directories.
=cut
sub del_unwanted_dirs {
my $dir = $_;
my @unwanted = qw( );
if ( $dir =~ /^(CVS|\.svn|\.git|.*\.swp|.*\.xml~|.directory)$/ ) {
rmtree($_)
|| croak(
maketext(
"couldn't remove unwanted dir '[_1]', error: [_2]",
$_, $@
)
);
return;
}
return;
}
=head2 del_unwanted_xml
Callback that deletes all unwanted xml from the given directory tree.
=cut
sub del_unwanted_xml {
if ( $_ =~ /\.xml$/ ) {
unlink($_)
|| croak(
maketext(
"couldn't unlink xml file '[_1]', error: [_2]", $_, $@
)
);
return;
}
return;
}
=head2 validate_xml
Ensure the XML validates against the DTD.
To debug the XML catalogs
export XML_DEBUG_CATALOG=1
test...
unset XML_DEBUG_CATALOG
=cut
sub validate_xml {
my ( $self, $args ) = @_;
logger( "validate_xml should be sub-classed!" . "\n", RED );
return;
}
=head2 package_brand
Create the structure for the distributed files and save it as a tar.gz file
=cut
sub package_brand {
my ( $self, $args ) = @_;
my $binary = delete( $args->{binary} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $name = lc( $self->{publican}->param('brand') );
my $version = $self->{publican}->param('version');
my $release = $self->{publican}->param('release');
my $tardir = "publican-$name-$version";
mkpath("$tmp_dir/tar/$tardir");
mkpath("$tmp_dir/rpm");
my $langs = get_all_langs();
my @file_list = (
'publican.cfg', "publican-$name.spec",
'README', 'COPYING',
'defaults.cfg', 'overrides.cfg'
);
foreach my $file (@file_list) {
rcopy( $file, "$tmp_dir/tar/$tardir/." ) if ( -f $file );
}
foreach my $dir ( split( /,/, $langs ),
'pot', 'xsl', 'book_templates', 'rpm_templates' )
{
dircopy( "$dir", "$tmp_dir/tar/$tardir/$dir" ) if ( -d $dir );
}
my $dir = pushd("$tmp_dir/tar");
finddepth( \&del_unwanted_dirs, $tardir );
my @files = dir_list( $tardir, '*' );
Archive::Tar->create_archive( "$tardir.tgz", 9, @files );
$dir = undef;
fmove( "$tmp_dir/tar/$tardir.tgz", "$tmp_dir/rpm/." );
$self->build_rpm( { spec => "publican-$name.spec", binary => $binary } );
return;
}
=head2 package_home
Package a book for use as a Publican Website home page.
=cut
sub package_home {
my ( $self, $args ) = @_;
my $binary = delete( $args->{binary} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $product = $self->{publican}->param('product');
my $version = $self->{publican}->param('version');
my $docname = $self->{publican}->param('docname');
my $edition = $self->{publican}->param('edition');
my $configfile = $self->{publican}->param('configfile');
my $release = $self->{publican}->param('release');
my $xml_lang = $self->{publican}->param('xml_lang');
my $type = $self->{publican}->param('type');
my $web_type = $self->{publican}->param('web_type') || 'home';
my $web_dir = $self->{publican}->param('web_dir')
|| '%{_localstatedir}/www/html/docs';
my $name_start = "$docname";
$name_start = "$product-$docname" if ( $web_type eq 'product' );
$name_start = "$product-$docname-$version" if ( $web_type eq 'version' );
my $tardir = "$name_start-web-$web_type-$edition";
mkpath("$tmp_dir/tar/$tardir");
mkpath("$tmp_dir/rpm");
my $langs = get_all_langs();
my @file_list = qw(publican.cfg site_overrides.css);
foreach my $file (@file_list) {
rcopy( $file, "$tmp_dir/tar/$tardir/." ) if ( -f $file );
}
foreach my $dir ( split( /,/, $langs ), 'pot' ) {
dircopy( "$dir", "$tmp_dir/tar/$tardir/$dir" ) if ( -d $dir );
}
my $dir = pushd("$tmp_dir/tar");
finddepth( \&del_unwanted_dirs, $tardir );
my @files = dir_list( $tardir, '*' );
Archive::Tar->create_archive( "$tardir-$release.tgz", 9, @files );
$dir = undef;
fmove( "$tmp_dir/tar/$tardir-$release.tgz", "$tmp_dir/rpm/." );
my $common_config = $self->{publican}->param('common_config');
my $xsl_file = $common_config . "/xsl/web-home-spec.xsl";
$xsl_file =~ s/"//g; # windows
my $license = $self->{publican}->param('license');
my $brand = 'publican-' . lc( $self->{publican}->param('brand') );
my $doc_url = $self->{publican}->param('doc_url');
my $src_url = $self->{publican}->param('src_url');
## BUGBUG for home pages we need to use $xml_lang/Rev... NOT $tmp/$lang/...
my $log = $self->change_log( { lang => $xml_lang } );
my $embedtoc = '--embedtoc';
$embedtoc = "" if ( $self->{publican}->param('no_embedtoc') );
my $full_subtitle
= $self->get_subtitle( { lang => $xml_lang, use_source => 1 } );
$full_subtitle =~ s/"/\\"/g;
$full_subtitle =~ s/\p{Z}+/ /g;
chomp($full_subtitle);
my %vars = (
'book_title' => $name_start,
'brand' => $brand,
'prod' => $product,
'prodver' => $version,
'rpmver' => $edition,
'rpmrel' => $release,
'docname' => $docname,
'license' => $license,
'url' => $doc_url,
'src_url' => $src_url,
'log' => $log,
tmpdir => $tmp_dir,
web_dir => $web_dir,
web_type => $web_type,
spec_version => $Publican::SPEC_VERSION,
embedtoc => $embedtoc,
full_subtitle => $full_subtitle,
GROUPS => ( -e "$xml_lang/Groups.xml" ? 1 : 0 ),
);
my $spec_name = "$tmp_dir/rpm/$name_start-web-$web_type.spec";
$self->{template}->process( 'splash.tmpl', \%vars, $spec_name,
binmode => ':encoding(UTF-8)' )
or croak( $self->{template}->error() );
$self->build_rpm(
{ spec => $spec_name,
binary => $binary
}
);
return;
}
=head2 build_rpm
Build an srpm for books and brands.
=cut
sub build_rpm {
my ( $self, $args ) = @_;
my $spec = delete( $args->{spec} )
|| croak( maketext("spec is a mandatory argument") );
my $binary = delete( $args->{binary} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $os_ver = $self->{publican}->param('os_ver');
my $dir = abs_path("$tmp_dir/rpm");
# From cspanspec and Fedora Makefile.common
my $rpmbuild
= ( -x "/usr/bin/rpmbuild" ? "/usr/bin/rpmbuild" : "/bin/rpm" );
unless ( -x $rpmbuild ) {
logger( maketext("rpmbuild not found, rpm creation aborted.") . "\n",
RED );
return;
}
debug_msg(
maketext( "Building rpms from [_1] using [_2] in [_3]",
$spec, $rpmbuild, $dir )
. "\n"
);
my @rpm_args = (
"--define", "_sourcedir $dir", "--define", "_builddir $dir",
"--define", "_srcrpmdir $dir", "--define", "_rpmdir $dir"
);
if ($binary) {
push( @rpm_args, "-ba" );
}
else {
push( @rpm_args, "-bs", "--nodeps" );
}
if ($os_ver) {
$os_ver = ".$os_ver" unless ( $os_ver =~ m/^\./ );
push( @rpm_args, "--define", "dist $os_ver" );
}
push( @rpm_args, $spec );
if ( system( $rpmbuild, @rpm_args ) != 0 ) {
if ( $? == -1 ) {
croak maketext( "Failed to execute [_1], error number: [_2]",
$rpmbuild, $! )
. "\n";
}
elsif ( WIFSIGNALED($?) ) {
croak maketext( "[_1] died with signal [_2]",
$rpmbuild, WTERMSIG($?) )
. "\n";
}
else {
croak maketext( "[_1] exited with value [_2]",
$rpmbuild, WEXITSTATUS($?) )
. "\n";
}
}
return;
}
=head2 package
Create the structure for the distributed files and save it as a tar.gz file
Creates RPM Specfile and build SRPM.
TODO: Consider handling other package formats, deb etc.
=cut
sub package {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak( maketext("lang is a mandatory argument") );
my $desktop = delete( $args->{desktop} ) || 0;
my $short_sighted = delete( $args->{short_sighted} ) || 0;
my $binary = delete( $args->{binary} );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
croak(
maketext(
"Short-sighted packages can only be used to make desktop rpms. Add --desktop to your argument list."
)
) if ( $short_sighted and not $desktop );
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $product = $self->{publican}->param('product');
my $version = $self->{publican}->param('version');
my $docname = $self->{publican}->param('docname');
my $edition = $self->{publican}->param('edition');
my $configfile = $self->{publican}->param('configfile');
my $release = $self->{publican}->param('release');
my $xml_lang = $self->{publican}->param('xml_lang');
my $type = $self->{publican}->param('type');
my $web_formats_comma = $self->{publican}->param('web_formats');
my $web_formats = $web_formats_comma;
my $embedtoc = '--embedtoc';
$embedtoc = "" if ( $self->{publican}->param('no_embedtoc') );
$web_formats =~ s/,/ /g;
my $book_src_lang = undef;
if ( $lang ne $xml_lang ) {
$book_src_lang = $xml_lang;
$release = undef;
## BUGBUG this should be moved to the DocBook sub classes
my $rev_file = "$lang/Revision_History.xml";
$rev_file = "$lang/" . $self->{publican}->param('rev_file')
if ( $self->{publican}->param('rev_file') );
croak( maketext( "Can't locate required file: [_1]", $rev_file ) )
if ( !-f $rev_file );
my $rev_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
eval { $rev_doc->parse_file($rev_file); };
if ($@) {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
my $VR = eval {
$rev_doc->root()->look_down( "_tag", "revnumber" )->as_text();
};
if ($@) {
croak( maketext( "revnumber not found in [_1]", $rev_file ) );
}
$VR =~ /^([0-9.]*)-([0-9.]*)$/ || croak(
maketext(
"revnumber ([_1]) does not match the required format of '[_2]'",
$VR,
'^([0-9.]*)-([0-9.]*)$/'
)
);
$edition = $1;
$release = $2;
}
my $name_start = "$product-$docname-$version";
$name_start = "$product-$docname" if ($short_sighted);
my $tardir = "$name_start-web-$lang-$edition";
$tardir = "$name_start-$lang-$edition" if ($desktop);
$tardir = "$name_start-$lang-$edition" if ($short_sighted);
# distributed sets need to be collected before packaging
if ( ( $type eq 'Set' ) && ( $self->{publican}->{config}->param('scm') ) )
{
$self->get_books();
$self->build_set_books( { langs => $lang } );
}
$self->setup_xml( { langs => $lang, cleaning => 1 } );
mkpath("$tmp_dir/tar/$tardir");
dircopy( "$tmp_dir/$lang/xml", "$tmp_dir/tar/$tardir/$lang" );
rmtree("$tmp_dir/tar/$tardir/$lang/Common_Content");
mkpath("$tmp_dir/rpm");
dircopy( "$xml_lang/icons", "$tmp_dir/tar/$tardir/$lang/icons" )
if ( -e "$xml_lang/icons" );
dircopy( "$lang/icons", "$tmp_dir/tar/$tardir/$lang/icons" )
if ( -e "$lang/icons" );
finddepth( \&del_unwanted_dirs, "$tmp_dir/tar/$tardir/$lang/icons" )
if ( -e "$tmp_dir/tar/$tardir/$lang/icons" );
dircopy( "$xml_lang/files", "$tmp_dir/tar/$tardir/$lang/files" )
if ( -e "$xml_lang/files" );
dircopy( "$lang/files", "$tmp_dir/tar/$tardir/$lang/files" )
if ( -e "$lang/files" );
finddepth( \&del_unwanted_dirs, "$tmp_dir/tar/$tardir/$lang/files" )
if ( -e "$tmp_dir/tar/$tardir/files" );
$self->{publican}->{config}->param( 'xml_lang', $lang );
my $common_config = $self->{publican}->param('common_config');
my $license = $self->{publican}->param('license');
my $brand = lc( $self->{publican}->param('brand') );
my $doc_url = $self->{publican}->param('doc_url');
my $src_url = $self->{publican}->param('src_url') || "";
my $dt_obsoletes = $self->{publican}->param('dt_obsoletes') || "";
my $dt_requires = $self->{publican}->param('dt_requires') || "";
my $web_obsoletes = $self->{publican}->param('web_obsoletes') || "";
my $translation = ( $lang ne $xml_lang );
my $language = code2language( substr( $lang, 0, 2 ) );
my ( $web_product_label, $web_version_label, $web_name_label )
= $self->web_labels( { lang => $lang, xml_lang => $xml_lang } );
my $web_dir = $self->{publican}->param('web_dir')
|| '%{_localstatedir}/www/html/docs';
my $web_cfg = $self->{publican}->param('web_cfg')
|| Publican::ConfigData->config('etc') . '/publican-website.cfg';
my $web_req = $self->{publican}->param('web_req') || '';
my $sort_order = $self->{publican}->param('sort_order') || '';
my $menu_category = $self->{publican}->param('menu_category')
|| "X-Red-Hat-Base;";
$menu_category =~ s/__LANG__/$lang/g;
$menu_category .= ';' if ( $menu_category !~ /;\s*$/ );
my %Config = $self->{publican}->{config}->vars();
my $config = new Config::Simple();
$config->syntax('http');
foreach my $key ( keys(%Config) ) {
# skip invalid parameters
next unless ( defined( $Publican::PARAMS{$key} ) );
# skip limited parameters
next
if (
defined $Publican::PARAMS{$key}->{limit_to}
&& (lc( $self->{publican}->param('type') ) ne
lc( $Publican::PARAMS{$key}->{limit_to} ) )
);
# skip defaults
next
if (
defined $Publican::PARAMS{$key}->{default}
&& (lc( $Publican::PARAMS{$key}->{default} ) eq
lc( $Config{$key} ) )
);
next if ( $Config{$key} eq "" );
$config->param( $key, encode_utf8( $Config{$key} ) );
}
# store lables for rebuilding translated content
$config->param( 'web_product_label', encode_utf8($web_product_label) )
if ($web_product_label);
$config->param( 'web_version_label', encode_utf8($web_version_label) )
if ($web_version_label);
$config->param( 'web_name_label', encode_utf8($web_name_label) )
if ($web_name_label);
$config->param( 'release', $release );
# don't override these
$config->delete('common_config');
$config->delete('common_content');
$config->delete('release');
$config->delete('edition');
$config->delete('brand_dir');
$config->delete('cover_image');
$config->write("$tmp_dir/tar/$tardir/publican.cfg");
my $dir = pushd("$tmp_dir/tar");
my @files = dir_list( $tardir, '*' );
Archive::Tar->create_archive( "../rpm/$tardir-$release.tgz", 9, @files );
$dir = undef;
my $log = $self->change_log( { lang => $lang } );
## BUGBUG this should be moved to the DocBook sub classes
my $full_abstract = $self->get_abstract( { lang => $lang } );
$full_abstract =~ s/\p{Z}+/ /g;
# Wrap description for RPM style requirements
$columns = 68;
my $abstract = fill( "", "", $full_abstract );
$columns = $DEFAULT_WRAP;
# Escape single quotes to prevent bash breaking
$full_abstract =~ s/"/\\"/g;
## BUGBUG this should be moved to the DocBook sub classes
my $full_subtitle = $self->get_subtitle( { lang => $lang } );
$full_subtitle =~ s/"/\\"/g;
$full_subtitle =~ s/\p{Z}+/ /g;
chomp($full_subtitle);
my %vars = (
book_title => $name_start,
lang => $lang,
prod => $product,
prodver => $version,
rpmver => $edition,
rpmrel => $release,
docname => $docname,
license => $license,
brand => "publican-$brand",
url => $doc_url,
src_url => $src_url,
'log' => $log,
dt_obsoletes => $dt_obsoletes,
dt_requires => $dt_requires,
web_obsoletes => $web_obsoletes,
translation => $translation,
language => $language,
abstract => $abstract,
tmpdir => $tmp_dir,
ICONS => ( -e "$xml_lang/icons" ? 1 : 0 ),
product_label => $web_product_label,
version_label => $web_version_label,
name_label => $web_name_label,
web_dir => $web_dir,
web_cfg => $web_cfg,
web_req => $web_req,
full_abstract => $full_abstract,
full_subtitle => $full_subtitle,
web_formats => $web_formats,
web_formats_comma => $web_formats_comma,
menu_category => $menu_category,
spec_version => $Publican::SPEC_VERSION,
embedtoc => $embedtoc,
sort_order => $sort_order,
book_version => "$edition-$release",
book_src_lang => $book_src_lang,
img_dir => $self->{publican}->param('img_dir'),
dt_format => $self->{publican}->param('dt_format'),
);
# \p{Z} is unicode white space, which is a super set of ascii white space.
if ( $full_abstract !~ /[^\p{Z}]/ ) {
logger(
maketext(
"WARNING: You can not create RPM packages with a blank abstract. Skipping RPM creation.\n"
),
RED
);
return;
}
if ( $full_subtitle !~ /[^\p{Z}]/ ) {
logger(
maketext(
"WARNING: You can not create RPM packages with a blank subtitle. Skipping RPM creation.\n"
),
RED
);
return;
}
my $spec_name = "$tmp_dir/rpm/$name_start-web-$lang.spec";
$spec_name = "$tmp_dir/rpm/$name_start-$lang.spec"
if ( $desktop or $short_sighted );
my $spec_tmpl = 'spec.tmpl';
if ($desktop) {
$spec_tmpl = 'desktop-spec.tmpl';
}
$self->{template}->process( $spec_tmpl, \%vars, $spec_name,
binmode => ':encoding(UTF-8)' )
or croak( $self->{template}->error() );
$self->build_rpm( { spec => $spec_name, binary => $binary } );
return;
}
=head2 web_labels
Determine if the labels use in the web navigation are different from the names used for packaging.
This should be sub-classed.
=cut
sub web_labels {
my ( $self, $args ) = @_;
logger( "web_labels should be sub-classed!\n", RED );
return;
}
=head2 setup_xml
Create the proper directory structure for the XML, including copying in Brand files.
This should be sub-classed.
=cut
sub setup_xml {
my ( $self, $args ) = @_;
logger( "setup_xml should be sub-classed!" . "\n", RED );
return;
}
=head2 clean_ids
Travers over the source XML and update the id's to match the standard format.
Updates all existing PO files with the new xref links.
This should be sub-classed.
=cut
sub clean_ids {
my ( $self, $args ) = @_;
logger( "clean_ids should be sub-classed!" . "\n", RED );
return;
}
=head2 change_log
Generate an RPM style change log from $xml_lang/Revision_History.xml
This should be sub-classed.
=cut
sub change_log {
my ( $self, $args ) = @_;
logger( "change_log should be sub-classed!" . "\n", RED );
return;
}
=head2 get_books
Fetch all the books for a set from a repo.
Supported Repos: SVN
=cut
sub get_books {
my ( $self, $args ) = @_;
my $scm = ( lc( $self->{publican}->param('scm') ) || "" );
unless ($scm) {
logger(
maketext(
"Config parameter 'scm' not found; treating set as standalone."
)
. "\n",
RED
);
return;
}
croak( maketext( "Unknown set SCM: [_1]", $scm ) )
unless ( $scm =~ /^(svn|git)$/ );
my $books = $self->{publican}->param('books')
|| croak(
maketext(
"'books' is a required configuration parameter for a remote set")
. "\n"
);
my $repo = $self->{publican}->param('repo')
|| croak(
maketext(
"'repo' is a required configuration parameter for a remote set")
. "\n"
);
foreach my $book ( split( " ", $books ) ) {
if ( !-d $book ) {
logger( maketext( "Fetching [_1] from scm", $book ) . "\n" );
my $result;
if ( $scm eq 'svn' ) {
$result = system("svn export --quiet $repo/$book $book");
}
else {
## BUGBUG assuming we stuff the full git repo in to this param.
## e.g.
## books: "book1 book2"
## repo: '"book1=git://git.example.org/book1.git""book2=git://git.example.com/git/book2.git"'
$repo =~ /$book=([^'"]+)["']/;
my $git_url = $1
|| croak(
maketext( "Cannot find GIT url for book [_1]", $book ) );
$result = system("git clone --quiet $git_url $book");
}
croak(
maketext(
"Fatal Error: Export failed. Book: [_1]. Error Number: [_2]",
$book,
$?
)
) if ($result);
}
}
return;
}
=head2 build_set_books
Prepare XML from sub books for Remote Sets
=cut
sub build_set_books {
my ( $self, $args ) = @_;
my $langs = delete( $args->{langs} )
|| croak( maketext("langs is a mandatory argument") );
if ( %{$args} ) {
croak( maketext( "unknown args: " . join( ", ", keys %{$args} ) ) );
}
my $books = $self->{publican}->param('books')
|| croak(
maketext(
"'books' is a required configuration parameter for a remote set")
);
my $tmp_dir = $self->{publican}->param('tmp_dir');
foreach my $book ( split( " ", $books ) ) {
logger( maketext( "Start building [_1]", $book ) . "\n" );
my $dir = pushd($book);
logger(
maketext("Running clean_ids to prevent inter-book ID clashes.")
. "\n" );
if ( system("publican clean_ids") != 0 ) {
croak(
maketext(
"Fatal error: Book failed to run clean_ids! Book: [_1]. Error Number: [_2]",
$book,
$?
)
);
}
if (system(
"publican build --formats=xml --langs=$langs --distributed_set"
) != 0
)
{
# build failed
croak(
maketext(
"Fatal error: Book failed to build! Book: [_1]. Error Number: [_2]",
$book,
$?
)
);
}
$dir = undef;
foreach my $lang ( split( /,/, $langs ) ) {
dirmove(
"$book/$tmp_dir/$lang/xml/images",
"$tmp_dir/$lang/xml/images/$book/images"
);
dircopy( "$book/$tmp_dir/$lang/xml", "$tmp_dir/$lang/xml/$book" );
}
logger( maketext( "Finish building [_1]", $book ) . "\n" );
}
return;
}
1; # Magic true value required at end of module
__END__
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
version
Config::Simple
Publican
Publican::XmlClean
Publican::Translate
File::Path
File::pushd
File::Find
Cwd
Archive::Tar
DateTime
DateTime::Format::DateParse
Syntax::Highlight::Engine::Kate
HTML::TreeBuilder
HTML::FormatText
Term::ANSIColor
POSIX
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
TreeView.pm 000444 041472 041472 20211 12555605450 20506 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican package Publican::TreeView;
use strict;
use warnings;
use Carp;
use XML::TreeBuilder;
use Publican;
use File::pushd;
use Term::ANSIColor qw(:constants);
use File::Basename;
use Cwd qw(realpath);
use File::Spec qw(abs2rel);
=head1 NAME
Publican::TreeView - Dumper for XInclude project structure.
=head1 SYNOPSIS
use Publican;
use Publican::TreeView...
=head1 DESCRIPTION
Publican::TreeView displays the xi:include structure of the entire project.
=head1 INTERFACE
=cut
=head2 new
Create a new Publican::TreeView object.
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $self = bless {}, $class;
my $publican = Publican->new();
$self->{publican} = $publican;
$self->{first} = 1;
return $self;
}
=head2 print_tree
Print out a tree view of xi:includes
=cut
sub print_tree {
my ( $self, $args ) = @_;
my $dir;
my $in_file = ( delete $args->{'in_file'}
|| ( $self->{publican}->param('mainfile') ) . '.xml' );
my $indent = ( delete $args->{'indent'} || 1 );
my $path = ( delete $args->{'path'} || '' );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
if ( $in_file eq $self->{publican}->param('mainfile') . '.xml' ) {
$dir = pushd( $self->{publican}->param('xml_lang') );
logger("$in_file\n");
}
elsif ( dirname($in_file) ne '.' ) {
$path = dirname($in_file) . '/';
}
my $xml_doc = XML::TreeBuilder->new();
$xml_doc->parse_file($in_file)
|| croak( maketext( "Can't open file: [_1]: [_2]", $in_file, $@ ) );
my @nodes = $xml_doc->look_down( "_tag", "xi:include" );
foreach my $node (@nodes) {
my $filename = $node->attr('href');
if ( -f "$path$filename" ) {
if ( "$filename" =~ /\.xml$/ ) {
if ( $node->attr('parse') && $node->attr('parse') eq 'text' )
{
logger( " " x $indent . "$path$filename\n", GREEN );
}
else {
logger( " " x $indent . "$path$filename\n" );
$self->print_tree(
{ in_file => "$path$filename",
indent => ( $indent + 1 ),
path => $path,
}
);
}
}
else {
logger( " " x $indent . "$path$filename\n", MAGENTA );
}
}
else {
logger( " " x $indent . "$path$filename*\n", RED );
}
}
return;
}
=head2 print_unused
Print out a list of XML files that are not xi:included
=cut
sub print_unused {
my ( $self, $args ) = @_;
my $dir;
my $in_file = ( delete $args->{'in_file'}
|| ( $self->{publican}->param('mainfile') ) . '.xml' );
my $path = ( delete $args->{'path'} || '' );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $unused = 0;
if ( $self->{first} ) {
$self->{first} = 0;
$unused = 1;
}
my $xml_lang = $self->{publican}->param('xml_lang');
if ( $in_file eq $self->{publican}->param('mainfile') . '.xml' ) {
$dir = pushd($xml_lang);
}
elsif ( dirname($in_file) ne '.' ) {
$path = dirname($in_file) . '/';
}
my $xml_doc = XML::TreeBuilder->new();
$xml_doc->parse_file($in_file)
|| croak( maketext( "Can't open file: [_1]: [_2]", $in_file, $@ ) );
my @nodes = $xml_doc->look_down( "_tag", "xi:include" );
foreach my $node (@nodes) {
my $filename = $node->attr('href');
if ( -f "$path$filename" && $filename =~ /\.xml$/ ) {
if ( !$node->attr('parse') || $node->attr('parse') ne 'text' ) {
$self->print_unused(
{ 'in_file' => "$path$filename", path => $path, } );
}
$filename = Cwd::realpath("$path$filename");
$filename = File::Spec->abs2rel($filename);
$self->{used_files}->{qq|'$filename'|} = 1;
}
}
$dir = undef;
if ($unused) {
my @xml_files = dir_list( $xml_lang, '*.xml' );
my $first = 1;
foreach my $xml_file ( sort(@xml_files) ) {
$xml_file =~ s/^$xml_lang\///;
next
if (
$xml_file eq $self->{publican}->param('mainfile') . '.xml' );
unless ( ( defined $self->{used_files}->{qq|'$xml_file'|} )
|| ( defined $self->{used_files}->{qq|'./$xml_file'|} ) )
{
if ($first) {
logger(
maketext("\nList of unused XML files in $xml_lang")
. "\n" );
$first = 0;
}
logger( " " . "$xml_file\n", RED );
}
}
if ($first) {
logger( maketext("\nNo unused XML files") . "\n" );
}
logger("\n");
}
return;
}
=head2 print_unused_images
Print out a list of image files that are not used.
=cut
sub print_unused_images {
my ( $self, $args ) = @_;
my $in_file = ( delete $args->{'in_file'}
|| ( $self->{publican}->param('mainfile') ) . '.xml' );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my ( %used_files, %missing_files );
my $xml_lang = $self->{publican}->param('xml_lang');
my @xml_files = dir_list( $xml_lang, '*.xml' );
my $first = 1;
foreach my $xml_file ( sort(@xml_files) ) {
my $xml_doc = XML::TreeBuilder->new();
$xml_doc->parse_file($xml_file)
|| croak(
maketext( "Can't open file: [_1]: [_2]", $xml_file, $@ ) );
my @nodes = $xml_doc->look_down( "_tag", "imagedata" );
foreach my $node (@nodes) {
my $filename = $node->attr('fileref');
$filename =~ s/'//g;
if ( -f "$xml_lang/$filename" ) {
$used_files{"$filename"} = 1;
}
else {
$missing_files{"$filename"} = 1;
}
}
}
my @image_files = dir_list( $xml_lang, '.*\.(svg|png|jpg|jpeg|gif)$', 1 );
$first = 1;
foreach my $image ( sort(@image_files) ) {
$image =~ s/^$xml_lang\///;
unless ( ( defined $used_files{"$image"} )
|| ( defined $used_files{"./$image"} ) )
{
if ($first) {
logger( "\n"
. maketext("List of unused Image files in $xml_lang")
. "\n" );
$first = 0;
}
logger( " " . "$image\n", RED );
}
}
if ($first) {
logger( "\n" . maketext("No unused Image files") . "\n" );
}
if (%missing_files) {
logger( "\n"
. maketext("List of missing Image files in $xml_lang")
. "\n" );
foreach my $image ( sort( keys %missing_files ) ) {
logger( " " . "$image\n", RED );
}
}
logger("\n");
return;
}
1; # Magic true value required at end of module
__END__
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=item C<< Can't open file %s >>
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
XML::TreeBuilder
Publican
File::pushd
Term::ANSIColor
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Ryan Lerch C<< >>
Builder 000755 041472 041472 0 12555605450 17633 5 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican DocBook5.pm 000444 041472 041472 60471 12555605450 21763 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican/Builder package Publican::Builder::DocBook5;
use utf8;
use strict;
use warnings;
use 5.008;
use base 'Publican::Builder::DocBook';
use Publican::Builder;
use Publican::Builder::DocBook;
use Carp;
use Publican;
use Publican::XmlClean;
use Publican::Translate;
use File::Path;
use File::pushd;
use File::Find;
use XML::LibXML;
use Cwd qw(abs_path);
use Archive::Tar;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use DateTime;
use DateTime::Format::DateParse;
use Syntax::Highlight::Engine::Kate;
use HTML::TreeBuilder;
use HTML::FormatText;
use HTML::FormatText::WithLinks::AndTables;
use HTML::FormatText::WithLinks;
use Term::ANSIColor qw(:constants);
use POSIX qw(floor :sys_wait_h);
use Locale::Language;
use List::Util qw(max);
use Text::Wrap qw(fill $columns);
use IO::String;
use File::Which;
use Text::CSV_XS;
use Publican::ConfigData;
use Sort::Versions;
use Template;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
use vars qw(@ISA @EXPORT @EXPORT_OK);
@ISA = qw(Publican::Builder::DocBook);
=head1 NAME
Publican::Builder::DocBook5 - A module to Convert XML to various output formats
=head1 SYNOPSIS
use Publican::Builder::DocBook5;
my $builder = Publican::Builder::DocBook5->new();
$builder->clean_ids();
=head1 DESCRIPTION
Manipulate DocBook 4 XML and convert to other formats.
=head1 INTERFACE
=cut
=head2 new
Create a new Publican::Builder::DocBook5 object.
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $self = $class->SUPER::new($args);
bless $self, $class;
$self->{id_attr} = "xml:id";
return $self;
}
=head2 setup_xml
Create the proper directory structure for the XML, including copying in Brand files.
=cut
sub setup_xml {
my ( $self, $args ) = @_;
my $xml_lang = $self->{publican}->param('xml_lang');
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $type = $self->{publican}->param('type');
my $exlude_common = delete( $args->{'exlude_common'} ) || undef;
my $langs = delete( $args->{langs} )
|| croak( maketext("langs is a mandatory argument") );
my $distributed_set = delete( $args->{distributed_set} ) || 0;
my $drupal = delete( $args->{drupal} ) || 0;
my $cleaning = delete( $args->{cleaning} ) || 0;
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $extras = $self->{publican}->param('extras_dir');
my $main_file = $self->{publican}->param('mainfile');
my $ent_file = undef;
$ent_file = "$main_file.ent"
if ( defined($main_file) && -e "$xml_lang/$main_file.ent" );
foreach my $lang ( split( /,/, $langs ) ) {
logger( maketext( "Setting up [_1]", $lang ) . "\n" );
croak(
maketext(
"Invalid build request: language directory [_1] does not exist.",
$lang
)
) if ( !-d $lang );
mkpath("$tmp_dir/$lang/xml");
my $lc_lang = $lang;
$lc_lang =~ s/-/_/g;
my $locale = Publican::Localise->get_handle($lc_lang)
|| croak(
"Could not create a Publican::Localise object for language: [_1]",
$lang
);
$locale->encoding("UTF-8");
$locale->textdomain("publican");
if ( $lang eq $xml_lang ) {
if ($drupal) {
# preprocess. set the unique id for every sections
my $set_ids = Publican::XmlClean->new( { unique_id => 1 } );
logger( maketext("Preprocessing xml files...\n") );
$set_ids->set_unique_ids();
logger( maketext("Finish preprocess\n") );
}
dircopy( $lang, "$tmp_dir/$lang/xml_tmp" );
}
elsif ( ( $self->{publican}->param('ignored_translations') )
&& ($self->{publican}->param('ignored_translations') =~ m/$lang/ )
)
{
logger(
"\t"
. maketext( "Bypassing translation for [_1]", $lang )
. "\n",
GREEN
);
dircopy( $self->{publican}->param('xml_lang'),
"$tmp_dir/$lang/xml_tmp" );
}
else {
my @po_files = dir_list( $lang, '*.po' );
croak(
maketext(
"Invalid build request: no PO files exist for language [_1]",
$lang
)
) unless (@po_files);
mkpath("$tmp_dir/$lang/xml_tmp");
my $source_dir = $self->{publican}->param('xml_lang');
$source_dir = 'trans_drop' if ( -d 'trans_drop' );
my $extras = $self->{publican}->param('extras_dir');
my @xml_files = dir_list( $source_dir, '*.xml' );
rcopy( "$xml_lang/$ent_file", "$tmp_dir/$lang/xml_tmp/." )
if ( $ent_file && -e "$xml_lang/$ent_file" );
rcopy( "$lang/$ent_file", "$tmp_dir/$lang/xml_tmp/." )
if ( $ent_file && -e "$lang/$ent_file" );
foreach my $xml_file ( sort(@xml_files) ) {
next if ( $xml_file =~ m|$source_dir/$extras/| );
my $po_file = $xml_file;
$po_file =~ s/\.xml/\.po/;
$po_file =~ s/$source_dir/$lang/;
my $out_file = $xml_file;
$out_file =~ s/$source_dir//;
$out_file =~ m|^(.*)/[^/]+$|;
my $path = ( $1 || undef );
mkpath("$tmp_dir/$lang/xml_tmp/$path")
if ( $path && !-d $path );
if ( !-f $po_file ) {
logger(
"\t"
. maketext(
"PO file '[_1]' not found! Using base XML!",
$po_file )
. "\n",
CYAN
);
rcopy( $xml_file, "$tmp_dir/$lang/xml_tmp/$out_file" );
}
else {
$self->{translator}->po2xml(
{ xml_file => $xml_file,
po_file => $po_file,
out_file => "$tmp_dir/$lang/xml_tmp/$out_file",
ent_file => $ent_file,
}
);
}
}
my $rev_file = "Revision_History.xml";
$rev_file = $self->{publican}->param('rev_file')
if ( $self->{publican}->param('rev_file') );
if ( -f "$lang/$rev_file" ) {
my $rev_tree = $self->{publican}->new_tree();
my $trans_rev_tree = $self->{publican}->new_tree();
eval {
$rev_tree->parse_file("$tmp_dir/$lang/xml_tmp/$rev_file");
};
if ($@) {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
eval { $trans_rev_tree->parse_file("$lang/$rev_file"); };
if ($@) {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
my $id = undef;
my $anode = $rev_tree->look_down( '_tag', "appendix" );
$id = $anode->id() if ( $anode && $anode->id() );
my $merged_rev_tree = XML::Element->new_from_lol(
[ 'appendix',
{ id => $id },
[ 'title',
decode_utf8(
$locale->maketext('Revision History')
)
],
[ 'simpara', ['revhistory'], ],
],
);
my $node
= $merged_rev_tree->look_down( '_tag', "revhistory" );
my @revisions = sort {
versioncmp(
$b->look_down( '_tag', "revnumber" )->as_text(),
$a->look_down( '_tag', "revnumber" )->as_text()
)
} (
$rev_tree->look_down( '_tag', "revision" ),
$trans_rev_tree->look_down( '_tag', "revision" )
);
if ( $self->{publican}->param('rev_dir')
&& $self->{publican}->param('rev_dir') =~ /^asc/i )
{
@revisions = reverse(@revisions);
}
$node->push_content(@revisions);
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)",
"$tmp_dir/$lang/xml_tmp/$rev_file" )
|| croak(
maketext(
"Could not open [_1] for output!",
"$tmp_dir/$lang/xml_tmp/$rev_file",
$@
)
);
print( $OUTDOC dtd_string(
{ tag => 'appendix',
dtdver => $self->{publican}->param('dtdver'),
cleaning => 1
}
)
);
print( $OUTDOC $merged_rev_tree->as_XML() );
close($OUTDOC);
}
my $trans_file = "$lang/Author_Group.xml";
if ( -f $trans_file ) {
my $auth_file = "$tmp_dir/$lang/xml_tmp/Author_Group.xml";
my $auth_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
eval { $auth_doc->parse_file($auth_file); };
if ($@) {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
my $auth_node = eval {
$auth_doc->root()->look_down( "_tag", "authorgroup" );
};
if ($@) {
croak(
maketext(
"authorgroup not found in [_1]", $auth_file
)
);
}
my $trans_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
eval { $trans_doc->parse_file($trans_file); };
if ($@) {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
my $trans_node = eval {
$trans_doc->root()->look_down( "_tag", "authorgroup" );
};
if ($@) {
croak(
maketext(
"authorgroup not found in [_1]", $trans_file
)
);
}
$auth_doc->push_content( $trans_doc->detach_content() );
my $text = $auth_doc->as_XML();
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", $auth_file )
|| croak(
maketext( "Could not open [_1] for output!", $auth_file )
);
print( $OUTDOC $text );
close($OUTDOC);
$auth_doc->root()->delete();
$trans_node->root()->delete();
}
}
# clean XML
my $cleaner = Publican::XmlClean->new(
{ lang => $lang,
donotset_lang => $exlude_common,
distributed_set => $distributed_set,
cleaning => $cleaning,
}
);
my @xml_files = dir_list( "$tmp_dir/$lang/xml_tmp", '*.xml' );
# copy css for brand and default images for non-brand
if ( $type eq 'brand' ) {
dircopy( "$lang/css", "$tmp_dir/$lang/xml/css" )
if ( -d "$lang/css" );
dircopy( "$lang/scripts", "$tmp_dir/$lang/xml/scripts" )
if ( -d "$lang/scripts" );
}
my $images = $self->{publican}->param('img_dir');
if ( $type ne 'brand' ) {
dircopy( "$xml_lang/$images", "$tmp_dir/$lang/xml/$images" )
if ( -d "$xml_lang/$images" );
}
dircopy( "$lang/$images", "$tmp_dir/$lang/xml/$images" )
if ( -d "$lang/$images" );
unless ($exlude_common) {
mkpath("$tmp_dir/$lang/xml/Common_Content");
# copy common files
my $common_content = $self->{publican}->param('common_content');
my $brand = $self->{publican}->param('brand');
my $base_brand
= ( $self->{publican}->{brand_config}->param('base_brand')
|| 'common' );
if ( $common_content =~ m/\"/ & $common_content !~ m/\s/ ) {
$common_content =~ s/\"//g;
}
my $brand_path = $self->{publican}->param('brand_dir')
|| $common_content . "/$brand";
# don't copy installed base brand when testing base brands
rcopy_glob(
$common_content . "/$base_brand/en-US/*",
"$tmp_dir/$lang/xml/Common_Content"
)
unless ( ( $brand eq $base_brand )
&& ( $brand_path ne $common_content . "/$brand" ) );
if ( $lang ne 'en-US' ) {
if ( -d $common_content . "/$base_brand/$lang" ) {
rcopy_glob(
$common_content . "/$base_brand/$lang/*",
"$tmp_dir/$lang/xml/Common_Content"
);
}
elsif (
defined( $LANG_MAP{$lang} )
&& ( -d $common_content
. "/$base_brand/"
. $LANG_MAP{$lang} )
)
{
rcopy_glob(
$common_content
. "/$base_brand/"
. $LANG_MAP{$lang} . "/*",
"$tmp_dir/$lang/xml/Common_Content"
);
}
}
if ( ( $brand ne $base_brand )
|| ( $brand_path ne $common_content . "/$brand" ) )
{
my $brand_lang
= $self->{publican}->{brand_config}->param('xml_lang');
my @files = rcopy_glob(
$brand_path . "/$brand_lang/*",
"$tmp_dir/$lang/xml/Common_Content"
);
croak(
maketext(
"Brand '[_1]' had no content to copy.", $brand
)
) if ( scalar(@files) == 0 );
if ( $lang ne $brand_lang ) {
if ( -d $brand_path . "/$lang" ) {
rcopy_glob( "$brand_path/$lang/*",
"$tmp_dir/$lang/xml/Common_Content" );
}
elsif ( defined( $LANG_MAP{$lang} )
&& ( -d $brand_path . "/" . $LANG_MAP{$lang} ) )
{
rcopy_glob(
"$brand_path/" . $LANG_MAP{$lang} . "/*",
"$tmp_dir/$lang/xml/Common_Content"
);
}
}
}
rcopy( "$xml_lang/$ent_file", "$tmp_dir/$lang/xml/." )
if ( $ent_file && -e "$xml_lang/$ent_file" );
rcopy( "$lang/$ent_file", "$tmp_dir/$lang/xml/." )
if ( $ent_file && -e "$lang/$ent_file" );
dircopy( "$xml_lang/$extras", "$tmp_dir/$lang/xml/$extras" )
if ( -d "$xml_lang/$extras" );
dircopy( "$lang/$extras", "$tmp_dir/$lang/xml/$extras" )
if ( -d "$lang/$extras" );
my @com_xml_files
= dir_list( "$tmp_dir/$lang/xml/Common_Content", '*.xml' );
$cleaner->{config}->param( 'common', 1 );
foreach my $xml_file ( sort(@com_xml_files) ) {
my $out_file = $xml_file;
chmod( 0664, $out_file );
if ( !$self->{publican}->{'no_clean'} ) {
$cleaner->process_file(
{ file => $xml_file, out_file => $out_file } );
}
}
}
if ( $type eq 'Set'
and !defined( $self->{publican}->{config}->param('scm') )
and defined( $self->{publican}->{config}->param('books') ) )
{
foreach my $xml_file ( sort(@xml_files) ) {
my $out_file = $xml_file;
$out_file =~ s/xml_tmp/xml/;
rcopy( $xml_file, $out_file );
}
my @ent_files = dir_list( $lang, '*.ent' );
foreach my $ent_file ( sort(@ent_files) ) {
my $out_file = $ent_file;
$out_file =~ s/$lang/$tmp_dir\/$lang\/xml/;
rcopy( $ent_file, $out_file );
}
}
else {
foreach my $xml_file ( sort(@xml_files) ) {
next if ( $xml_file =~ m{/$extras/} );
my $out_file = $xml_file;
$out_file =~ s/xml_tmp/xml/;
if ( $self->{publican}->{'no_clean'} ) {
rcopy( $xml_file, $out_file );
}
else {
$cleaner->process_file(
{ file => $xml_file, out_file => $out_file } );
}
}
}
finddepth( \&del_unwanted_dirs, $tmp_dir );
}
return;
}
=head2 clean_ids
Travers over the source XML and update the id's to match the standard format.
Updates all existing PO files with the new xref links.
=cut
sub clean_ids {
my ( $self, $args ) = @_;
# if ( %{$args} ) {
# croak "unknown args: " . join( ", ", keys %{$args} );
# }
my @xml_files = dir_list( $self->{publican}->param('xml_lang'), '*.xml' );
my $cleaner
= Publican::XmlClean->new( { clean_id => 1, id_attr => 'xml:id' } );
my $extras = $self->{publican}->param('extras_dir');
foreach my $xml_file ( sort(@xml_files) ) {
next if ( $xml_file =~ m{/$extras/} );
$cleaner->process_file(
{ file => $xml_file, out_file => $xml_file } );
}
return;
}
=head2 validate_xml
Ensure the XML validates against the DTD.
To debug the XML catalogs
export XML_DEBUG_CATALOG=1
test...
unset XML_DEBUG_CATALOG
=cut
sub validate_xml {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak( maketext("lang is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $docname = $self->{publican}->param('docname');
my $dtdver = $self->{publican}->param('dtdver');
my $main_file = $self->{publican}->param('mainfile');
if ( ( $self->{publican}->param('ignored_translations') )
&& ( $self->{publican}->param('ignored_translations') =~ m/$lang/ ) )
{
logger(
maketext( "Bypassing test for language: [_1]", $lang ) . "\n" );
return (0);
}
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $dir = pushd("$tmp_dir/$lang/xml");
my $parser = XML::LibXML->new(
{ pedantic_parser => 1,
suppress_errors => 0,
suppress_warnings => 0,
line_numbers => 1,
expand_xinclude => 1,
no_network => !$self->{publican}->{allow_network}
}
);
croak(
maketext( "Cannot locate main XML file: '[_1]'", "$main_file.xml" ) )
unless ( -f "$main_file.xml" );
my $source;
eval { $source = $parser->parse_file("$main_file.xml"); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR 3: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
}
## BUGBUG how does this get localised?
# e.g. even though /usr/share/xml/docbook5/schema/rng/5.0/catalog.xml contains a local link
# setting location = http://docbook.org/xml/5.0/rng/docbook.rng still does a web look up :(
## BUGBUG also need to change header ... entities?
# http://www.docbook.org/xml/5.1b2/rng/docbook.rng
# http://www.docbook.org/xml/5.0/rng/docbook.rng
# wget http://docbook.org/xml/5.1b2/tools/db4-upgrade.xsl
# for file in `ls *.xml`; do echo "$file"; xsltproc ../../db4-upgrade-publican.xsl $file > $file.tmp;mv $file.tmp $file; echo; done
my $rngschema = XML::LibXML::RelaxNG->new(
location => "http://docbook.org/xml/$dtdver/rng/docbook.rng" );
eval { $rngschema->validate($source); };
if ($@) {
logger(
maketext("RelaxNG Validation failed for '$dir/$main_file.xml': ")
. "\nIGNORING: Validation is broken, see BZ #1097495\n",
RED
);
## croak("$@\n$!\n");
}
logger("RelaxNG Validation OK\n");
$dir = undef;
return (0);
}
=head2 get_author_list
Return the author list for the supplied language.
## BUGBUG this should be moved to the DocBook sub classes
=cut
sub get_author_list {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak( maketext("lang is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my @authors;
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $file = "$tmp_dir/$lang/xml/Author_Group.xml";
croak( maketext("ERROR: Cannot find Author file Author_Group.xml.") )
unless ( -f $file );
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "0", 'ErrorContext' => "2" } );
eval { $xml_doc->parse_file($file); };
if ($@) {
croak( maketext( "FATAL ERROR: [_1]", $@ ) );
}
foreach my $author (
$xml_doc->root()->look_down( "_tag", qr/^(?:author|orgname)$/ ) )
{
if ( $author->tag() =~ /^(?:orgname)$/ ) {
my $name;
eval { $name = $author->as_text; };
if ($@) {
croak(
maketext(
"corpauthor can not be converted to text as expected."
)
);
}
push( @authors, "$name" );
}
else {
my ( $fn, $sn );
eval { $fn = $author->look_down( "_tag", 'firstname' )->as_text; };
if ($@) {
croak(
maketext(
"Authorтs firstname not found in Author_Group.xml as expected."
)
);
}
eval { $sn = $author->look_down( "_tag", 'surname' )->as_text; };
if ($@) {
croak(
maketext(
"Authorтs surname not found in Author_Group.xml as expected."
)
);
}
push( @authors, "$fn $sn" );
}
}
return (@authors);
}
1; # Magic true value required at end of module
__END__
=head1 DIAGNOSTICS
=over
=item C<< unknown args %s >>
All subs with named parameters will return this error when unexpected named arguments are provided.
=item C<< %s is a required argument >>
Any sub with a mandatory parameter will return this error if the parameter is undef.
=back
=head1 CONFIGURATION AND ENVIRONMENT
Publican requires no configuration files or environment variables.
=head1 DEPENDENCIES
Carp
version
Publican
Publican::XmlClean
Publican::Translate
File::Path
File::pushd
File::Find
XML::LibXML
Cwd
Archive::Tar
DateTime
DateTime::Format::DateParse
Syntax::Highlight::Engine::Kate
HTML::TreeBuilder
HTML::FormatText
Term::ANSIColor
POSIX
=head1 INCOMPATIBILITIES
None reported.
=head1 BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to
C, or through the web interface at
L.
=head1 AUTHOR
Jeff Fearn C<< >>
DocBook.pm 000444 041472 041472 417742 12555605450 21725 0 ustar 00lnewson lnewson 000000 000000 Publican-v4.3.2/lib/Publican/Builder package Publican::Builder::DocBook;
use utf8;
use strict;
use warnings;
use 5.008;
use base 'Publican::Builder';
use Publican::Builder;
use Carp;
use Publican;
use Publican::XmlClean;
use Publican::Translate;
use File::Path;
use File::pushd;
use File::Find;
use XML::LibXSLT;
use XML::LibXML;
use Cwd qw(abs_path);
use Archive::Tar;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use DateTime;
use DateTime::Format::DateParse;
use Syntax::Highlight::Engine::Kate;
use HTML::TreeBuilder;
use HTML::FormatText;
use HTML::FormatText::WithLinks::AndTables;
use HTML::FormatText::WithLinks;
use Term::ANSIColor qw(:constants);
use POSIX qw(floor :sys_wait_h);
use Locale::Language;
use List::Util qw(max);
use Text::Wrap qw(fill $columns);
use IO::String;
use File::Which;
use Publican::ConfigData;
use Sort::Versions;
use Template;
use Encode qw(is_utf8 decode_utf8 encode_utf8);
use Data::Dumper;
use HTML::WikiConverter;
use File::Slurp;
use vars qw(@ISA @EXPORT @EXPORT_OK);
@ISA = qw(Publican::Builder);
%HTML::Element::optionalEndTag = ();
our ( %CHUNK_TAGS );
%CHUNK_TAGS = (
book => { format => 'bk%02d', any_level => 1 },
article => { format => 'ar%02d', any_level => 1 },
chapter => { format => 'ch%02d', any_level => 1 },
appendix => { format => 'ap%s', any_level => 1, use_alpha => 1 },
part => { format => 'pt%02d', any_level => 1 },
preface => { format => 'pr%02d', any_level => 1 },
index => { format => 'ix%02d', any_level => 1 },
reference => { format => 'rn%02d', any_level => 1 },
refentry => { format => 're%02d', any_level => 1 },
colophon => { format => 'co%02d', any_level => 1 },
bibliography => { format => 'bi%02d', any_level => 1 },
glossary => { format => 'go%02d', any_level => 1 },
topic => { format => 'to%02d', any_level => 1 },
section => { format => 's%02d', use_parent => 1 },
sect1 => { format => 's%02d', use_parent => 1 },
sect2 => { format => 's%02d', use_parent => 1 },
sect3 => { format => 's%02d', use_parent => 1 },
sect4 => { format => 's%02d', use_parent => 1 },
sect5 => { format => 's%02d', use_parent => 1 },
legalnotice => { format => 'ln%02d', any_level => 1 },
);
=head1 NAME
Publican::Builder::DocBook - A module to Convert XML to various output formats
=head1 SYNOPSIS
use Publican::Builder::DocBook;
my $builder = Publican::Builder::DocBook->new();
$builder->clean_ids();
=head1 DESCRIPTION
Manipulate DocBook XML and convert to other formats.
=head1 INTERFACE
=cut
=head2 new
Create a new Publican::Builder::DocBook object.
=cut
sub new {
my ( $this, $args ) = @_;
my $class = ref($this) || $this;
my $self = $class->SUPER::new($args);
bless $self, $class;
return $self;
}
=head2 build
Transform the source in to another format.
=cut
sub build {
my ( $self, $args ) = @_;
my $langs = delete( $args->{langs} )
|| croak( maketext("langs is a mandatory argument") );
my $formats = delete( $args->{formats} )
|| croak( maketext("formats is a mandatory argument") );
my $publish = delete( $args->{publish} ) || undef;
my $embedtoc = delete( $args->{embedtoc} ) || undef;
my $distributed_set = delete( $args->{distributed_set} ) || 0;
my $pdftool = delete( $args->{pdftool} ) || undef;
my $pub_dir = delete( $args->{pub_dir} )
|| croak( maketext("pub_dir is a mandatory argument") );
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
my $product = $self->{publican}->param('product');
my $version = $self->{publican}->param('version');
my $docname = $self->{publican}->param('docname');
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $type = $self->{publican}->param('type');
my $brand = $self->{publican}->param('brand');
if ( ( $type eq 'Set' ) && ( $self->{publican}->{config}->param('scm') ) )
{
$self->get_books();
$self->build_set_books( { langs => $langs } );
}
if ( $langs =~ /^all$/i ) {
$langs = get_all_langs();
}
my $drupal = 0;
if ( $formats =~ /drupal-book/ ) {
$drupal = 1;
}
$self->setup_xml(
{ langs => $langs,
exlude_common => ( $type eq 'brand' ),
distributed_set => $distributed_set,
drupal => $drupal
}
);
foreach my $lang ( sort( split( /,/, $langs ) ) ) {
logger( maketext( "Beginning work on [_1]", $lang ) . "\n" );
# hmmm can't validate brand XML as it's incomplete
if ( ( $type ne 'brand' )
and $self->{validate}
and ( $self->validate_xml( { lang => $lang } ) == $INVALID ) )
{
logger(
maketext(
"All build formats will be skipped for language: [_1]",
$lang )
. "\n",
RED
);
next;
}
# catch txt not being rebuilt BZ #802576
my $rebuild = 1;
foreach my $format ( split( /,/, $formats ) ) {
logger( "\t" . maketext( "Starting [_1]", $format ) . "\n" );
if ( $format eq 'test' ) {
logger( "\t" . maketext( "Finished [_1]", $format ) . "\n" );
next;
}
$self->transform(
{ format => $format,
lang => $lang,
embedtoc => $embedtoc,
rebuild => $rebuild,
pdftool => $pdftool,
}
) unless ( $format eq 'xml' );
$rebuild = 0
if ( $format eq 'txt' || $format eq 'html-single-plain' );
if ($publish) {
if ( $type eq 'brand' ) {
my $path = "$pub_dir/$brand/$lang";
mkpath($path);
rcopy( "$tmp_dir/$lang/$format/*", "$path/." )
if ( -d "$tmp_dir/$lang/$format" );
}
else {
my $path
= "$pub_dir/$lang/$product/$version/$format/$docname";
# The basic layout is for the web system
# but these formats are used differently
if ( $self->{publican}->param('web_home') ) {
$path = "$pub_dir/home/$lang";
}
elsif ( $self->{publican}->param('web_type') ) {
my $web_type = $self->{publican}->param('web_type');
if ( $web_type =~ m/^home$/i ) {
$path = "$pub_dir/home/$lang";
fcopy( 'site_overrides.css',
"$pub_dir/home/site_overrides.css" )
if ( -f 'site_overrides.css' );
# Build ADs
if ( -f "$tmp_dir/$lang/xml/Ads.xml" ) {
mkpath($path);
my $common_config = $self->{publican}
->param('common_config');
my $xsl_file
= $common_config . "/xsl/carousel.xsl";
# required for Windows
$xsl_file =~ s/"//g;
my $parser = XML::LibXML->new();
my $xslt = XML::LibXSLT->new();
my $source;
eval {
$source
= $parser->parse_file(
"$tmp_dir/$lang/xml/Ads.xml");
};
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR 1: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak(
maketext(
"FATAL ERROR 2: [_1]", $@
)
);
}
}
my $style_doc
= $parser->parse_file($xsl_file);
my $stylesheet
= $xslt->parse_stylesheet($style_doc);
my $results = $stylesheet->transform($source);
my $outfile;
my $ad_file = "$path/carousel.html";
open( $outfile, ">:encoding(UTF-8)",
"$ad_file" )
|| croak(
maketext(
"Can't open ad file: [_1]", $@
)
);
print( $outfile $stylesheet->output_string(
$results) );
close($outfile);
unlink("$tmp_dir/$lang/xml/Ads.xml");
}
}
elsif ( $web_type =~ m/^product$/i ) {
$path = "$pub_dir/home/$lang/$product";
my $tmpl_dir = "$pub_dir/datadir/templates/groups/$lang/$product";
# Copy External Links
if ( -f "$tmp_dir/$lang/xml/External_Links.xml" )
{
mkpath($tmpl_dir);
fcopy(
"$tmp_dir/$lang/xml/External_Links.xml",
"$tmpl_dir/External_Links.xml"
);
unlink(
"$tmp_dir/$lang/xml/External_Links.xml");
}
if ( -f "$tmp_dir/$lang/xml/Groups.xml" ) {
mkpath($tmpl_dir);
my $xml_doc = XML::TreeBuilder->new(
{ 'NoExpand' => "0",
'ErrorContext' => "2"
}
);
eval {
$xml_doc->parse_file(
"$tmp_dir/$lang/xml/Groups.xml");
};
if ($@) {
croak(
maketext( "FATAL ERROR 3: [_1]", $@ )
);
}
foreach my $node (
$xml_doc->look_down(
'_tag', 'varlistentry'
)
)
{
my $sort = $node->attr('role');
croak(
maketext(
"varlistentry must have it's attribute 'role' set to an integer"
)
)
if ( !defined($sort)
|| $sort !~ /^\d+$/ );
my $subtitles = 0;
my $annot = $node->attr('annotations');
$subtitles = 1
if ( $annot && lc($annot) eq 'yes' );
my $term
= $node->look_down( '_tag', 'term' )
->as_trimmed_text();
my $text = $node->look_down( '_tag',
'listitem' )->as_trimmed_text();
my $OUT;
open( $OUT, ">:encoding(UTF-8)",
"$tmpl_dir/$sort.tmpl" )
|| croak( maketext("BURP") );
print( $OUT <
\t\t\t\t\t\t\t$term
EOL
);
print( $OUT <$text
EOL
) if ( $text && $text ne "" );
print( $OUT <
EOL
);
=cut
close($OUT);
}
unlink("$tmp_dir/$lang/xml/Groups.xml");
}
}
elsif ( $web_type =~ m/^version$/i ) {
$path = "$pub_dir/home/$lang/$product/$version";
}
}
elsif ( $format eq 'html-desktop' ) {
$path = "$pub_dir/desktop/$lang";
}
elsif ( $format eq 'xml' ) {
$path = "$pub_dir/xml/$lang";
}
elsif ( $format eq 'eclipse' ) {
$path = "$pub_dir/eclipse/$lang";
}
mkpath($path);
if ( $format eq 'epub' ) {
fcopy( "$tmp_dir/$lang/" . $self->{epub_name},
"$path/." );
}
else {
rcopy( "$tmp_dir/$lang/$format/*", "$path/." )
if ( -d "$tmp_dir/$lang/$format" );
# for splash pages, we need to rename them if using a web style 2
if ($self->{publican}->param('web_type')
## && $self->{publican}->param('web_style') == 2
)
{
fmove( "$path/index.html", "$path/splash.html" );
}
}
}
}
logger( "\t" . maketext( "Finished [_1]", $format ) . "\n" );
}
}
if ($publish) {
if ( $type eq 'brand' ) {
if ( -d 'xsl' ) {
my $path = "$pub_dir/$brand/xsl";
mkpath($path);
rcopy( "xsl", "$path/." );
}
if ( -d 'book_templates' ) {
my $path = "$pub_dir/$brand/book_templates";
mkpath($path);
rcopy( "book_templates", "$path/." );
}
if ( -d 'templates' ) {
my $path = "$pub_dir/$brand/templates";
mkpath($path);
rcopy( "templates", "$path/." );
}
}
}
debug_msg("end of build\n");
return;
}
=head2 transform
Run XSLT over XML
=cut
sub transform {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak( maketext("lang is a mandatory argument") );
my $format = delete( $args->{format} )
|| croak( maketext("format is a mandatory argument") );
my $embedtoc = delete( $args->{embedtoc} ) || 0;
my $rebuild = delete( $args->{rebuild} ) || 0;
my $pdftool = delete( $args->{pdftool} ) || undef;
if ( %{$args} ) {
croak(
maketext(
"unknown arguments: [_1]", join( ", ", keys %{$args} )
)
);
}
if ( defined($pdftool) && ( $pdftool !~ /^(?:fop|wkhtmltopdf)$/ ) ) {
croak(
maketext(
"pdftool only supports fop or wkhtmltopdf, not: [_1]",
$pdftool
)
);
}
my $dir;
my $lc_lang = $lang;
$lc_lang =~ s/-/_/g;
my $locale = Publican::Localise->get_handle($lc_lang)
|| croak(
"Could not create a Publican::Localise object for language: [_1]",
$lang );
$locale->encoding("UTF-8");
$locale->textdomain("publican");
## BUGBUG test an alternative to fop!
my $wkhtmltopdf_cmd = which('wkhtmltopdf');
my $diefopdie = ( $wkhtmltopdf_cmd && $wkhtmltopdf_cmd ne '' );
$diefopdie = 0 if ( $pdftool && $pdftool eq 'fop' );
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $docname = $self->{publican}->param('docname');
my $common_config = $self->{publican}->param('common_config');
my $common_content = $self->{publican}->param('common_content');
my $brand = $self->{publican}->param('brand');
my $toc_section_depth = $self->{publican}->param('toc_section_depth');
my $confidential = $self->{publican}->param('confidential');
my $confidential_text = $self->{publican}->param('confidential_text');
my $show_remarks = $self->{publican}->param('show_remarks');
my $generate_section_toc_level
= $self->{publican}->param('generate_section_toc_level');
my $chunk_section_depth = $self->{publican}->param('chunk_section_depth');
my $doc_url = $self->{publican}->param('doc_url');
my $prod_url = $self->{publican}->param('prod_url');
my $chunk_first = $self->{publican}->param('chunk_first');
my $xml_lang = $self->{publican}->param('xml_lang');
my $classpath = $self->{publican}->param('classpath');
my $type = lc( $self->{publican}->param('type') );
my $ec_name = $self->{publican}->param('ec_name');
my $ec_id = $self->{publican}->param('ec_id');
my $ec_provider = $self->{publican}->param('ec_provider');
my $product = $self->{publican}->param('product');
my $bridgehead_in_toc = $self->{publican}->param('bridgehead_in_toc');
my $main_file = $self->{publican}->param('mainfile');
my $brand_path = $self->{publican}->param('brand_dir')
|| $common_content . "/$brand";
my $base_brand = $self->{publican}->{brand_config}->param('base_brand');
my $web_type = $self->{publican}->param('web_type') || '';
my $TAR_NAME
= $self->{publican}->param('product') . '-'
. $self->{publican}->param('docname') . '-'
. $self->{publican}->param('version');
my $RPM_VERSION = $self->{publican}->param('edition');
my $RPM_RELEASE = $self->{publican}->param('release');
my $pdf_name
= $self->{publican}->param('product') . '-'
. $self->{publican}->param('version') . '-'
. $self->{publican}->param('docname') . '-'
. "$lang.pdf";
my $sub_format = 0;
$sub_format = 1 if ( $format eq 'txt' );
foreach my $dialect ( HTML::WikiConverter->available_dialects ) {
if ( $dialect eq $format ) {
$sub_format = 1;
last;
}
}
if ($sub_format) {
if ( !-e "$tmp_dir/$lang/html-single-plain" || $rebuild ) {
$self->transform(
{ lang => $lang, format => 'html-single-plain' } );
}
$dir = pushd("$tmp_dir/$lang");
mkdir $format;
my $TXT_FILE;
my $fh;
open( $fh, "<:encoding(UTF-8)", "html-single-plain/index.html" )
|| croak( maketext("Can't open file for html input!") );
if ( $format eq 'txt' ) {
open( $TXT_FILE, ">:encoding(UTF-8)", "$format/$docname.txt" )
|| croak( maketext("Can't open file for text output!") );
my $tree = HTML::TreeBuilder->new();
eval { $tree->parse_file($fh); };
if ($@) {
croak( maketext( "FATAL ERROR 4: [_1]", $@ ) );
}
## BZ #697363
my $formatter = $self->{publican}->param('txt_formater') || '';
if ( $formatter eq 'links' ) {
my $f = HTML::FormatText::WithLinks->new();
print( $TXT_FILE $f->parse( $tree->as_HTML() ) );
}
elsif ( $formatter eq 'tables' ) {
print( $TXT_FILE HTML::FormatText::WithLinks::AndTables
->convert(
$tree->as_HTML,
{ leftmargin => 0,
rightmargin => 72,
anchor_links => 0,
before_link => ' [%n] '
}
)
);
}
else {
my $f = HTML::FormatText->new(
leftmargin => 0,
rightmargin => 72
);
print( $TXT_FILE $f->format($tree) );
}
}
else {
# must be a wiki format
open( $TXT_FILE, ">:encoding(UTF-8)", "$format/$docname.txt" )
|| croak( maketext("Can't open file for text output!") );
my $tree = HTML::TreeBuilder->new();
eval { $tree->parse_file($fh); };
if ($@) {
croak( maketext( "FATAL ERROR 4: [_1]", $@ ) );
}
# remove broken empty anchors
foreach my $node ( $tree->root()->look_down( '_tag', 'a' ) ) {
if ( $node->is_empty() && $node->id() ) {
$node->parent()->id( $node->id() );
$node->delete();
}
}
# remove extra code tags anchors
foreach my $node ( $tree->root()
->look_down( _tag => 'code', class => qr/email|uri/ ) )
{
$node->replace_with_content();
}
my %opts;
if ( $format eq 'Markdown' ) {
$opts{link_style} = 'inline';
$opts{ordered_list_style} = 'one-dot';
$opts{md_extra} = 1;
}
my $wc = new HTML::WikiConverter( dialect => $format, %opts );
my $html = encode_utf8( $tree->as_XML() );
my $txt = $wc->html2wiki($html);
print( $TXT_FILE decode_utf8($txt) );
}
close($TXT_FILE);
$dir = undef;
return;
}
my ( $web_product_label, $web_version_label, $web_name_label )
= $self->web_labels( { lang => $lang, xml_lang => $xml_lang } );
if ( $format eq 'pdf' && $diefopdie ) {
if ( -d "$tmp_dir/$lang/html-pdf" ) {
rmtree("$tmp_dir/$lang/html-pdf");
}
$self->transform( { lang => $lang, format => 'html-pdf' } );
mkdir "$tmp_dir/$lang/pdf";
my $tmpl_path = Publican::ConfigData->config('book_templates');
my $header = "$tmp_dir/$lang/html-pdf/header.html";
my $footer = "$tmp_dir/$lang/html-pdf/footer.html";
my @wkhtmltopdf_args = (
$wkhtmltopdf_cmd, '--disable-smart-shrinking',
'--javascript-delay', 0,
'--header-spacing', 6,
'--footer-spacing', 6,
'--margin-top', '14mm',
'--margin-bottom', '14mm',
'--margin-left', '15mm',
'--margin-right', '15mm',
'--header-html', $header,
'--footer-html', $footer,
'--load-error-handling', 'ignore'
);
if ( $self->{publican}->param('wkhtmltopdf_opts') ) {
push( @wkhtmltopdf_args,
split( /\s+/, $self->{publican}->param('wkhtmltopdf_opts') )
);
}
rcopy_glob( "$tmpl_path/*.css", "$tmp_dir/$lang/html-pdf/" ) if (-e "$tmpl_path/*.css");
if ( -d "$brand_path/book_templates" ) {
rcopy_glob(
"$brand_path/book_templates/*.css",
"$tmp_dir/$lang/html-pdf/"
) if ( glob("$brand_path/book_templates/*.css") );
$tmpl_path = "$brand_path/book_templates:$tmpl_path";
}
my $tconf = { INCLUDE_PATH => $tmpl_path, };
my $template = Template->new($tconf)
or croak( Template->error() );
my $subtitle = $self->get_subtitle( { lang => $lang } );
$subtitle =~ s/"/\\"/g;
$subtitle =~ s/\p{Z}+/ /g;
chomp($subtitle);
my $prod
= $web_product_label
? $web_product_label
: $self->{publican}->param('product');
$prod =~ s/_/ /g;
my $ver
= $web_version_label
? $web_version_label
: $self->{publican}->param('version');
$ver =~ s/_/ /g;
my $name
= $web_name_label
? $web_name_label
: $self->{publican}->param('docname');
$name =~ s/_/ /g;
my @authors = $self->get_author_list( { lang => $lang } );
my $contributors = $self->get_contributors( { lang => $lang } );
my $legalnotice = $self->get_legalnotice( { lang => $lang } );
my $abstract
= $self->get_abstract( { lang => $lang, format => 'xml' } );
$abstract =~ s/\p{Z}+/ /g;
my @keywords = $self->get_keywords( { lang => $lang } );
my $draft = $self->get_draft( { lang => $lang } );
my $xml_file = "$tmp_dir/$lang/xml/" . ucfirst($type) . '_Info.xml';
$xml_file
= "$tmp_dir/$lang/xml/" . $self->{publican}->param('info_file')
if ( $self->{publican}->param('info_file') );
croak( maketext( "Can't locate required file: [_1]", $xml_file ) )
if ( !-f $xml_file );
my $xml_doc = XML::TreeBuilder->new();
eval { $xml_doc->parse_file($xml_file); };
if ($@) {
croak( maketext( "FATAL ERROR 5: [_1]", $@ ) );
}
my $logo = eval {
$xml_doc->root()->look_down( "_tag", "corpauthor" )
->look_down( "_tag", "imagedata" )->attr('fileref');
};
my $edition = eval {
$xml_doc->root()->look_down( "_tag", "edition" )->as_text();
};
my $releaseinfo = eval {
$xml_doc->root()->look_down( "_tag", "releaseinfo" )->as_text();
};
my $bodyfont = $self->{publican}->param('pdf_body_font');
my $monofont = $self->{publican}->param('pdf_mono_font');
my $vars = {
draft => $draft,
product => decode_utf8( encode_utf8($prod) ),
docname => decode_utf8( encode_utf8($name) ),
version => decode_utf8( encode_utf8($ver) ),
release => decode_utf8(
encode_utf8( $self->{publican}->param('release') )
),
subtitle => decode_utf8( encode_utf8($subtitle) ),
authors => \@authors,
editorlabel => decode_utf8( $locale->maketext("Edited by") ),
contributors => $contributors,
contriblabel =>
decode_utf8( $locale->maketext("With contributions from") ),
legalnotice => $legalnotice,
legaltitle => decode_utf8( $locale->maketext("Legal Notice") ),
abstract => $abstract,
abstracttitle => decode_utf8( $locale->maketext("Abstract") ),
keywordtitle => decode_utf8( $locale->maketext("Keywords") ),
toctitle => decode_utf8( $locale->maketext("Table of Contents") ),
logo => ( $logo || 'Common_Content/images/title_logo.svg' ),
buildpath => abs_path("$tmp_dir/$lang/html-pdf"),
chunk_section_depth => $chunk_section_depth,
bodyfont => $bodyfont,
bodyface =>
( -f "$tmp_dir/$lang/html-pdf/$bodyfont-font-faces.css" ),
monofont => $monofont,
monoface =>
( -f "$tmp_dir/$lang/html-pdf/$monofont-font-faces.css" ),
overrides_css => ( -f "$tmp_dir/$lang/html-pdf/Common_Content/css/overrides.css" ),
lang_css => ( -f "$tmp_dir/$lang/html-pdf/Common_Content/css/lang.css" ),
};
if (@keywords) {
$vars->{keywords} = \@keywords;
}
if ($edition) {
$vars->{edition} = decode_utf8(
$locale->maketext( 'Edition [_1]', $edition ) );
}
if ($releaseinfo) {
$vars->{releaseinfo} = decode_utf8($releaseinfo);
}
$template->process(
'cover.tmpl', $vars,
"$tmp_dir/$lang/html-pdf/cover.html",
binmode => ':encoding(UTF-8)'
) or croak( $template->error() );
push( @wkhtmltopdf_args,
'cover', "$tmp_dir/$lang/html-pdf/cover.html" );
my $toc_xsl = "$tmp_dir/$lang/html-pdf/toc.xsl";
$template->process( 'toc-xsl.tmpl', $vars, $toc_xsl,
binmode => ':encoding(UTF-8)' )
or croak( $template->error() );
my $out_file = "$tmp_dir/$lang/html-pdf/header.html";
$template->process( 'header.tmpl', $vars, $out_file,
binmode => ':encoding(UTF-8)' )
or croak( $template->error() );
$out_file = "$tmp_dir/$lang/html-pdf/footer.html";
$template->process( 'footer.tmpl', $vars, $out_file,
binmode => ':encoding(UTF-8)' )
or croak( $template->error() );
$out_file = "$tmp_dir/$lang/html-pdf/pdfmain.css";
$template->process( 'pdfmain-css.tmpl', $vars, $out_file,
binmode => ':encoding(UTF-8)' )
or croak( $template->error() );
$out_file = "$tmp_dir/$lang/html-pdf/pdf.css";
$template->process( 'pdf-css.tmpl', $vars, $out_file,
binmode => ':encoding(UTF-8)' )
or croak( $template->error() );
push(
@wkhtmltopdf_args,
'toc',
'--xsl-style-sheet',
$toc_xsl,
## '--toc-header-text',
## decode_utf8( $locale->maketext("Table of Contents") ),
"$tmp_dir/$lang/html-pdf/index.html",
"$tmp_dir/$lang/pdf/$pdf_name"
);
logger( "Running: " . join( " ", @wkhtmltopdf_args ) . "\n" );
my $result = system(@wkhtmltopdf_args);
if ($result) {
croak(
"\n",
maketext(
'wkhtmltopdf died, PDF generation failed. Check log for details.'
),
"\n"
);
}
return;
}
my $xsl_file = $common_config . "/xsl/$format.xsl";
$xsl_file = "$common_content/$base_brand/xsl/$format.xsl"
if ( defined($base_brand));
$xsl_file = "$brand_path/xsl/$format.xsl"
if ( -f "$brand_path/xsl/$format.xsl" );
# required for Windows
$xsl_file =~ s/"//g;
my %xslt_opts = (
'toc.section.depth' => $toc_section_depth,
'confidential' => $confidential,
'confidential.text' => "'$confidential_text'",
'profile.lang' => "'$lang'",
'l10n.gentext.language' => "'$lang'",
'show.comments' => $show_remarks,
'generate.section.toc.level' => $generate_section_toc_level,
'use.extensions' => 1,
'tablecolumns.extensions' => 1,
'publican.version' => "'$Publican::VERSION'",
'bridgehead.in.toc' => $bridgehead_in_toc,
'body.only' => 0,
'brand' => "'$brand'",
'langpath' => "'$lang'",
'book.type' => "'$type'",
'web.type' => "'$web_type'",
## '' => ,
);
mkdir "$tmp_dir/$lang/$format";
my $pop_prod = $self->{publican}->param('product');
my $pop_ver = $self->{publican}->param('version');
my $pop_name = $self->{publican}->param('docname');
my $toc_path = '../../../..';
$toc_path = '.' if ( $self->{publican}->param('web_home') );
if ( $self->{publican}->param('web_type') ) {
if ( $web_type =~ m/^home$/i ) {
$toc_path = '.';
$pop_prod = undef;
$pop_ver = undef;
$pop_name = undef;
}
elsif ( $web_type =~ m/^product$/i ) {
$toc_path = '..';
$pop_ver = undef;
$pop_name = undef;
}
elsif ( $web_type =~ m/^version$/i ) {
$toc_path = '../..';
$pop_name = undef;
}
}
$xslt_opts{clean_title}
= $web_name_label
? $web_name_label
: $pop_name;
$xslt_opts{clean_title} = $self->{publican}->param('docname')
unless ( $xslt_opts{clean_title} );
$xslt_opts{clean_title} = '"' . $xslt_opts{clean_title} . '"';
$xslt_opts{clean_title} =~ s/_/ /g;
if ( $format eq 'html-single' ) {
$dir = pushd("$tmp_dir/$lang/$format");
$xslt_opts{'doc.url'} = "'$doc_url'";
$xslt_opts{'prod.url'} = "'$prod_url'";
$xslt_opts{'package'} = "'$TAR_NAME-$lang-$RPM_VERSION-$RPM_RELEASE'";
$xslt_opts{'embedtoc'} = $embedtoc;
$xslt_opts{'tocpath'} = "'$toc_path'";
$xslt_opts{'pop_prod'} = "'$pop_prod'" if ($pop_prod);
$xslt_opts{'pop_ver'} = "'$pop_ver'" if ($pop_ver);
$xslt_opts{'pop_name'} = "'$pop_name'" if ($pop_name);
}
elsif ( $format eq 'html-single-plain' ) {
$dir = pushd("$tmp_dir/$lang/$format");
}
elsif ( $format eq 'html-pdf' ) {
$dir = pushd("$tmp_dir/$lang/$format");
my $title;
$title
= $web_product_label
? $web_product_label
: $self->{publican}->param('product');
$title .= ' ';
$title .=
$web_version_label
? $web_version_label
: $self->{publican}->param('version');
$title .= ' ';
$title =~ s/_/ /g;
$xslt_opts{'product'} = "'$title'";
$xslt_opts{'svg.object'} = "0";
$xslt_opts{'doc.url'} = "'$doc_url'";
$xslt_opts{'prod.url'} = "'$prod_url'";
$xslt_opts{'package'} = "'$TAR_NAME-$lang-$RPM_VERSION-$RPM_RELEASE'";
$xslt_opts{'tocpath'} = "'$toc_path'";
$xslt_opts{'pop_prod'} = "'$pop_prod'" if ($pop_prod);
$xslt_opts{'pop_ver'} = "'$pop_ver'" if ($pop_ver);
$xslt_opts{'pop_name'} = "'$pop_name'" if ($pop_name);
}
elsif ( $format eq 'html-desktop' ) {
$xsl_file = $common_config . "/xsl/html-single.xsl";
$xsl_file = "$common_content/$base_brand/xsl/html-single.xsl"
if ( defined($base_brand));
$xsl_file = "$brand_path/xsl/html-single.xsl"
if ( -e "$brand_path/xsl/html-single.xsl" );
$dir = pushd("$tmp_dir/$lang/$format");
$xslt_opts{'doc.url'} = "'$doc_url'";
$xslt_opts{'prod.url'} = "'$prod_url'";
$xslt_opts{'package'} = "'$TAR_NAME-$lang-$RPM_VERSION-$RPM_RELEASE'";
$xslt_opts{'desktop'} = 1;
}
elsif ( $format eq 'html' ) {
$dir = pushd("$tmp_dir/$lang/$format");
$xslt_opts{'doc.url'} = "'$doc_url'";
$xslt_opts{'prod.url'} = "'$prod_url'";
$xslt_opts{'package'} = "'$TAR_NAME-$lang-$RPM_VERSION-$RPM_RELEASE'";
$xslt_opts{'embedtoc'} = $embedtoc;
$xslt_opts{'tocpath'} = "'$toc_path'";
$xslt_opts{'chunk.first.sections'} = $chunk_first;
$xslt_opts{'chunk.section.depth'} = $chunk_section_depth;
$xslt_opts{'pop_prod'} = "'$pop_prod'" if ($pop_prod);
$xslt_opts{'pop_ver'} = "'$pop_ver'" if ($pop_ver);
$xslt_opts{'pop_name'} = "'$pop_name'" if ($pop_name);
}
elsif ( $format eq 'drupal-book' ) {
$dir = pushd("$tmp_dir/$lang/$format");
$xslt_opts{'chunk.first.sections'} = $chunk_first;
$xslt_opts{'chunk.section.depth'} = $chunk_section_depth;
$xslt_opts{'doc.url'} = "'$doc_url'";
$xslt_opts{'prod.url'} = "'$prod_url'";
}
elsif ( ( $format =~ /^pdf/ ) and ( -f $xsl_file ) ) {
$dir = pushd("$tmp_dir/$lang/xml");
}
elsif ( $format eq 'epub' ) {
$dir = pushd("$tmp_dir/$lang/$format");
}
elsif ( $format eq 'eclipse' ) {
$xslt_opts{'eclipse.plugin.name'} = "'$ec_name'";
$xslt_opts{'eclipse.plugin.id'} = "'$ec_id'";
$xslt_opts{'eclipse.plugin.provider'} = "'$ec_provider'";
$dir = pushd("$tmp_dir/$lang/$format");
}
elsif ( $format eq 'man' ) {
$dir = pushd("$tmp_dir/$lang/$format");
}
else {
croak( maketext( "Unknown format: [_1]", $format ) );
}
# required for Windows
$xsl_file =~ s/"//g;
logger(
"\t" . maketext( "Using XML::LibXSLT on [_1]", $xsl_file ) . "\n" );
my $parser = XML::LibXML->new(no_network => !$self->{publican}->{allow_network});
my $xslt = XML::LibXSLT->new();
XML::LibXSLT->register_function( 'urn:perl', 'adjustColumnWidths',
\&adjustColumnWidths );
XML::LibXSLT->register_function( 'urn:perl', 'highlight', \&highlight );
XML::LibXSLT->register_function( 'urn:perl', 'insertCallouts',
\&insertCallouts );
XML::LibXSLT->register_function( 'urn:perl', 'numberLines',
\&numberLines );
XML::LibXSLT->max_depth(10000);
my $security = XML::LibXSLT::Security->new();
$security->register_callback( create_dir => sub { 1; }, read_net => sub {return($self->{publican}->{allow_network})});
# $security->register_callback(read_net => sub { 0; });
$xslt->security_callbacks($security);
$parser->expand_xinclude(1);
$parser->expand_entities(1);
my $source;
eval { $source = $parser->parse_file("../xml/$main_file.xml"); };
if ($@) {
if ( ref($@) ) {
# handle a structured error (XML::LibXML::Error object)
croak(
maketext(
"FATAL ERROR 6 building $format: [_1]:[_2] in [_3] on line [_4]: [_5]",
$@->domain(),
$@->code(),
$@->file(),
$@->line(),
$@->message(),
)
);
}
else {
croak( maketext( "FATAL ERROR 7: [_1]", $@ ) );
}
}
my $style_doc = $parser->parse_file($xsl_file);
## BUGBUG get Win32 working with Publican::ConfigData
## BUGBUG also get catalog working!
if ( $^O eq 'MSWin32' ) {
eval { require Win32::TieRegistry; };
croak(
maketext(
"Failed to load Win32::TieRegistry module. Error: [_1]", $@
)
) if ($@);
my $defualt_href
= 'http://docbook.sourceforge.net/release/xsl/current';
my $key = new Win32::TieRegistry( "LMachine\\Software\\Publican",
{ Delimiter => "\\" } );
my $new_href = 'file:///C:/publican/docbook-xsl-1.76.1';
if ( $key and $key->GetValue("xsl_path") ) {
$new_href = 'file:///' . $key->GetValue("xsl_path");
$new_href =~ s/ /%20/g;
$new_href =~ s/\\/\//g;
}
my @nodelist = $style_doc->getElementsByTagName('xsl:import');
foreach my $node (@nodelist) {
my $href = $node->getAttribute('href');
debug_msg("changing $defualt_href to $new_href\n");
$href =~ s|$defualt_href|$new_href|;
$node->setAttribute( 'href', $href );
}
}
my $stylesheet = $xslt->parse_stylesheet($style_doc);
my $results = $stylesheet->transform( $source, %xslt_opts );
if ( $format =~ /^pdf/ ) {
eval { $stylesheet->output_file( $results, "$docname.fo" ) };
}
elsif ( $format =~ /^html-/ ) { # html-single and html-desktop html-pdf
eval { $stylesheet->output_file( $results, "index.html" ) };
}
else { # html
eval { $stylesheet->output_string($results) };
}
croak( maketext( "Transformation error '[_1]' : [_2]", $!, $@ ) ) if $@;
if ( $format =~ /^pdf/ ) {
my $fop_command
= qq|CLASSPATH="$classpath" fop -q -c $common_config/fop/fop.xconf -fo $docname.fo -pdf ../pdf/$pdf_name|;
## TODO find out if we need to set classpath on windows and how
if ( $^O eq 'MSWin32' ) {
$fop_command
= qq|fop -q -c $common_config/fop/fop.xconf -fo $docname.fo -pdf ../pdf/$pdf_name|;
}
if ( system($fop_command) != 0 ) {
croak(
"\n",
maketext(
"FOP error, PDF generation failed. Check log for details."
),
"\n"
);
}
$dir = undef;
}
elsif ( $format eq 'epub' ) {
$dir = undef;
my $images = $self->{publican}->param('img_dir');
dircopy( "$tmp_dir/$lang/xml/$images",
"$tmp_dir/$lang/$format/OEBPS/$images" )
if ( -d "$tmp_dir/$lang/xml/$images" );
dircopy(
"$tmp_dir/$lang/xml/Common_Content",
"$tmp_dir/$lang/$format/OEBPS/Common_Content"
);
unlink("$tmp_dir/$lang/$format/OEBPS/$images/icon.svg");
unlink("$tmp_dir/$lang/$format/OEBPS/Common_Content/css/brand.css");
unlink("$tmp_dir/$lang/$format/OEBPS/Common_Content/css/common.css");
unlink("$tmp_dir/$lang/$format/OEBPS/Common_Content/css/default.css");
unlink(
"$tmp_dir/$lang/$format/OEBPS/Common_Content/css/overrides.css");
unlink("$tmp_dir/$lang/$format/OEBPS/Common_Content/css/pdf.css");
unless (
-f "$tmp_dir/$lang/$format/OEBPS/Common_Content/css/lang.css" )
{
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)",
"$tmp_dir/$lang/$format/OEBPS/Common_Content/css/lang.css" )
|| croak(
maketext(
"Could not open [_1] for output!",
"\$tmp_dir/\$lang/\$format/OEBPS/Common_Content/css/lang.css"
)
);
close($OUTDOC);
}
# remove any RCS from the output
finddepth( \&del_unwanted_dirs, "$tmp_dir/$lang/$format" );
# remove any XML files from common
finddepth( \&del_unwanted_xml,
"$tmp_dir/$lang/$format/OEBPS/Common_Content" );
my @files = dir_list( "$tmp_dir/$lang/$format/OEBPS", '*' );
my $content_file = "$tmp_dir/$lang/$format/OEBPS/content.opf";
my $tree = XML::TreeBuilder->new(
{ 'NoExpand' => "1", 'ErrorContext' => "2" } );
$tree->parse_file("$content_file");
my $node;
eval { $node = $tree->look_down( '_tag', "manifest" ); };
if ( $@ or !$node ) {
croak( maketext("manifest not found") );
}
foreach my $file (@files) {
$file =~ s/^.*OEBPS\///g;
$file =~ /(...)$/;
my $ext = $1;
my $id = $file;
$id =~ s/\//-/g;
my $exists;
eval { $exists = $tree->root()->look_down( 'href', "$file" ); };
if ( !defined($exists) ) {
$node->push_content(
[ 'item',
{ href => "$file",
'media-type' => "image/$ext",
id => $id
}
]
);
}
}
my $OUTDOC;
open( $OUTDOC, ">:encoding(UTF-8)", "$content_file" )
|| croak(
maketext( "Could not open [_1] for output!", $content_file ) );
my $text = $tree->as_XML();
$text =~ s/"/"/g;
$text =~ s/'/'/g;
$text =~ s/"/"/g;
$text =~ s/'/'/g;
print( $OUTDOC $text );
close($OUTDOC);
my $MIME;
open( $MIME, ">", "$tmp_dir/$lang/$format/mimetype" )
|| croak( maketext("Can't open mimetype file: ") );
print( $MIME 'application/epub+zip' );
close($MIME);
$dir = pushd("$tmp_dir/$lang/$format");
my $zip = Archive::Zip->new();
my $mimetype = $zip->addFile("mimetype");
$mimetype->desiredCompressionMethod(COMPRESSION_STORED);
my $member = $zip->addDirectory("OEBPS/");
$member = $zip->addDirectory("META-INF/");
my @filelist = File::Find::Rule->file->not_name('mimetype')->in(".");
foreach my $file (@filelist) {
$member = $zip->addFile($file);
}
my $epub_name
= $self->{publican}->param('product') . '-'
. $self->{publican}->param('version') . '-'
. $self->{publican}->param('docname') . '-'
. "$lang.epub";
$self->{epub_name} = $epub_name;
$zip->writeToFileNamed("../$epub_name") == AZ_OK
|| croak( maketext("epub creation failed.") );
logger(
maketext( "Wrote epub archive: [_1]",
"$tmp_dir/$lang/$epub_name" )
. "\n"
);
$dir = undef;
}
elsif ( $format eq 'man' ) {
# NO-OP?
}
elsif ( $format eq 'drupal-book' ) {
$dir = undef;
my $title = $xslt_opts{clean_title};
$title =~ s/^"//;
$title =~ s/"$//;
my $docname = $self->{publican}->param('docname');
my $product = $self->{publican}->param('product');
my $version = $self->{publican}->param('version');
my $edition = $self->{publican}->param('edition');
my $release = $self->{publican}->param('release');
my $filename
= "$product-$version-$docname-$lang-$edition-$release.tar.gz";
my $content_dir
= "$product-$version-$docname-$lang-$edition-$release";
$self->drupal_transform(
{ lang => $lang, filename => $filename, title => $title } );
my $images = $self->{publican}->param('img_dir');
dircopy( "$tmp_dir/$lang/xml/$images",
"$tmp_dir/$lang/$format/$content_dir/$images" )
if ( -d "$tmp_dir/$lang/xml/$images" );
dircopy(
"$tmp_dir/$lang/xml/Common_Content/images",
"$tmp_dir/$lang/$format/$content_dir/Common_Content/images")
if ( -d "$tmp_dir/$lang/xml/Common_Content/images" );
dircopy( "$xml_lang/files",
"$tmp_dir/$lang/$format/$content_dir/files" )
if ( -e "$xml_lang/files" );
dircopy( "$lang/files", "$tmp_dir/$lang/$format/$content_dir/files" )
if ( -e "$lang/files" );
# remove any RCS from the output
finddepth( \&del_unwanted_dirs, "$tmp_dir/$lang/$format" );
$dir = pushd("$tmp_dir/$lang/$format/$content_dir");
# remove all html files
my @htmls = glob "*.html";
foreach (@htmls) {
unlink($_);
}
my $tar = Archive::Tar->new();
my @filelist = File::Find::Rule->file->in(".");
$tar->add_files(@filelist);
$tar->write( "../$filename", COMPRESS_GZIP );
$dir = undef;
logger(
maketext( "Wrote tar archive: [_1]",
"$tmp_dir/$lang/$format/$filename" )
. "\n"
);
}
else {
my $images = $self->{publican}->param('img_dir');
$dir = undef;
dircopy( "$tmp_dir/$lang/xml/$images",
"$tmp_dir/$lang/$format/$images" )
if ( -d "$tmp_dir/$lang/xml/$images" );
dircopy(
"$tmp_dir/$lang/xml/Common_Content",
"$tmp_dir/$lang/$format/Common_Content"
)
if ( $embedtoc == 0
|| $format eq 'html-desktop'
|| $format eq 'html-pdf' );
dircopy( "$xml_lang/files", "$tmp_dir/$lang/$format/files" )
if ( -e "$xml_lang/files" );
dircopy( "$lang/files", "$tmp_dir/$lang/$format/files" )
if ( -e "$lang/files" );
# remove any RCS from the output
finddepth( \&del_unwanted_dirs, "$tmp_dir/$lang/$format" );
# remove any XML files from common
finddepth( \&del_unwanted_xml,
"$tmp_dir/$lang/$format/Common_Content" )
if ( $embedtoc == 0
|| $format eq 'html-desktop'
|| $format eq 'html-pdf' );
}
$xslt = undef;
$source = undef;
$style_doc = undef;
$stylesheet = undef;
$parser = undef;
## TODO BUGBUG freeing $results goes BOOM on windows
## TODO requires testing since the other crashbug is resolved
$results = undef;
return;
}
=head2 drupal_transform
Write csv file for drupal node import
=cut
sub drupal_transform {
my ( $self, $args ) = @_;
my $lang = delete $args->{lang}
|| croak maketext(
"[_1] is a mandatory argument for drupal_transform", 'lang' );
my $filename = delete $args->{filename}
|| croak maketext(
"[_1] is a mandatory argument for drupal_transform", 'filename' );
my $title = delete $args->{title}
|| croak maketext(
"[_1] is a mandatory argument for drupal_transform", 'title' );
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $main_file = $self->{publican}->param('mainfile');
my $docname = $self->{publican}->param('docname');
my $product = $self->{publican}->param('product');
my $version = $self->{publican}->param('version');
my $edition = $self->{publican}->param('edition');
my $release = $self->{publican}->param('release');
my $xml_lang = $self->{publican}->param('xml_lang');
my $drupal_dir = "$tmp_dir/$lang/drupal-book";
my $subtitle = $self->get_subtitle( { lang => $lang } );
my $abstract = $self->get_abstract( { lang => $lang } );
my $keywords = join( ',', $self->get_keywords( { lang => $lang } ) );
my ( $web_product_label, $web_version_label, $web_name_label )
= $self->web_labels( { lang => $lang, xml_lang => $xml_lang } );
my $prod
= $web_product_label
? $web_product_label
: $product;
$prod =~ s/_/ /g;
my $ver
= $web_version_label
? $web_version_label
: $version;
$ver =~ s/_/ /g;
my $parser = XML::LibXML->new(no_network => !$self->{publican}->{allow_network});
$parser->expand_xinclude(1);
$parser->expand_entities(1);
my $source;
eval {
$source = $parser->parse_file("$tmp_dir/$lang/xml/$main_file.xml");
};
my %all_nodes;
my %section_maps;
my $nodes_order = $self->get_nodes_order(
{ source => $source,
section_maps => \%section_maps,
all_nodes => \%all_nodes
}
);
my $outputs = $self->build_drupal_book(
{ lang => $lang,
nodes_order => $nodes_order,
section_maps => \%section_maps,
all_nodes => \%all_nodes
}
);
$self->{dbh}->disconnect()
if ( defined $self->{dbh} );
# Escape some of the generated content for XML use
$title = $self->escape_xml($title);
$prod = $self->escape_xml($prod);
$ver = $self->escape_xml($ver);
$subtitle = $self->escape_xml($subtitle);
$abstract = $self->escape_xml($abstract);
my $out_file
= "$drupal_dir/$product-$version-$docname-$lang-$edition-$release.xml";
my $fh;
open( $fh, ">:encoding(UTF-8)", $out_file )
|| croak(
maketext( "Could not open [_1] for output: [_2]", $out_file, $@ ) );
$fh->print(<$prod $ver $title$title$subtitle$lang$filename$prod$ver$edition$release$abstract$keywords
EOH
foreach my $row ( @{$outputs} ) {
$fh->print(<$row->[0]$row->[10]$row->[2]$row->[3]
$row->[6]
EOR
}
$fh->print("\n");
return;
}
=head2 escape_xml
Escapes an input string so that it can be used in an XML Element.
=cut
sub escape_xml {
my ($self, $source) = @_;
$source =~ s{\&}{\&\;};
$source =~ s{\<}{\<\;};
$source =~ s{\>}{\>\;};
$source =~ s{\'}{\&apos\;};
$source =~ s{\"}{\"\;};
return ($source);
}
=head2 get_nodes_order
Get all nodes with id from xml files in order
=cut
sub get_nodes_order {
my ( $self, $args ) = @_;
my $source = delete( $args->{source} )
|| croak( maketext("source is a mandatory argument") );
my $node = delete( $args->{node} ) || undef;
my $section_maps = delete( $args->{section_maps} ) || {};
my $all_nodes = delete( $args->{all_nodes} ) || {};
my $check_dups = delete( $args->{check_dups} ) || {};
my $type = lc( $self->{publican}->param('type') );
if ( !$node ) {
$node = $source->getElementsByTagName($type)->[0];
}
my %order;
my @node_list = $node->childNodes();
my $count = 0;
foreach my $cnode (@node_list) {
my $tag = $cnode->nodeName();
# Ignore anything that isn't an element
next if ( $cnode->nodeType() != XML_ELEMENT_NODE);
my $unique_id = undef;
if ( $cnode->hasAttribute("conformance")) {
$unique_id = $cnode->getAttribute("conformance");
}
if ( $cnode->hasAttribute( $self->{id_attr} ) ) {
my $value = $cnode->getAttribute( $self->{id_attr} );
$order{ ++$count }{'id'} = $value;
$order{$count}{'type'} = $tag;
$order{$count}{'parent'} = $cnode->parentNode->nodeName();
$section_maps->{$value} = $unique_id || $value;
if ( defined $unique_id ) {
croak(
maketext(
"Duplicate conformance value in section $value which value = $unique_id."
)
) if ( defined $check_dups->{$unique_id} );
$check_dups->{$unique_id} = 1;
}
#|| croak ( maketext("missing 'conformance' attribute in $order{$count}{type} where id is $value") );
if ( $cnode->hasChildNodes() ) {
$all_nodes->{$value} = 1;
my $child_nodes = $self->get_nodes_order(
{ source => $source,
node => $cnode,
section_maps => $section_maps,
all_nodes => $all_nodes,
check_dups => $check_dups,
}
);
$order{$count}{'childs'} = $child_nodes
if ( %{$child_nodes} );
}
} elsif ( exists $CHUNK_TAGS{$tag} ) {
# We need to emulate the filename given to the element when chunked (see chunk-code.xsl). BZ #1173421
my $value = $self->get_chunk_filename($cnode);
$order{ ++$count }{'id'} = $value;
$order{$count}{'type'} = $tag;
$order{$count}{'parent'} = $cnode->parentNode->nodeName();
$section_maps->{$value} = $unique_id || $value;
if ( $cnode->hasChildNodes() ) {
$all_nodes->{$value} = 1;
my $child_nodes = $self->get_nodes_order(
{ source => $source,
node => $cnode,
section_maps => $section_maps,
all_nodes => $all_nodes,
check_dups => $check_dups,
}
);
$order{$count}{'childs'} = $child_nodes
if ( %{$child_nodes} );
}
} elsif ( $node->nodeName() eq $type && $tag =~ /^(${type})?info/ ) {
# The main info element is generated as the index page. BZ #1173421
$order{ ++$count }{'id'} = "index";
$order{$count}{'type'} = $tag;
$order{$count}{'parent'} = $type;
if ( $cnode->hasChildNodes() ) {
my $child_nodes = $self->get_nodes_order(
{ source => $source,
node => $cnode,
section_maps => $section_maps,
all_nodes => $all_nodes,
check_dups => $check_dups,
}
);
$order{$count}{'childs'} = $child_nodes
if ( %{$child_nodes} );
}
}
}
return \%order;
}
=head2 get_chunk_filename
Gets the chunked filename for an LibXML::Node in a tree.
=cut
sub get_chunk_filename {
my ( $self, $node ) = @_;
my $tag = $node->nodeName();
# Check to make sure the node can be chunked
if ( !exists $CHUNK_TAGS{$tag} ) {
return;
}
my $format = $CHUNK_TAGS{$tag}{'format'};
my $tag_count = $node->findvalue("count(preceding-sibling::*[local-name()='${tag}'])") + 1;
if ( $CHUNK_TAGS{$tag}{'any_level'} ) {
$tag_count += $node->findvalue("count(../preceding::*[local-name()='${tag}'])");
}
my $chunk_name;
if ( $CHUNK_TAGS{$tag}{'use_alpha'} ) {
$chunk_name = sprintf( $format, $self->convert_num_to_alpha( $tag_count ));
} else {
$chunk_name = sprintf( $format, $tag_count);
}
if ( $CHUNK_TAGS{$tag}{'use_parent'} && $node->parentNode ) {
# Get the parents node name and then prefix
my $parent_name = $self->get_chunk_filename($node->parentNode);
return $parent_name . $chunk_name;
} else {
return $chunk_name;
}
}
=head2 convert_num_to_alpha
Converts a numeric number to an alpha list item. ie 1 -> a, 27 -> aa
=cut
sub convert_num_to_alpha {
my ($self, $num) = @_;
my $dividend = $num;
my $alpha = "";
my $mod;
while( $dividend > 0 ) {
$mod = ($dividend - 1) % 26;
$alpha = chr(97 + $mod) . $alpha;
$dividend = int(($dividend - $mod) / 26);
}
return $alpha;
}
=head2 build_drupal_book
Convert each html file into csv a row for drupal.
=cut
sub build_drupal_book {
my ( $self, $args ) = @_;
my $lang = delete( $args->{lang} )
|| croak(
maketext("lang is a mandatory argument for build_drupal_book") );
my $nodes_order = delete( $args->{nodes_order} )
|| croak(
maketext("nodes_order is a mandatory argument for build_drupal_book")
);
my $section_maps = delete $args->{section_maps} || {};
my $all_nodes = delete $args->{all_nodes} || {};
my $parent = delete $args->{parent} || "";
my $parent_alias = delete $args->{parent_alias} || "";
my $tmp_dir = $self->{publican}->param('tmp_dir');
my $docname = $self->{publican}->param('docname');
my $product = $self->{publican}->param('product');
my $version = $self->{publican}->param('version');
my $author = $self->{publican}->param('drupal_author');
my $book_title = $self->{publican}->param('drupal_menu_title');
my $menu_block = $self->{publican}->param('drupal_menu_block');
my $img_path = $self->{publican}->param('drupal_image_path');
my $type = lc( $self->{publican}->param('type') );
$menu_block = ($menu_block) ? "menu-$menu_block" : "";
my $bookname = "$product-$version-$docname-$lang";
my $drupal_dir = "$tmp_dir/$lang/drupal-book";
my $resource_dir = "$lang/$product/$version/$docname";
my @outputs;
my $weight = -16;
my $previous_type = "";
foreach my $order_num ( sort { $a <=> $b } keys %{$nodes_order} ) {
my $page
= ( $nodes_order->{$order_num}{'type'} =~ /^(${type})?info/
&& $nodes_order->{$order_num}{'parent'} =~ /^$type/ )
? 'index'
: $nodes_order->{$order_num}{'id'};
my $file_name = "$drupal_dir/$page.html";
if ( -e $file_name ) {
my @csv_row;
my $tree = HTML::TreeBuilder->new();
# Fix unknown sections being removed BZ1158747
$tree->ignore_unknown(0);
# Fix entities being expanded in the output BZ 1165438
$tree->no_expand_entities(1);
open my $html_file, "<:encoding(utf8)", $file_name
or croak "$file_name: $!";
eval { $tree->parse_file($html_file); };
if ($@) {
croak( maketext( "FATAL ERROR 8: [_1]", $@ ) );
}
$html_file->close();
my $title_element = $tree->look_down( '_tag', 'title' );
my $title = $title_element->as_trimmed_text;
#delete html head
my $head_element = $tree->look_down( '_tag', 'head' );
$head_element->delete();
my $delete_first_header = 1;
my %header_tags = ( h1 => 1, h2 => 1, h3 => 1, h4 => 1, h5 => 1 );
$tree->traverse(
[ # Callbacks;
# pre-order callback:
sub {
my $node = $_[0];
my $tag = $node->{'_tag'};
# only delete the first header tag because it is already showing
# in the drupal title
if ( defined $header_tags{$tag}
&& $delete_first_header == 1 )
{
$node->delete();
$delete_first_header = 0;
}
if ( $tag eq 'img' && defined $node->attr('src') ) {
my $old_value = $node->attr('src');
$node->attr( 'src',
"$img_path$resource_dir/" . $old_value )
if ($old_value);
}
if ( $tag eq 'object'
&& defined $node->attr('type')
&& $node->attr('type') eq 'image/svg+xml' )
{
my $old_value = $node->attr('data') || undef;
$node->attr( 'data',
"$img_path$resource_dir/" . $old_value )
if ($old_value);
}
if ( $tag eq 'a' && defined $node->attr('href')) {
my $old_value = $node->attr('href');
if ($old_value) {
my @links;
my $update_link = 0;
@links = split( '#', $old_value, 2 );
my $link_filename = $links[0];
$link_filename =~ s/\.html$//;
if ($link_filename eq $page ) {
$link_filename = "";
$update_link = 1;
} elsif (defined $section_maps->{ $link_filename }
)
{
$link_filename
= "$bookname-" . $section_maps->{ $link_filename };
$update_link = 1;
}
unless ($update_link) {
# check if it is internal page
if (defined $all_nodes->{ $link_filename }
)
{
$update_link = 1;
}
}
if ( $link_filename eq 'ix01' ) {
$link_filename = "$bookname-index";
$update_link = 1;
}
if ($update_link) {
$links[0] = $link_filename;
$old_value = join( '#', @links );
$node->attr( 'href', $old_value);
$update_link = 0;
}
#else {
#print ">>$old_value>> not found\n";
#}
}
}
return HTML::Element::OK; # keep traversing
},
# post-order callback:
undef
],
1, # don't call the callbacks for text nodes
);
my $alias = "$bookname-$page";
my $section_weight
= { preface => 1, chapter => 2, appendix => 3 };
#if ($previous_type ne $nodes_order->{$order_num}{'type'}) {
if ( $weight < 30 ) {
$weight++;
}
else {
logger(
maketext(
"Reached the maximum page ordering weight(30) that drupal can support. The rest of the pages will be ordered in alphabetical order\n"
),
RED
);
}
#}
my $menu_link = "";
my $menu_title = "";
my $book
= ($book_title)
? $book_title
: "$product $version $docname";
if ( $page eq 'index' ) {
$alias = $bookname;
$menu_title = $book;
$menu_link = $menu_block;
$book = "";
}
elsif ( $page eq 'ix01' ) {
$alias = "$bookname-index";
}
else {
$alias = "$bookname-$section_maps->{$page}"
|| croak( maketext("Fail to get the mapping for $page") );
}
$title =~ s/\s+/ /g;
my $html_string = $tree->as_XML();
$html_string =~ s{^]*>\n*}{};
$html_string =~ s{\s*]*>}{};
$html_string =~ s{}{};
$html_string =~ s{