xpi.sh 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. # -*- mode: sh; tab-width: 4; coding: utf-8 -*-
  2. # vim: ts=4 noet ai ft=sh
  3. # Build a .xpi package.
  4. # This file is part of JPM.sh.
  5. # Copyright (C) 2016 the Desktopd developers
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. # Dependencies
  20. . "$gLibDir/tmpdir.sh"
  21. . "$gLibDir/git.sh"
  22. . "$gLibDir/xml.sh"
  23. . "$gLibDir/crypto.sh"
  24. . "$gLibDir/json.sh"
  25. . "$gLibDir/code-minifier.sh"
  26. # jpmXpiGetId
  27. jpmXpiGetId () {
  28. printf %s "@${addon_id}"
  29. }
  30. # jpmXpiFormatVersion <version>
  31. jpmXpiFormatVersion () {
  32. printf %s "$1" | sed 's/[^-._a-zA-Z0-9]*//g'
  33. }
  34. # jpmXpiBuild <isProdBuild> [<printPackageName>]
  35. # Note: Intentional use of subshell
  36. jpmXpiBuild () (
  37. isProdBuild=$1
  38. printPackageName=$2
  39. [ -d "$addon_src_dir" ] || {
  40. jpmConsoleError "xpi-build: No such directory: $addon_src_dir"
  41. exit 1 # Exits this subshell
  42. }
  43. srcDir=`cd "$addon_src_dir" ; pwd`
  44. # Normalize build environment
  45. unset LANGUAGE DISPLAY USER
  46. LANG=C
  47. LC_ALL=C
  48. [ "$addon_main_path" ] || addon_main_path=main.js
  49. tmpDir=`jpmTempDirCreate`
  50. [ -d "$tmpDir" ] || {
  51. jpmConsoleError "xpi-build: Failed to create a temporary directory"
  52. exit 1 # Exits this subshell
  53. }
  54. tmpHomeDir="$tmpDir/home"
  55. tmpTmpDir="$tmpDir/tmp"
  56. mkdir -p "$tmpHomeDir" "$tmpTmpDir" >&2
  57. TMP="$tmpTmpDir"
  58. TMPDIR="$tmpTmpDir"
  59. TEMP="$tmpTmpDir"
  60. TEMPDIR="$tmpTmpDir"
  61. HOME="$tmpHomeDir"
  62. export TMP TMPDIR TEMP TEMPDIR HOME
  63. # Create build directory
  64. buildDir="$tmpDir/build"
  65. mkdir -p "$buildDir" >&2
  66. cp -r "$srcDir"/* "$buildDir/" >&2
  67. versionGit=''
  68. gitHash=`jpmGitGetHash`
  69. [ "$gitHash" ] && {
  70. versionGit="+git.`printf %s "$gitHash" | head -c8`"
  71. uncomitted=''
  72. jpmGitUncomitted && {
  73. versionGit=${versionGit}+uncommitted
  74. uncomitted=+uncomitted
  75. }
  76. printf '//Build:git-%s%s' "$gitHash" "$uncomitted" \
  77. >> "$buildDir/${addon_main_path}"
  78. [ "$addon_release_phase" = stable ] && versionGit=''
  79. }
  80. version=${addon_version}${versionGit}
  81. [ "$isProdBuild" ] && {
  82. jpmConsoleLog "xpi-build: Excluding development files..."
  83. rm -fr "$buildDir/debug.js" "$buildDir/data/debug" >&2
  84. preprocess_sed_html='s,^\s*<!--!_DEBUGONLY_!.*-->\s*,,'
  85. find "$buildDir" \( -name '*.html' -or -name '*.xhtml' \) -exec \
  86. sh -c 'sed "$1" < "$2" > "$2.tmp" && mv -f "$2.tmp" "$2"' \
  87. -- "$preprocess_sed_html" {} \;
  88. preprocess_sed='s,^\s*/\*!_DEBUGONLY_!.*\*/.*,,'
  89. find "$buildDir" \( -name '*.js' -or -name '*.css' \) -exec \
  90. sh -c 'sed "$1" < "$2" > "$2.tmp" && mv -f "$2.tmp" "$2"' \
  91. -- "$preprocess_sed" {} \;
  92. # TODO: implement optional minification here
  93. [ "$addon_minify_html" ] && jpmMinifyHtml "$buildDir"
  94. [ "$addon_minify_css" ] && jpmMinifyCss "$buildDir"
  95. [ "$addon_minify_js" ] && jpmMinifyJs "$buildDir"
  96. :;} || jpmConsoleLog "xpi-build: Debugging build enabled."
  97. addon_preferences_json=''
  98. [ -f "${addon_preferences_json_path}" ] && \
  99. addon_preferences_json=`cat "${addon_preferences_json_path}"`
  100. addon_translators_json=''
  101. [ -f "${addon_translators_json_path}" ] && \
  102. addon_translators_json=`cat "${addon_translators_json_path}"`
  103. cd "$buildDir" >&2
  104. jpmConsoleLog "xpi-build: Generating the necessary files..."
  105. id=`jpmXpiGetId`
  106. jpmXpiGenInstallRdf "$id" "$version" > ./install.rdf
  107. cp "$gDepsDir/jpm-core/data/bootstrap.js" ./bootstrap.js >&2
  108. jpmXpiGenPackageJson "$id" "$version" > ./package.json
  109. jpmConsoleLog "xpi-build: Zipping files..."
  110. # Skipping directory entries
  111. zip -9rXD ../build.zip ./* >/dev/null
  112. cd .. >&2
  113. [ "$isProdBuild" ] && [ -z "$JPM_SH_RAW_PACKAGING" ] && {
  114. # Postprocessing
  115. which advzip >/dev/null && {
  116. jpmConsoleLog "xpi-build: Recompressing..."
  117. advzip -z -4 -i 500 ./build.zip >/dev/null
  118. :;} || jpmConsoleNotice "xpi-build: Skipping: AdvanceCOMP (not found)"
  119. which strip-nondeterminism >/dev/null && {
  120. jpmConsoleLog "xpi-build: Trying to strip nondeterminism (experimental)..."
  121. strip-nondeterminism -t zip ./build.zip >&2
  122. } || {
  123. jpmConsoleWarn "xpi-build: NOTE: Deterministic build disabled (strip-nondeterminism needed)..."
  124. }
  125. jpmConsoleNotice "xpi-build: SHA2-256: `jpmCryptoSha256 < ./build.zip`"
  126. }
  127. # Output the built package
  128. jpmConsoleLog "xpi-build: Streaming the built package..."
  129. cat ./build.zip
  130. # Clean up temporary files
  131. jpmConsoleLog "xpi-build: Cleaning up temporary files to build .xpi ..."
  132. cd "$srcDir/.." >&2
  133. rm -fr "$tmpDir" >&2
  134. # Print filename
  135. [ "$printPackageName" ] && printf %s "${id}-${version}" >&3
  136. )
  137. # jpmXpiGenPackageJson <id> <version>
  138. jpmXpiGenPackageJson () {
  139. versionF=`jpmXpiFormatVersion "$2"`
  140. printf '{"title":%s,"name":%s,"id":%s,"version":%s' \
  141. "`jpmJsonArgToStringValue "$addon_name"`" \
  142. "`jpmJsonArgToStringValue "$addon_id"`" \
  143. "`jpmJsonArgToStringValue "$1"`" \
  144. "`jpmJsonArgToStringValue "$versionF"`"
  145. printf ',"description":%s,"main":%s,"author":%s,"license":%s' \
  146. "`jpmJsonArgToStringValue "$addon_description"`" \
  147. "`jpmJsonArgToStringValue "$addon_main_path"`" \
  148. "`jpmJsonArgToStringValue "$addon_author"`" \
  149. "`jpmJsonArgToStringValue "$addon_license_id"`"
  150. printf ',"engines":{"firefox":%s' \
  151. "`jpmJsonArgToStringValue "$addon_firefox_version"`"
  152. [ "$addon_fennec_version" ] && printf ',"fennec":%s' \
  153. "`jpmJsonArgToStringValue "$addon_fennec_version"`"
  154. [ "$addon_thunderbird_version" ] && printf ',"thunderbird":%s' \
  155. "`jpmJsonArgToStringValue "$addon_thunderbird_version"`"
  156. [ "$addon_seamonkey_version" ] && printf ',"seamonkey":%s' \
  157. "`jpmJsonArgToStringValue "$addon_seamonkey_version"`"
  158. printf '}'
  159. printf ',"permissions":{"multiprocess":true'
  160. [ "$addon_support_private_browsing" ] && printf ',"private-browsing":true'
  161. printf '}'
  162. [ "$addon_preferences_json" ] && printf ',"preferences":%s' \
  163. "`jpmJsonNormalizeArg "$addon_preferences_json"`"
  164. [ "$addon_translators_json" ] && printf ',"translators":%s' \
  165. "`jpmJsonNormalizeArg "$addon_translators_json"`"
  166. [ "$addon_unpack" ] && printf ',"unpack":true'
  167. printf '}'
  168. }
  169. # @private
  170. # jpmXpiGenInstallRdfTarget <uuid> <minVersion> <maxVersion>
  171. jpmXpiGenInstallRdfTarget () {
  172. cat <<RDF
  173. <em:targetApplication><Description>
  174. <em:id>${1}</em:id>
  175. <em:minVersion>${2}</em:minVersion>
  176. <em:maxVersion>${3}</em:maxVersion>
  177. </Description></em:targetApplication>
  178. RDF
  179. }
  180. # jpmXpiGenInstallRdf <id> <version>
  181. jpmXpiGenInstallRdf () {
  182. uuidFirefox='{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'
  183. uuidFennec='{aa3c5121-dab2-40e2-81ca-7ea25febc110}'
  184. uuidThunderbird='{3550f703-e582-4d05-9a08-453d09bdfdc6}'
  185. uuidSeamonkey='{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'
  186. uuidPaleMoon='{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}'
  187. versionF=`jpmXpiFormatVersion "$2"`
  188. # XXX: hardcoded
  189. targetFirefox=`jpmXpiGenInstallRdfTarget "$uuidFirefox" '38.0a1' '*'`
  190. targetFennec=''
  191. targetThunderbird=''
  192. targetSeamonkey=''
  193. [ "${addon_fennec_version}" ] && \
  194. targetFennec=`jpmXpiGenInstallRdfTarget "$uuidFennec" '38.0a1' '*'`
  195. [ "${addon_thunderbird_version}" ] && \
  196. targetThunderbird=`jpmXpiGenInstallRdfTarget "$uuidThunderbird" '38.0a1' '48.*'`
  197. [ "${addon_seamonkey_version}" ] && \
  198. targetSeamonkey=`jpmXpiGenInstallRdfTarget "$uuidSeamonkey" '2.38' '2.47.*'`
  199. # XXX Experimental: Be careful!
  200. [ "${addon_palemoon_version}" ] && \
  201. targetPaleMoon=`jpmXpiGenInstallRdfTarget "$uuidPaleMoon" '25.0' '26.*'`
  202. cat <<RDF
  203. <?xml version="1.0" encoding="utf-8"?>
  204. <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#">
  205. <Description about="urn:mozilla:install-manifest">
  206. <em:id>`jpmXmlEscapeArg "$1"`</em:id>
  207. <em:type>2</em:type>
  208. <em:bootstrap>true</em:bootstrap>
  209. <em:unpack>`jpmToBoolValue "${addon_unpack}"`</em:unpack>
  210. <em:version>`jpmXmlEscapeArg "$versionF"`</em:version>
  211. <em:name>`jpmXmlEscapeArg "${addon_name}"`</em:name>
  212. <em:description>`jpmXmlEscapeArg "${addon_description}"`</em:description>
  213. <em:creator>`jpmXmlEscapeArg "${addon_author}"`</em:creator>
  214. <em:optionsURL>data:text/xml,&lt;placeholder/&gt;</em:optionsURL>
  215. <em:optionsType>2</em:optionsType>
  216. <em:multiprocessCompatible>true</em:multiprocessCompatible>
  217. ${targetFirefox}${targetFennec}${targetThunderbird}${targetSeamonkey}${targetPaleMoon}
  218. </Description>
  219. </RDF>
  220. RDF
  221. }