[Libreoffice-commits] core.git: Branch 'aoo/trunk' - instsetoo_native/data instsetoo_native/util solenv/bin
Andre Fischer
af at apache.org
Wed Dec 4 02:07:52 PST 2013
instsetoo_native/data/releases.xml | 275 +-
instsetoo_native/util/makefile.mk | 113 -
solenv/bin/make_installer.pl | 133 +
solenv/bin/modules/installer/globals.pm | 9
solenv/bin/modules/installer/logger.pm | 10
solenv/bin/modules/installer/parameter.pm | 4
solenv/bin/modules/installer/patch/FileSequenceList.pm | 119 -
solenv/bin/modules/installer/patch/InstallationSet.pm | 401 +++-
solenv/bin/modules/installer/patch/Msi.pm | 291 ++-
solenv/bin/modules/installer/patch/MsiRow.pm | 9
solenv/bin/modules/installer/patch/MsiTable.pm | 230 ++
solenv/bin/modules/installer/patch/ReleasesList.pm | 283 ++-
solenv/bin/modules/installer/patch/Tools.pm | 19
solenv/bin/modules/installer/patch/Version.pm | 35
solenv/bin/modules/installer/systemactions.pm | 52
solenv/bin/modules/installer/windows/component.pm | 308 ++-
solenv/bin/modules/installer/windows/directory.pm | 642 ++++--
solenv/bin/modules/installer/windows/file.pm | 648 +++++--
solenv/bin/modules/installer/windows/msiglobal.pm | 255 +-
solenv/bin/modules/installer/windows/registry.pm | 169 +
solenv/bin/patch_tool.pl | 1571 +++++++++++++++++
solenv/bin/release_prepare.pl | 141 -
22 files changed, 4625 insertions(+), 1092 deletions(-)
New commits:
commit 1138b2a95c8c985e5682ab4b25b15b00e96cc8e5
Author: Andre Fischer <af at apache.org>
Date: Wed Dec 4 08:51:30 2013 +0000
123531: Reimplemented support for creating patches on Windows.
diff --git a/instsetoo_native/data/releases.xml b/instsetoo_native/data/releases.xml
index 34c4d07..a8635f6 100644
--- a/instsetoo_native/data/releases.xml
+++ b/instsetoo_native/data/releases.xml
@@ -21,296 +21,357 @@
***********************************************************-->
<releases>
<release>
- <version>4.0.0</version>
- <download>
+ <version>
+ <major>4</major>
+ <minor>0</minor>
+ <micro>0</micro>
+ </version>
+ <downloads>
<package-format>msi</package-format>
<url-template>
http://archive.apache.org/dist/openoffice/4.0.0/binaries/%L/Apache_OpenOffice_4.0.0_Win_x86_install_%L.exe
</url-template>
+ <upgrade-code>7C35B9AB-2CE3-4C18-BE7C-5B97EA089EB3</upgrade-code>
+ <build-id>9702</build-id>
<item>
<language>ast</language>
<checksum type="sha256">415e2f3cf4d99a3f6ad495e33b89c716ef6966c9c4d7df90ad6e004fcf0222f4</checksum>
<size>154219869</size>
+ <product-code>59496534-E113-4A02-AC23-DD77E6079398</product-code>
</item>
<item>
<language>cs</language>
<checksum type="sha256">a90a2c00c58f3e30654b89b4a363b099b0a7d1f829ebf9c7c18333d387f4bf41</checksum>
<size>130773239</size>
+ <product-code>A81E275C-C1D1-473D-90D9-7EAE310550C7</product-code>
</item>
<item>
<language>de</language>
<checksum type="sha256">5569634ac40b42a710c666d0511f6aa4dbcb05d1a525e06f6be038e828c507f0</checksum>
<size>162401424</size>
+ <product-code>B28DBCBA-60F8-40ED-B35B-F510C327946C</product-code>
</item>
<item>
<language>el</language>
<checksum type="sha256">cc5cde6314cea634200da6861da527c11ca7d74338074cdd4e5a22e1ffd9ef7c</checksum>
<size>139633387</size>
+ <product-code>43A3EED6-E15A-4EBA-9FBA-E0A0D1793EDA</product-code>
</item>
<item>
<language>en-GB</language>
<checksum type="sha256">7f83397877b72e7f2da38f11b76c3f46e30b93713b40becba699d21f913847e0</checksum>
<size>136201626</size>
- </item>
- <item>
- <language>en-US</language>
- <checksum type="sha256">8db246183f549c298d731cf61771f8f8adb37028d8ecc737fe1ad452899adb2d</checksum>
- <size>143436858</size>
+ <product-code>EA1DC8F8-C357-44CA-A332-AB9762DF698C</product-code>
</item>
<item>
<language>es</language>
<checksum type="sha256">eb991c71b436c4d740f3d2b5441716fc321bb57eb7f36c7019ec86feebb7f5d4</checksum>
<size>132424454</size>
+ <product-code>FBD275C7-DD8C-4056-BD4F-5ECC1A56DE6A</product-code>
</item>
<item>
<language>fi</language>
<checksum type="sha256">fa2b9015864651be44afc940988ed20c6093bc8707aea72ab1b75cf147d81ed2</checksum>
<size>138474963</size>
+ <product-code>1D365623-A8E7-4ACA-8CBB-431A6CCA1F84</product-code>
</item>
<item>
<language>fr</language>
<checksum type="sha256">b4b20eac7f6220a4a6250e79d950a328d08b927b8856d762b0b1e033833e198f</checksum>
<size>133397214</size>
+ <product-code>4F8C9861-DDCF-4EE8-978C-35B691C406B3</product-code>
</item>
<item>
<language>gd</language>
<checksum type="sha256">c2e5ac75f899efab61f039a193a68ec2f4d092fd43c6eb46d8b2d34d8166ce6e</checksum>
<size>154472734</size>
+ <product-code>D67CE80F-3DD6-4433-ACE3-C591B8CA013B</product-code>
</item>
<item>
<language>gl</language>
<checksum type="sha256">bac4915fd47b9e219d72a02a268fa590096c0884ebafd966b10e9b77fe16eee0</checksum>
<size>137952793</size>
+ <product-code>529BC9F1-8478-4F1E-9FCD-144ED91B529B</product-code>
</item>
<item>
<language>hu</language>
<checksum type="sha256">2e01d00431692cb6071cf520e71b900dba28a846dccf4ed3a85c245761c98906</checksum>
<size>133240224</size>
+ <product-code>FAA13518-DA5A-429B-990F-896589C83900</product-code>
</item>
<item>
<language>it</language>
<checksum type="sha256">8663c01de8f62b26a7864ac4da6abd316a1c2e00b35c60372cad5287120fe409</checksum>
<size>138823014</size>
+ <product-code>B73A5540-CC29-489E-B513-B58EEDEB3A69</product-code>
</item>
<item>
<language>ja</language>
<checksum type="sha256">559f165ee9ff516a80573befaf7d0936ca81fa89aca655213b4f265eb7c7059a</checksum>
<size>136416679</size>
+ <product-code>B611F56C-12F5-4AC2-8395-F6E7E79A2FE7</product-code>
</item>
<item>
<language>ko</language>
<checksum type="sha256">daa7f3b51e6ffb0b541a98fbcdc0bad53eea579a7d74c9acbdd73ad660b117b1</checksum>
<size>131617051</size>
+ <product-code>FAF9DE58-C459-44C8-A627-DCD83BC071BA</product-code>
</item>
<item>
<language>nl</language>
<checksum type="sha256">fcc6e55c7a1407be8e8f2faf7305ebb9a8f7e1bea882e5d917b5846a2c0ee955</checksum>
<size>138526756</size>
+ <product-code>EB29A33D-3425-486D-B602-E464ADE4D71C</product-code>
</item>
<item>
<language>pt</language>
<checksum type="sha256">58307e0eeb485840e1462a23f8741e793422ccdc468123f85876ae287482a987</checksum>
<size>130929247</size>
+ <product-code>497906E9-6B2F-45C4-BA2B-B662DCFDE940</product-code>
</item>
<item>
<language>pt-BR</language>
<checksum type="sha256">08ef83f28e138dc0bc6bdf761e4676eb13c2b30717ce47e0becec2de90c73f7a</checksum>
<size>130814647</size>
+ <product-code>8DCC7121-A76E-4493-A90E-06E06485E4FF</product-code>
</item>
<item>
<language>ru</language>
<checksum type="sha256">dda689b273eb9ddadfb156a08df8e73c3b41e3cc8178a16546e282f8e1c54d77</checksum>
<size>137558077</size>
+ <product-code>970C0E46-87BD-4210-9F24-CCD5A902F7D3</product-code>
</item>
<item>
<language>sk</language>
<checksum type="sha256">d2722d2569178838a57705e76062603f995f71d5219e8f910bc7a6b46fa6039a</checksum>
<size>131199460</size>
+ <product-code>B645BA5F-A4CD-44B8-BE37-A0F6BDF4A6D3</product-code>
</item>
<item>
<language>sl</language>
<checksum type="sha256">eecea1c75833a873a3cc00f81c85f411319b085728224c716ac90159622c0c3e</checksum>
<size>132340393</size>
+ <product-code>0489E54B-1826-45CB-8197-794634889904</product-code>
</item>
<item>
<language>ta</language>
<checksum type="sha256">4051b4831a960a8f27a3f56f32d7bd5a7bbdfcf859238a149aca9cd69ae0121c</checksum>
<size>136961005</size>
+ <product-code>99F5B898-533E-4248-90D6-AA7202A3325C</product-code>
</item>
<item>
<language>zh-CN</language>
<checksum type="sha256">94424b9c24d3237e70d6452da8366cf9c6617a46fa171901db093b1a1166934d</checksum>
<size>131840961</size>
+ <product-code>BFB77D24-4983-4FD8-99A8-164206DEFBEE</product-code>
</item>
- </download>
+ </downloads>
</release>
<release>
- <version>4.0.1</version>
- <download>
+ <version>
+ <major>4</major>
+ <minor>0</minor>
+ <micro>1</micro>
+ </version>
+ <downloads>
<package-format>msi</package-format>
<url-template>
http://archive.apache.org/dist/openoffice/4.0.1/binaries/%L/Apache_OpenOffice_4.0.1_Win_x86_install_%L.exe
</url-template>
+ <upgrade-code>7C35B9AB-2CE3-4C18-BE7C-5B97EA089EB3</upgrade-code>
+ <build-id>9714</build-id>
<item>
- <language>ast</language>
- <checksum type="sha256">9854b6a99c6e56902e30ec01009e294aafe091e4733e9b8933690ee0365d6754</checksum>
- <size>154320289</size>
+ <language>ast</language>
+ <checksum type="sha256">9854b6a99c6e56902e30ec01009e294aafe091e4733e9b8933690ee0365d6754</checksum>
+ <size>154320289</size>
+ <product-code>0D9885DA-8FEC-410B-A1A9-0282C58E04FC</product-code>
</item>
<item>
- <language>cs</language>
- <checksum type="sha256">b23c5dc07a6e521a7ad24e7c1d131c96ea3a6fdf3a2f96020b5cad2e7ebe0253</checksum>
- <size>130785256</size>
+ <language>cs</language>
+ <checksum type="sha256">b23c5dc07a6e521a7ad24e7c1d131c96ea3a6fdf3a2f96020b5cad2e7ebe0253</checksum>
+ <size>130785256</size>
+ <product-code>220C463A-2890-4C7F-B97C-C49FE175B849</product-code>
</item>
<item>
- <language>de</language>
- <checksum type="sha256">fbbe39def767e6ecd16c7b6802f35d6e4b035c4b72328bbf0a8f045cf585aaa7</checksum>
- <size>163606685</size>
+ <language>de</language>
+ <checksum type="sha256">fbbe39def767e6ecd16c7b6802f35d6e4b035c4b72328bbf0a8f045cf585aaa7</checksum>
+ <size>163606685</size>
+ <product-code>0AEC308E-7EB3-47F7-BB59-F2C9C6166B27</product-code>
</item>
<item>
- <language>el</language>
- <checksum type="sha256">e59f47b986c4bcd8f21062446b299f68ac7ed941356813b0e2dbd651fb59c847</checksum>
- <size>139717373</size>
+ <language>el</language>
+ <checksum type="sha256">e59f47b986c4bcd8f21062446b299f68ac7ed941356813b0e2dbd651fb59c847</checksum>
+ <size>139717373</size>
+ <product-code>8022138A-6A6B-45CC-A2F2-81E7E21A4284</product-code>
</item>
<item>
- <language>en-GB</language>
- <checksum type="sha256">75f06dbe9f13804ea9f3ef20d831e300a55df1bf1a5b656d2422206a8a0d8bda</checksum>
- <size>136295104</size>
+ <language>en-GB</language>
+ <checksum type="sha256">75f06dbe9f13804ea9f3ef20d831e300a55df1bf1a5b656d2422206a8a0d8bda</checksum>
+ <size>136295104</size>
+ <product-code>24B89186-2A56-4D28-B930-6F4FCF224E2F</product-code>
</item>
<item>
- <language>en-US</language>
- <checksum type="sha256">3b68145a33fa83d246febb3b7551fb0cbf57363bc772401ac0c37cfc1cde21b3</checksum>
- <size>143485940</size>
+ <language>en-US</language>
+ <checksum type="sha256">3b68145a33fa83d246febb3b7551fb0cbf57363bc772401ac0c37cfc1cde21b3</checksum>
+ <size>143485940</size>
+ <product-code>47F460DA-D1BE-4D85-8DF2-AA1F31D3445F</product-code>
</item>
<item>
- <language>es</language>
- <checksum type="sha256">5136276a370378d11327b9a0bd074d269a49e797c7186f2e3cc9cf6c0bbc20fc</checksum>
- <size>132478227</size>
+ <language>es</language>
+ <checksum type="sha256">5136276a370378d11327b9a0bd074d269a49e797c7186f2e3cc9cf6c0bbc20fc</checksum>
+ <size>132478227</size>
+ <product-code>52F63384-0FE8-41F5-B9C1-3331BE2E74F1</product-code>
</item>
<item>
- <language>eu</language>
- <checksum type="sha256">aae1ff61af9ac117637842ccc1c28221620c79b05ffbb1fb47d8a6fcbe3b1700</checksum>
- <size>131476228</size>
+ <language>eu</language>
+ <checksum type="sha256">aae1ff61af9ac117637842ccc1c28221620c79b05ffbb1fb47d8a6fcbe3b1700</checksum>
+ <size>131476228</size>
+ <product-code>3EEA17A1-B7AC-40BC-BDA8-ED58A5695225</product-code>
</item>
<item>
- <language>fi</language>
- <checksum type="sha256">65ff3209a51afefde11dd1326921340ebe035f09626d8884f37a0f72f8c2785b</checksum>
- <size>138523539</size>
+ <language>fi</language>
+ <checksum type="sha256">65ff3209a51afefde11dd1326921340ebe035f09626d8884f37a0f72f8c2785b</checksum>
+ <size>138523539</size>
+ <product-code>955C3F64-C693-41E6-B9D5-A505A5C41B52</product-code>
</item>
<item>
- <language>fr</language>
- <checksum type="sha256">70c97dc59412a8e4aeb87e51e8714cbba776397beb6a774804591653150e78d5</checksum>
- <size>134622711</size>
+ <language>fr</language>
+ <checksum type="sha256">70c97dc59412a8e4aeb87e51e8714cbba776397beb6a774804591653150e78d5</checksum>
+ <size>134622711</size>
+ <product-code>8D5D54B8-3D29-4AB4-8DA8-1868DAF941D8</product-code>
</item>
<item>
- <language>gd</language>
- <checksum type="sha256">a57115a636f4004de2df9599e72bc4d07937b65a6bb99fe126dc18a788a57142</checksum>
- <size>154574682</size>
+ <language>gd</language>
+ <checksum type="sha256">a57115a636f4004de2df9599e72bc4d07937b65a6bb99fe126dc18a788a57142</checksum>
+ <size>154574682</size>
+ <product-code>17010592-9593-4061-B5C8-21CED2273B3C</product-code>
</item>
<item>
- <language>gl</language>
- <checksum type="sha256">4c8fe9b42193dc37dc6a2b979b790ea6317ea25a6fa27fcb9007036c5725111d</checksum>
- <size>138019151</size>
+ <language>gl</language>
+ <checksum type="sha256">4c8fe9b42193dc37dc6a2b979b790ea6317ea25a6fa27fcb9007036c5725111d</checksum>
+ <size>138019151</size>
+ <product-code>61A540F1-3DB4-4215-9259-21BD0D98746D</product-code>
</item>
<item>
- <language>hu</language>
- <checksum type="sha256">97765ef536ed1e3f07220fe4cb90520efdfb376fab751ad2cac7390316f14e65</checksum>
- <size>133302800</size>
+ <language>hu</language>
+ <checksum type="sha256">97765ef536ed1e3f07220fe4cb90520efdfb376fab751ad2cac7390316f14e65</checksum>
+ <size>133302800</size>
+ <product-code>BE64FC93-72C0-4540-BC12-B8FEAE8CA33B</product-code>
</item>
<item>
- <language>it</language>
- <checksum type="sha256">c6fa3e0e9bef615d804b5d24d3f2cc49f7655aee01ef34cecb9b520a47249d02</checksum>
- <size>138894766</size>
+ <language>it</language>
+ <checksum type="sha256">c6fa3e0e9bef615d804b5d24d3f2cc49f7655aee01ef34cecb9b520a47249d02</checksum>
+ <size>138894766</size>
+ <product-code>03F15CFC-BA7D-48B8-AA16-7F152BA27547</product-code>
</item>
<item>
- <language>ja</language>
- <checksum type="sha256">93d20ae5f96f4a93c705894849f01b6501604bf003e9b66f7d0dbdc6f2282965</checksum>
- <size>136444096</size>
+ <language>ja</language>
+ <checksum type="sha256">93d20ae5f96f4a93c705894849f01b6501604bf003e9b66f7d0dbdc6f2282965</checksum>
+ <size>136444096</size>
+ <product-code>BA498C26-5210-4F14-BE9C-63041FCD306E</product-code>
</item>
<item>
- <language>km</language>
- <checksum type="sha256">4fc263c631d4ba797633d28ca529202b600d5fe676a8c215904d12d08ed8cc49</checksum>
- <size>151866955</size>
+ <language>km</language>
+ <checksum type="sha256">4fc263c631d4ba797633d28ca529202b600d5fe676a8c215904d12d08ed8cc49</checksum>
+ <size>151866955</size>
+ <product-code>D10262B9-30E7-4EF8-8BF1-3C7BEDBEF4EE</product-code>
</item>
<item>
- <language>ko</language>
- <checksum type="sha256">2abd13afe2978c4300d872a06dcec00ae23592ed563be3d0d046ef81738d7a87</checksum>
- <size>131671507</size>
+ <language>ko</language>
+ <checksum type="sha256">2abd13afe2978c4300d872a06dcec00ae23592ed563be3d0d046ef81738d7a87</checksum>
+ <size>131671507</size>
+ <product-code>697857AD-7EF1-4A6E-8F5B-D53409B97FB0</product-code>
</item>
<item>
- <language>lt</language>
- <checksum type="sha256">4ac6c2c88edb5254e0cf93f49daaf5e411ea0168d6c431d11da5d89638977cff</checksum>
- <size>136935582</size>
+ <language>lt</language>
+ <checksum type="sha256">4ac6c2c88edb5254e0cf93f49daaf5e411ea0168d6c431d11da5d89638977cff</checksum>
+ <size>136935582</size>
+ <product-code>4DDF6CE7-9E5E-4192-9996-288AB7B23644</product-code>
</item>
<item>
- <language>nl</language>
- <checksum type="sha256">85292dad5aa80711c126091d3565dc9cd2219d818a59cbd5c7c9a4bc5282ebb8</checksum>
- <size>139734741</size>
+ <language>nl</language>
+ <checksum type="sha256">85292dad5aa80711c126091d3565dc9cd2219d818a59cbd5c7c9a4bc5282ebb8</checksum>
+ <size>139734741</size>
+ <product-code>EA9BAE1A-2D68-4160-81E6-14B712435D66</product-code>
</item>
<item>
- <language>pl</language>
- <checksum type="sha256">c71c63d0c0e76f28b7d3bebb39e1cb9c0ca35e29557c53528f631e6c1aeca04c</checksum>
- <size>133661993</size>
+ <language>pl</language>
+ <checksum type="sha256">c71c63d0c0e76f28b7d3bebb39e1cb9c0ca35e29557c53528f631e6c1aeca04c</checksum>
+ <size>133661993</size>
+ <product-code>DA0106A3-216E-48DE-9CF6-655DA8FC1D22</product-code>
</item>
<item>
- <language>pt-BR</language>
- <checksum type="sha256">e6baed3d30d4b18e32e21ab4fcd22446ac1f8a40efe49a4f105e9c3fc0ba1611</checksum>
- <size>130866989</size>
+ <language>pt</language>
+ <checksum type="sha256">dd855dc99fc41fd509e938881397798fa2e9ed92e663cb8b9ea6c356d5d5a096</checksum>
+ <size>130989882</size>
+ <product-code>08D91641-36A2-4DA8-BA5B-6DFF68BBFE04</product-code>
</item>
<item>
- <language>pt</language>
- <checksum type="sha256">dd855dc99fc41fd509e938881397798fa2e9ed92e663cb8b9ea6c356d5d5a096</checksum>
- <size>130989882</size>
+ <language>pt-BR</language>
+ <checksum type="sha256">e6baed3d30d4b18e32e21ab4fcd22446ac1f8a40efe49a4f105e9c3fc0ba1611</checksum>
+ <size>130866989</size>
+ <product-code>50FA6B86-D3C4-4961-A58F-1A061B2DCE04</product-code>
</item>
<item>
- <language>ru</language>
- <checksum type="sha256">7e965822f8dfb0aa4a67bf5bff8ddb852901c672886bb9f2ee275c5c976c0a48</checksum>
- <size>137584051</size>
+ <language>ru</language>
+ <checksum type="sha256">7e965822f8dfb0aa4a67bf5bff8ddb852901c672886bb9f2ee275c5c976c0a48</checksum>
+ <size>137584051</size>
+ <product-code>85B491F5-56FA-483B-92EE-C6F90CCDBA74</product-code>
</item>
<item>
- <language>sk</language>
- <checksum type="sha256">4400eb30ca5072b175da7963049bb0ecca761af73b7dbccb9a0b4cd789b26042</checksum>
- <size>131265676</size>
+ <language>sk</language>
+ <checksum type="sha256">4400eb30ca5072b175da7963049bb0ecca761af73b7dbccb9a0b4cd789b26042</checksum>
+ <size>131265676</size>
+ <product-code>A00F439C-600D-4220-96CF-C6F1F8C32633</product-code>
</item>
<item>
- <language>sl</language>
- <checksum type="sha256">83d384d9e50ddcb9c1d74069d8796e5f37bed55b5da6f43c326c0784a6e61cef</checksum>
- <size>132368586</size>
+ <language>sl</language>
+ <checksum type="sha256">83d384d9e50ddcb9c1d74069d8796e5f37bed55b5da6f43c326c0784a6e61cef</checksum>
+ <size>132368586</size>
+ <product-code>0BFA9E1C-B3EB-4E6C-812F-CAA1D88F0F09</product-code>
</item>
<item>
- <language>sr</language>
- <checksum type="sha256">a2d2e043c1c3fa9a90924ae29138641b238d7749984f873a8672e2844a55e3d9</checksum>
- <size>136961170</size>
+ <language>sr</language>
+ <checksum type="sha256">a2d2e043c1c3fa9a90924ae29138641b238d7749984f873a8672e2844a55e3d9</checksum>
+ <size>136961170</size>
+ <product-code>02E47753-869E-4757-92FA-478E8EF0FEA3</product-code>
</item>
<item>
- <language>sv</language>
- <checksum type="sha256">15cbdb4f5a7ecf253f31981d0203c08e279a26603ca737e64f740524e1d672ca</checksum>
- <size>131330363</size>
+ <language>sv</language>
+ <checksum type="sha256">15cbdb4f5a7ecf253f31981d0203c08e279a26603ca737e64f740524e1d672ca</checksum>
+ <size>131330363</size>
+ <product-code>46BCB691-9148-4FCB-B215-CCDF70B5D95A</product-code>
</item>
<item>
- <language>ta</language>
- <checksum type="sha256">352083d6d2fc6c39027a03fbbb6449d4a67955b370c5a8efba0407b74a456bc9</checksum>
- <size>137001517</size>
+ <language>ta</language>
+ <checksum type="sha256">352083d6d2fc6c39027a03fbbb6449d4a67955b370c5a8efba0407b74a456bc9</checksum>
+ <size>137001517</size>
+ <product-code>1297D7DE-BCDB-4B37-81AC-03C34DCF0A9B</product-code>
</item>
<item>
- <language>tr</language>
- <checksum type="sha256">bdfbf83cc905bf44f086ea51295899a042667fa6334e6378ef5b5b354843ba37</checksum>
- <size>130397087</size>
+ <language>tr</language>
+ <checksum type="sha256">bdfbf83cc905bf44f086ea51295899a042667fa6334e6378ef5b5b354843ba37</checksum>
+ <size>130397087</size>
+ <product-code>7242DE31-0571-4C24-A142-E60AB70D6982</product-code>
</item>
<item>
- <language>vi</language>
- <checksum type="sha256">0483c20036f47738ae86a19d0ab4e66eff8d8f5226f716970a4ec7f56a78bff6</checksum>
- <size>131526617</size>
+ <language>vi</language>
+ <checksum type="sha256">0483c20036f47738ae86a19d0ab4e66eff8d8f5226f716970a4ec7f56a78bff6</checksum>
+ <size>131526617</size>
+ <product-code>37188DD9-F074-40CC-BCE4-EB0E7EA664BD</product-code>
</item>
<item>
- <language>zh-CN</language>
- <checksum type="sha256">f2966f3c251cf31a24d7931950838c04e410935dd15a6fdd9241acf81bc5e784</checksum>
- <size>131863915</size>
+ <language>zh-CN</language>
+ <checksum type="sha256">f2966f3c251cf31a24d7931950838c04e410935dd15a6fdd9241acf81bc5e784</checksum>
+ <size>131863915</size>
+ <product-code>2E6C4507-4909-44A6-AD5C-0FC1FDCDCFA1</product-code>
</item>
<item>
- <language>zh-TW</language>
- <checksum type="sha256">a194cfb2dc2cbcae2e89740485ebfcbf605b7c80a5bbdffb699e447c53698e53</checksum>
- <size>131990994</size>
+ <language>zh-TW</language>
+ <checksum type="sha256">a194cfb2dc2cbcae2e89740485ebfcbf605b7c80a5bbdffb699e447c53698e53</checksum>
+ <size>131990994</size>
+ <product-code>7890D527-C555-46DA-B60F-173675BFCC19</product-code>
</item>
- </download>
+ </downloads>
</release>
</releases>
\ No newline at end of file
diff --git a/instsetoo_native/util/makefile.mk b/instsetoo_native/util/makefile.mk
index c608103..5e6cc6e 100644
--- a/instsetoo_native/util/makefile.mk
+++ b/instsetoo_native/util/makefile.mk
@@ -19,8 +19,6 @@
#
#**************************************************************
-
-
PRJ=..
PRJNAME=instsetoo_native
TARGET=util
@@ -74,6 +72,10 @@ help .PHONY :
@echo " sdkoo"
@echo " sdkoodev"
@echo
+ @echo "experimental targets:"
+ @echo " patch_create create a patch for updating an installed office (Windows only)"
+ @echo " patch_apply apply a previously created patch"
+ @echo
@echo "Most targets (all except aoo_srcrelease and updatepack) accept suffixes"
@echo " add _<language> to build a target for one language only"
@echo " the default set of languages is alllangiso=$(alllangiso)"
@@ -81,9 +83,9 @@ help .PHONY :
@echo " the default set of package formats is archive and PKGFORMAT=$(PKGFORMAT)"
-LOCALPYFILES= \
- $(BIN)$/uno.py \
- $(BIN)$/unohelper.py \
+LOCALPYFILES= \
+ $(BIN)$/uno.py \
+ $(BIN)$/unohelper.py \
$(BIN)$/pythonloader.py \
$(BIN)$/pythonscript.py \
$(BIN)$/officehelper.py \
@@ -118,7 +120,7 @@ PKGFORMAT+=$(MAKETARGETS:e:s/.//)
# Independent of PKGFORMAT, always build a default-language openoffice product
# also in archive format, so that tests that require an OOo installation (like
# smoketestoo_native) have one available:
-openoffice_$(defaultlangiso) : $$@.archive
+#openoffice_$(defaultlangiso) : $$@.archive
.IF "$(VERBOSE)"=="TRUE"
VERBOSESWITCH=-verbose
@@ -126,6 +128,20 @@ VERBOSESWITCH=-verbose
VERBOSESWITCH=-quiet
.ENDIF
+.IF "$(release:U)"=="T"
+RELEASE_SWITCH=-release
+$(foreach,i,$(alllangiso) openoffice_$i.msi) : prepare_release_build
+.ELSE
+RELEASE_SWITCH=
+.ENDIF
+
+prepare_release_build .PHONY:
+ @$(PERL) -w $(SOLARENV)$/bin$/release_prepare.pl \
+ --lst-file $(PRJ)$/util$/openoffice.lst \
+ --product-name Apache_OpenOffice \
+ --output-path $(OUT) \
+ $(alllangiso)
+
.IF "$(VERBOSE_INSTALLER)"=="TRUE"
VERBOSESWITCH+=-log
.ENDIF
@@ -166,12 +182,20 @@ MSIOFFICETEMPLATEDIR=$(MISC)$/openoffice$/msi_templates
MSILANGPACKTEMPLATEDIR=$(MISC)$/ooolangpack$/msi_templates
MSISDKOOTEMPLATEDIR=$(MISC)$/sdkoo$/msi_templates
-ADDDEPS=$(NOLOGOSPLASH) $(DEVNOLOGOSPLASH)
+ADDDEPS=adddeps
+adddeps .PHONY : $(NOLOGOSPLASH) $(DEVNOLOGOSPLASH)
.IF "$(OS)" == "WNT"
-ADDDEPS+=msitemplates
+adddeps : msitemplates
.ENDIF
+.IF "$(LOCALPYFILES)"!=""
+local_python_files .PHONY : $(LOCALPYFILES)
+adddeps : local_python_files
+updatepack : local_python_files
+.ENDIF # "$(LOCALPYFILES)"!=""
+
+
$(foreach,i,$(alllangiso) openoffice_$i) : $(ADDDEPS)
openoffice_$(defaultlangiso).archive : $(ADDDEPS)
@@ -187,23 +211,19 @@ $(foreach,i,$(alllangiso) sdkoo_$i) : $(ADDDEPS)
$(foreach,i,$(alllangiso) sdkoodev_$i) : $(ADDDEPS)
-.IF "$(MAKETARGETS)"!=""
-$(MAKETARGETS) : $(ADDDEPS)
-.ENDIF # "$(MAKETARGETS)"!=""
-
$(foreach,i,$(alllangiso) openoffice_$i) : $$@{$(PKGFORMAT:^".")}
-.IF "$(MAKETARGETS)"!=""
-.IF "$(MAKETARGETS:e)"=="" && "$(MAKETARGETS:s/_//)"!="$(MAKETARGETS)"
-$(MAKETARGETS) : $$@{$(PKGFORMAT:^".")}
-$(MAKETARGETS){$(PKGFORMAT:^".")} : $(ADDDEPS)
-.ENDIF # "$(MAKETARGETS:e)"=="" && "$(MAKETARGETS:s/_//)"!="$(MAKETARGETS)"
-.ENDIF # "$(MAKETARGETS)"!=""
+$(foreach,i,$(alllangiso) openofficewithjre_$i) : $$@{$(PKGFORMAT:^".")}
+$(foreach,i,$(alllangiso) openofficedev_$i) : $$@{$(PKGFORMAT:^".")}
+$(foreach,i,$(alllangiso) ooolanguagepack_$i) : $$@{$(PKGFORMAT:^".")}
+$(foreach,i,$(alllangiso) ooodevlanguagepack_$i) : $$@{$(PKGFORMAT:^".")}
+$(foreach,i,$(alllangiso) sdkoo_$i) : $$@{$(PKGFORMAT:^".")}
+$(foreach,i,$(alllangiso) sdkoodev_$i) : $$@{$(PKGFORMAT:^".")}
# This macro makes calling the make_installer.pl script a bit easier.
# Just add -p and -msitemplate switches.
MAKE_INSTALLER_COMMAND= \
- @$(PERL) -w $(SOLARENV)$/bin$/make_installer.pl \
+ @$(PERL) -w $(SOLARENV)$/bin$/make_installer.pl \
-f $(PRJ)$/util$/openoffice.lst \
-l $(subst,$(@:s/_/ /:1)_, $(@:b)) \
-u $(OUT) \
@@ -215,7 +235,7 @@ MAKE_INSTALLER_COMMAND= \
# This macro makes calling gen_update_info.pl a bit easier
# Just add --product switches, and xml input file and redirect output.
GEN_UPDATE_INFO_COMMAND= \
- @$(PERL) -w $(SOLARENV)$/bin$/gen_update_info.pl \
+ @$(PERL) -w $(SOLARENV)$/bin$/gen_update_info.pl \
--buildid $(BUILD) \
--arch "$(RTL_ARCH)" \
--os "$(RTL_OS)" \
@@ -223,9 +243,10 @@ GEN_UPDATE_INFO_COMMAND= \
--languages $(subst,$(@:s/_/ /:1)_, $(@:b))
openoffice_%{$(PKGFORMAT:^".")} :
- $(MAKE_INSTALLER_COMMAND) \
- -p Apache_OpenOffice \
- -msitemplate $(MSIOFFICETEMPLATEDIR)
+ $(MAKE_INSTALLER_COMMAND) \
+ -p Apache_OpenOffice \
+ -msitemplate $(MSIOFFICETEMPLATEDIR) \
+ $(RELEASE_SWITCH)
$(GEN_UPDATE_INFO_COMMAND) \
--product Apache_OpenOffice \
$(PRJ)$/util$/update.xml \
@@ -240,11 +261,9 @@ openoffice_%{.archive} :
$(PRJ)$/util$/update.xml \
> $(MISC)/$(@:b)_$(RTL_OS)_$(RTL_ARCH)$(@:e).update.xml
-$(foreach,i,$(alllangiso) openofficewithjre_$i) : $$@{$(PKGFORMAT:^".")}
openofficewithjre_%{$(PKGFORMAT:^".")} :
$(MAKE_INSTALLER_COMMAND) -p Apache_OpenOffice_wJRE -msitemplate $(MSIOFFICETEMPLATEDIR)
-$(foreach,i,$(alllangiso) openofficedev_$i) : $$@{$(PKGFORMAT:^".")}
openofficedev_%{$(PKGFORMAT:^".")} :
$(MAKE_INSTALLER_COMMAND) \
-p Apache_OpenOffice_Dev \
@@ -254,54 +273,57 @@ openofficedev_%{$(PKGFORMAT:^".")} :
$(PRJ)$/util$/update.xml \
> $(MISC)/$(@:b)_$(RTL_OS)_$(RTL_ARCH)$(@:e).update.xml
-$(foreach,i,$(alllangiso) ooolanguagepack_$i) : $$@{$(PKGFORMAT:^".")}
ooolanguagepack_%{$(PKGFORMAT:^".")} :
$(MAKE_INSTALLER_COMMAND) \
-p Apache_OpenOffice \
-msitemplate $(MSILANGPACKTEMPLATEDIR) \
-languagepack
-$(foreach,i,$(alllangiso) ooodevlanguagepack_$i) : $$@{$(PKGFORMAT:^".")}
ooodevlanguagepack_%{$(PKGFORMAT:^".")} :
$(MAKE_INSTALLER_COMMAND) -p Apache_OpenOffice_Dev -msitemplate $(MSILANGPACKTEMPLATEDIR) -languagepack
-$(foreach,i,$(alllangiso) sdkoo_$i) : $$@{$(PKGFORMAT:^".")}
sdkoo_%{$(PKGFORMAT:^".")} :
$(MAKE_INSTALLER_COMMAND) -p Apache_OpenOffice_SDK -msitemplate $(MSISDKOOTEMPLATEDIR) -dontstrip
-$(foreach,i,$(alllangiso) sdkoodev_$i) : $$@{$(PKGFORMAT:^".")}
sdkoodev_%{$(PKGFORMAT:^".")} :
$(MAKE_INSTALLER_COMMAND) -p Apache_OpenOffice_Dev_SDK -msitemplate $(MSISDKOOTEMPLATEDIR) -dontstrip
-.IF "$(MAKETARGETS)"!=""
-.IF "$(MAKETARGETS:e)"=="" && "$(MAKETARGETS:s/_//)"!="$(MAKETARGETS)"
-$(MAKETARGETS) : $$@{$(PKGFORMAT:^".")}
-$(MAKETARGETS){$(PKGFORMAT:^".")} : $(ADDDEPS)
-.ENDIF # "$(MAKETARGETS:e)"=="" && "$(MAKETARGETS:s/_//)"!="$(MAKETARGETS)"
-.ENDIF # "$(MAKETARGETS)"!=""
-
.ELSE # "$(alllangiso)"!=""
openoffice:
@echo cannot pack nothing...
.ENDIF # "$(alllangiso)"!=""
-.IF "$(LOCALPYFILES)"!=""
-$(foreach,i,$(alllangiso) openoffice_$i{$(PKGFORMAT:^".") .archive} openofficewithjre_$i{$(PKGFORMAT:^".")} openofficedev_$i{$(PKGFORMAT:^".")} sdkoo_$i{$(PKGFORMAT:^".")}) updatepack : $(LOCALPYFILES)
-.ENDIF # "$(LOCALPYFILES)"!=""
-
$(BIN)$/%.py : $(SOLARSHAREDBIN)$/pyuno$/%.py
- @$(COPY) $< $@
+ $(COPY) $< $@
-#$(BIN)$/intro.zip : $(SOLARCOMMONPCKDIR)$/openoffice_nologo$/intro.zip
$(BIN)$/intro.zip : $(SOLARCOMMONPCKDIR)$/intro.zip
$(COPY) $< $@
-#$(BIN)$/dev$/intro.zip : $(SOLARCOMMONPCKDIR)$/openoffice_dev_nologo$/intro.zip
$(BIN)$/dev$/intro.zip : $(SOLARCOMMONPCKDIR)$/openoffice_dev$/intro.zip
@-$(MKDIR) $(@:d)
$(COPY) $< $@
+
+.IF "$(OS)" == "WNT"
+patch_create .PHONY : $(PRJ)$/data
+ perl -I $(SOLARENV)$/bin/modules $(SOLARENV)$/bin$/patch_create.pl \
+ --product-name Apache_OpenOffice \
+ --output-path $(OUT) \
+ --data-path $(PRJ)$/data \
+ --lst-file $(PRJ)$/util$/openoffice.lst
+patch_apply .PHONY :
+ perl -I $(SOLARENV)$/bin/modules $(SOLARENV)$/bin$/patch_apply.pl \
+ ../wntmsci12.pro/Apache_OpenOffice/msp/v-4-0-1_v-4-1-0/en-US/openoffice.msp
+
+$(PRJ)$/data :
+ mkdir $@
+.ELSE
+patch .PHONY :
+ @echo "patches can only be created on Windows at the moment"
+.ENDIF
+
+
msitemplates .PHONY: msi_template_files msi_langpack_template_files msi_sdk_template_files
MSI_OFFICE_TEMPLATE_FILES= \
@@ -460,3 +482,8 @@ $(MSISDKOOTEMPLATEDIR) $(MSISDKOOTEMPLATEDIR)$/Binary :
-$(MKDIRHIER) $@
$(MSISDKOOTEMPLATEDIR)/% : $(MSISDKOOTEMPLATESOURCE)$/%
$(GNUCOPY) $< $@
+
+
+# Local Variables:
+# tab-width: 8
+# End:
diff --git a/solenv/bin/make_installer.pl b/solenv/bin/make_installer.pl
index 871e806..8aa7449 100644
--- a/solenv/bin/make_installer.pl
+++ b/solenv/bin/make_installer.pl
@@ -86,9 +86,11 @@ use installer::windows::upgrade;
use installer::worker;
use installer::xpdinstaller;
use installer::ziplist;
-
+use installer::patch::InstallationSet;
+use installer::patch::Msi;
use strict;
+
sub GetSetupScriptLines ($$$)
{
my ($allsettingsarrayref, $allvariableshashref, $includepatharrayref) = @_;
@@ -210,9 +212,6 @@ sub MakeWindowsBuild ($$$$$$$$$$$$$$$$$$$$)
my $newidtdir = $idtdirbase . $installer::globals::separator . "00"; # new files into language independent directory "00"
installer::systemactions::create_directory($newidtdir);
- my @allfilecomponents = ();
- my @allregistrycomponents = ();
-
# Collecting all files with flag "BINARYTABLE"
my $binarytablefiles = installer::worker::collect_all_items_with_special_flag($filesinproductlanguageresolvedarrayref ,"BINARYTABLE");
@@ -234,27 +233,81 @@ sub MakeWindowsBuild ($$$$$$$$$$$$$$$$$$$$)
# Collection all available directory trees
installer::windows::directory::collectdirectorytrees($directoriesforepmarrayref);
- $filesinproductlanguageresolvedarrayref = installer::windows::file::create_files_table(
+ $filesinproductlanguageresolvedarrayref = installer::windows::file::filter_files(
+ $filesinproductlanguageresolvedarrayref,
+ $allvariableshashref);
+ installer::windows::file::prepare_file_table_creation(
+ $filesinproductlanguageresolvedarrayref,
+ $directoriesforepmarrayref,
+ $allvariableshashref);
+ my $file_table_data = installer::windows::file::create_file_table_data(
$filesinproductlanguageresolvedarrayref,
- \@allfilecomponents,
- $newidtdir,
$allvariableshashref);
+ installer::windows::file::create_file_table($file_table_data, $newidtdir);
+ installer::windows::file::create_filehash_table($filesinproductlanguageresolvedarrayref, $newidtdir);
+ my @allfilecomponents = installer::windows::file::collect_components($filesinproductlanguageresolvedarrayref);
+
+ installer::windows::directory::prepare_directory_table_creation(
+ $directoriesforepmarrayref,
+ $allvariableshashref);
installer::windows::directory::create_directory_table(
$directoriesforepmarrayref,
$newidtdir,
- $allvariableshashref,
- $loggingdir);
+ $allvariableshashref);
# Attention: The table "Registry.idt" contains language specific strings -> parameter: $languagesarrayref !
- installer::windows::registry::create_registry_table($registryitemsinproductlanguageresolvedarrayref, \@allregistrycomponents, $newidtdir, $languagesarrayref, $allvariableshashref);
+ my $registry_table_data = installer::windows::registry::prepare_registry_table(
+ $registryitemsinproductlanguageresolvedarrayref,
+ $languagesarrayref,
+ $allvariableshashref);
+ my @allregistrycomponents = installer::windows::registry::collect_registry_components($registry_table_data);
+
+ my $target_registry_component_translation = installer::windows::component::prepare_component_table_creation(
+ \@allfilecomponents,
+ \@allregistrycomponents,
+ $allvariableshashref);
+
+ @allregistrycomponents = installer::windows::component::apply_component_translation(
+ $target_registry_component_translation,
+ @allregistrycomponents);
+ installer::windows::registry::translate_component_names(
+ $target_registry_component_translation,
+ $registryitemsinproductlanguageresolvedarrayref,
+ $registry_table_data);
+
+ installer::windows::registry::create_registry_table_32(
+ $newidtdir,
+ $languagesarrayref,
+ $allvariableshashref,
+ $registry_table_data);
+ installer::windows::registry::create_registry_table_64(
+ $newidtdir,
+ $languagesarrayref,
+ $allvariableshashref,
+ $registry_table_data);
- installer::windows::component::create_component_table($filesinproductlanguageresolvedarrayref, $registryitemsinproductlanguageresolvedarrayref, $directoriesforepmarrayref, \@allfilecomponents, \@allregistrycomponents, $newidtdir, $allvariableshashref);
+ my $component_table_data = installer::windows::component::create_component_table_data (
+ $filesinproductlanguageresolvedarrayref,
+ $registryitemsinproductlanguageresolvedarrayref,
+ $directoriesforepmarrayref,
+ \@allfilecomponents,
+ \@allregistrycomponents,
+ $allvariableshashref);
+ installer::windows::component::create_component_table(
+ $component_table_data,
+ $newidtdir);
# Attention: The table "Feature.idt" contains language specific strings -> parameter: $languagesarrayref !
installer::windows::feature::add_uniquekey($modulesinproductlanguageresolvedarrayref);
- $modulesinproductlanguageresolvedarrayref = installer::windows::feature::sort_feature($modulesinproductlanguageresolvedarrayref);
- installer::windows::feature::create_feature_table($modulesinproductlanguageresolvedarrayref, $newidtdir, $languagesarrayref, $allvariableshashref);
+ $modulesinproductlanguageresolvedarrayref = installer::windows::feature::sort_feature(
+ $modulesinproductlanguageresolvedarrayref);
+
+ installer::windows::feature::create_feature_table(
+ $modulesinproductlanguageresolvedarrayref,
+ $newidtdir,
+ $languagesarrayref,
+ $allvariableshashref);
installer::windows::featurecomponent::create_featurecomponent_table(
$filesinproductlanguageresolvedarrayref,
@@ -482,7 +535,11 @@ sub MakeWindowsBuild ($$$$$$$$$$$$$$$$$$$$)
$installer::logger::Info->print( "... creating msi database (language $onelanguage) ... \n" );
- installer::windows::msiglobal::set_uuid_into_component_table($languageidtdir, $allvariableshashref); # setting new GUID for the components using the tool uuidgen.exe
+ # setting new GUID for the components using the tool uuidgen.exe
+# installer::windows::msiglobal::set_uuid_into_component_table(
+# $languageidtdir,
+# $allvariableshashref);
+
installer::windows::msiglobal::prepare_64bit_database($languageidtdir, $allvariableshashref); # making last 64 bit changes
installer::windows::msiglobal::create_msi_database($languageidtdir ,$msifilename);
@@ -1302,6 +1359,38 @@ foreach my $key (sort keys %$allvariableshashref)
}
+# When we are building a release (-release option was given on the command line)
+# then we need additional information.
+if ($installer::globals::is_release)
+{
+ $installer::logger::Info->print("... building a release, checking required values ... \n");
+ $installer::globals::target_version = $allvariableshashref->{'PRODUCTVERSION'};
+ $installer::globals::source_version = $allvariableshashref->{'PREVIOUS_VERSION'};
+ if ( ! defined $installer::globals::source_version)
+ {
+ $installer::globals::source_version = installer::patch::ReleasesList::GetPreviousVersion(
+ $installer::globals::target_version);
+ }
+ if ( ! defined $installer::globals::source_version)
+ {
+ installer::exiter::exit_program(
+ "can not detect the previous version number. Please add a 'PREVIOUS_VERSION' variable to openoffice.lst",
+ "make_installer.pl");
+ }
+
+ # Determine if we are building a new major release, ie if target_version is ?.0.0
+ $installer::globals::is_major_release
+ = installer::patch::Version::IsMajorVersion($installer::globals::target_version);
+
+ $installer::logger::Info->printf(" building version %s\n", $installer::globals::target_version);
+ $installer::logger::Info->printf(" which is %sa major version\n",
+ $installer::globals::is_major_release
+ ? ""
+ : "not ");
+ $installer::logger::Info->printf(" previous version is %s\n", $installer::globals::source_version);
+}
+
+
########################################################
# Check if this is simple packaging mechanism
########################################################
@@ -1597,6 +1686,22 @@ for (;1;last)
else { $installer::globals::makedownload = 0; }
}
+ # Set up an MSI object for the source version.
+ if ($installer::globals::is_release
+ && $installer::globals::iswindowsbuild)
+ {
+ $installer::logger::Info->printf("preparing MSI object for source version %s\n",
+ $installer::globals::source_version);
+ my $source_version_string = join(
+ "",
+ installer::patch::Version::StringToNumberArray($installer::globals::source_version));
+ $installer::globals::source_msi = installer::patch::Msi->FindAndCreate(
+ $installer::globals::source_version,
+ 0,
+ $$languagestringref,
+ $installer::globals::product);
+ }
+
############################################################
# Beginning of language specific logging mechanism
# Until now only global logging into default: logfile.txt
diff --git a/solenv/bin/modules/installer/globals.pm b/solenv/bin/modules/installer/globals.pm
index 6d43e32..603991a 100644
--- a/solenv/bin/modules/installer/globals.pm
+++ b/solenv/bin/modules/installer/globals.pm
@@ -155,8 +155,8 @@ BEGIN
$fontsfolder = "FontsFolder";
$fontsfoldername = "Fonts";
$fontsdirparent = "";
- $fontsdirname = "";
$fontsdirhostname = "truetype";
+ $fontsdirname = $fontsdirhostname;
$officefolder = "OfficeFolder";
$officemenufolder = "OfficeMenuFolder";
$startupfolder = "StartupFolder";
@@ -535,6 +535,13 @@ BEGIN
# ToDo: Needs to be expanded for additional platforms
+ $is_release = 0; # Is changed in parameter.pm when the -release option is given.
+ $source_version = undef;
+ $target_version = undef;
+ $source_msi = undef;
+
+ # Is set to 1 when target_version is a major version, ie ?.0.0
+ $is_major_release = 0;
}
1;
diff --git a/solenv/bin/modules/installer/logger.pm b/solenv/bin/modules/installer/logger.pm
index 3cac508..652bc17 100644
--- a/solenv/bin/modules/installer/logger.pm
+++ b/solenv/bin/modules/installer/logger.pm
@@ -93,10 +93,11 @@ our $Info = installer::logger->new("info",
=head2 SetupSimpleLogging ($filename)
- Setup logging so that $Global, $Lang and $Info all print to the console AND to the log file.
+ Setup logging so that $Global, $Lang and $Info all print to the console.
+ If $filename is given then logging also goes to that file.
=cut
-sub SetupSimpleLogging ($)
+sub SetupSimpleLogging (;$)
{
my ($log_filename) = @_;
@@ -114,7 +115,10 @@ sub SetupSimpleLogging ($)
'is_show_relative_time' => 1,
'forward' => [$Info]
);
- $Info->set_filename($log_filename);
+ if (defined $log_filename)
+ {
+ $Info->set_filename($log_filename);
+ }
$Info->{'is_print_to_console'} = 1;
$installer::globals::quiet = 0;
starttime();
diff --git a/solenv/bin/modules/installer/parameter.pm b/solenv/bin/modules/installer/parameter.pm
index 1cb5ba9..478362e 100644
--- a/solenv/bin/modules/installer/parameter.pm
+++ b/solenv/bin/modules/installer/parameter.pm
@@ -164,6 +164,10 @@ sub getparameter
$path =~ s/^\Q$installer::globals::destdir\E//;
$installer::globals::rootpath = $path;
}
+ elsif ($param eq "-release")
+ {
+ $installer::globals::is_release = 1;
+ }
else
{
installer::logger::print_error( "unknown parameter: $param" );
diff --git a/solenv/bin/modules/installer/patch/FileSequenceList.pm b/solenv/bin/modules/installer/patch/FileSequenceList.pm
index 6c607d8..80d0583 100644
--- a/solenv/bin/modules/installer/patch/FileSequenceList.pm
+++ b/solenv/bin/modules/installer/patch/FileSequenceList.pm
@@ -21,7 +21,6 @@
package installer::patch::FileSequenceList;
-use XML::LibXML;
use strict;
=head1 NAME
@@ -50,22 +49,53 @@ sub new ($)
-sub SetFromFileList ($$)
+sub SetFromMap ($$)
{
- my ($self, $files) = @_;
+ my ($self, $map) = @_;
- my %data = map {$_->{'uniquename'} => $_->{'sequencenumber'}} @$files;
- $self->{'data'} = \%data;
+ $self->{'data'} = $map;
}
-sub SetFromMap ($$)
+sub SetFromMsi ($$)
{
- my ($self, $map) = @_;
+ my ($self, $msi) = @_;
- $self->{'data'} = $map;
+ my $file_table = $msi->GetTable("File");
+ my $file_map = $msi->GetFileMap();
+
+ my $file_column_index = $file_table->GetColumnIndex("File");
+ my $filename_column_index = $file_table->GetColumnIndex("FileName");
+ my $sequence_column_index = $file_table->GetColumnIndex("Sequence");
+
+ my %sequence_data = ();
+
+ printf("extracting columns %d and %d from %d rows\n",
+ $file_column_index,
+ $sequence_column_index,
+ $file_table->GetRowCount());
+
+ foreach my $row (@{$file_table->GetAllRows()})
+ {
+ my $unique_name = $row->GetValue($file_column_index);
+ my $filename = $row->GetValue($filename_column_index);
+ my ($long_filename,$short_filename) = installer::patch::Msi::SplitLongShortName($filename);
+ my $sequence = $row->GetValue($sequence_column_index);
+ my $directory_item = $file_map->{$unique_name}->{'directory'};
+ my $source_path = $directory_item->{'full_source_long_name'};
+ my $target_path = $directory_item->{'full_target_long_name'};
+ my $key = $source_path ne ""
+ ? $source_path."/".$long_filename
+ : $long_filename;
+ $sequence_data{$key} = {
+ 'sequence' => $sequence,
+ 'uniquename' => $unique_name,
+ 'row' => $row
+ };
+ }
+ $self->{'data'} = \%sequence_data;
}
@@ -81,78 +111,45 @@ sub GetFileCount ($)
-=head2 GetSequenceNumbers ($files)
-
- $files is a hash that maps unique file names (File->File) to sequence
- numbers (File->Sequence). The later is (expected to be) initially unset and
- is set in this method.
-
- For new files -- entries in the given $files that do not exist in the 'data'
- member -- no sequence numbers are defined.
-
- When there are removed files -- entries in the 'data' member that do not
- exist in the given $files -- then a list of these files is returned. In
- that case the given $files remain unmodified.
-
- The returned list is empty when everyting is OK.
-
-=cut
-sub GetSequenceNumbers ($$)
+sub get_removed_files ($@)
{
- my ($self, $files) = @_;
+ my ($self, $target_unique_names) = @_;
+
+ my %uniquename_to_row_map = map{$_->{'uniquename'} => $_->{'row'}} values %{$self->{'data'}};
# Check if files have been removed.
my @missing = ();
- foreach my $name (keys %{$self->{'data'}})
+ foreach my $item (values %{$self->{'data'}})
{
- if ( ! defined $files->{$name})
+ my ($uniquename, $row) = ($item->{'uniquename'}, $item->{'row'});
+ if ( ! defined $target_unique_names->{$uniquename})
{
- push @missing, $name;
+ # $name is defined in source but not in target => it has been removed.
+ push @missing, $row;
}
}
- if (scalar @missing > 0)
- {
- # Yes. Return the names of the removed files.
- return @missing;
- }
-
- # No files where removed. Set the sequence numbers.
- foreach my $name (keys %$files)
- {
- $files->{$name} = $self->{'data'}->{$name};
- }
- return ();
+ return @missing;
}
-sub GetDifference ($$)
+sub get_sequence_and_unique_name($$)
{
- my ($self, $other) = @_;
+ my ($self, $source_path) = @_;
- # Create maps for easy reference.
- my (@files_in_both, @files_in_self, @files_in_other);
- foreach my $name (keys %{$self->{'data'}})
+ my $sequence_and_unique_name = $self->{'data'}->{$source_path};
+ if ( ! defined $sequence_and_unique_name)
{
- if (defined $other->{'data'}->{$name})
- {
- push @files_in_both, $name;
- }
- else
- {
- push @files_in_self, $name;
- }
+ $installer::logger::Lang->printf("can not find entry for source path '%s'\n", $source_path);
+ return (undef,undef);
}
- foreach my $name (keys %{$self->{'data'}})
+ else
{
- if ( ! defined $self->{'data'}->{$name})
- {
- push @files_in_other, $name;
- }
+ return (
+ $sequence_and_unique_name->{'sequence'},
+ $sequence_and_unique_name->{'uniquename'});
}
-
- return (\@files_in_both, \@files_in_self, \@files_in_other);
}
diff --git a/solenv/bin/modules/installer/patch/InstallationSet.pm b/solenv/bin/modules/installer/patch/InstallationSet.pm
index 67ff1fe..7d6647d 100644
--- a/solenv/bin/modules/installer/patch/InstallationSet.pm
+++ b/solenv/bin/modules/installer/patch/InstallationSet.pm
@@ -25,9 +25,25 @@ use installer::patch::Tools;
use installer::patch::Version;
use installer::logger;
+use strict;
+# TODO: Detect the location of 7z.exe
my $Unpacker = "/c/Program\\ Files/7-Zip/7z.exe";
+
+
+# TODO: Is there a touch in a standard library?
+sub touch ($)
+{
+ my ($filename) = @_;
+
+ open my $out, ">", $filename;
+ close $out;
+}
+
+
+
+
=head1 NAME
package installer::patch::InstallationSet - Functions for handling installation sets
@@ -48,29 +64,25 @@ sub UnpackExe ($$)
# Unpack to a temporary path and change its name to the destination path
# only when the unpacking has completed successfully.
- my $temporary_destination_path = $destination_path . ".tmp";
- File::Path::make_path($temporary_destination_path);
+ File::Path::make_path($destination_path);
- my $windows_filename = installer::patch::Tools::CygpathToWindows($filename);
- my $windows_destination_path = installer::patch::Tools::CygpathToWindows($temporary_destination_path);
+ my $windows_filename = installer::patch::Tools::ToEscapedWindowsPath($filename);
+ my $windows_destination_path = installer::patch::Tools::ToEscapedWindowsPath($destination_path);
my $command = join(" ",
$Unpacker,
- "x", "-o".$windows_destination_path,
+ "x",
+ "-y",
+ "-o".$windows_destination_path,
$windows_filename);
my $result = qx($command);
# Check the existence of the .cab files.
- my $cab_filename = File::Spec->catfile($temporary_destination_path, "openoffice1.cab");
+ my $cab_filename = File::Spec->catfile($destination_path, "openoffice1.cab");
if ( ! -f $cab_filename)
{
installer::logger::PrintError("cab file '%s' was not extracted from installation set\n", $cab_filename);
return 0;
}
- if (rename($temporary_destination_path, $destination_path) == 0)
- {
- installer::logger::PrintError("can not rename temporary extraction directory\n");
- return 0;
- }
return 1;
}
@@ -99,7 +111,7 @@ sub UnpackCab ($$$)
# Extract the directory structure from the 'File' and 'Directory' tables in the given msi.
$installer::logger::Info->printf("setting up directory tree\n");
my $file_table = $msi->GetTable("File");
- my $file_to_directory_map = $msi->GetFileToDirectoryMap();
+ my $file_map = $msi->GetFileMap();
# Step 2
# Unpack the .cab file to a temporary path.
@@ -122,19 +134,17 @@ sub UnpackCab ($$$)
foreach my $file_row (@{$file_table->GetAllRows()})
{
my $unique_name = $file_row->GetValue('File');
- my $directory_full_names = $file_to_directory_map->{$unique_name};
- my ($source_full_name, $target_full_name) = @$directory_full_names;
+ my $directory_item = $file_map->{$unique_name}->{'directory'};
+ my $source_full_name = $directory_item->{'full_source_long_name'};
my $flat_filename = File::Spec->catfile($temporary_destination_path, $unique_name);
my $dir_path = File::Spec->catfile($destination_path, $source_full_name);
my $dir_filename = File::Spec->catfile($dir_path, $unique_name);
- printf("%d: making path %s and copying %s to %s\n",
- $count,
- $dir_path,
- $unique_name,
- $dir_filename);
- File::Path::make_path($dir_path);
+ if ( ! -d $dir_path)
+ {
+ File::Path::make_path($dir_path);
+ }
File::Copy::move($flat_filename, $dir_filename);
++$count;
@@ -166,16 +176,14 @@ sub UnpackCabFlat ($$$)
# when another step fails.
$installer::logger::Info->printf("unpacking cab file\n");
- my $temporary_destination_path = $destination_path . ".tmp";
- File::Path::make_path($temporary_destination_path);
- my $windows_cab_filename = installer::patch::Tools::CygpathToWindows($cab_filename);
- my $windows_destination_path = installer::patch::Tools::CygpathToWindows($temporary_destination_path);
+ File::Path::make_path($destination_path);
+ my $windows_cab_filename = installer::patch::Tools::ToEscapedWindowsPath($cab_filename);
+ my $windows_destination_path = installer::patch::Tools::ToEscapedWindowsPath($destination_path);
my $command = join(" ",
$Unpacker,
"x", "-o".$windows_destination_path,
$windows_cab_filename,
"-y");
- printf("running command '%s'\n", $command);
open my $cmd, $command."|";
my $extraction_count = 0;
my $file_count = $file_table->GetRowCount();
@@ -190,61 +198,52 @@ sub UnpackCabFlat ($$$)
$extraction_count*100/$file_count);
}
close $cmd;
- printf("extraction done \n");
-
- rename($temporary_destination_path, $destination_path)
- || installer::logger::PrintError(
- "can not rename the temporary directory '%s' to '%s'\n",
- $temporary_destination_path,
- $destination_path);
}
-=head GetUnpackedMsiPath ($version, $language, $package_format, $product)
+=head GetUnpackedExePath ($version, $is_current_version, $language, $package_format, $product)
Convenience function that returns where a downloadable installation set is extracted to.
=cut
-sub GetUnpackedMsiPath ($$$$)
+sub GetUnpackedExePath ($$$$$)
{
- my ($version, $language, $package_format, $product) = @_;
+ my ($version, $is_current_version, $language, $package_format, $product) = @_;
- return File::Spec->catfile(
- GetUnpackedPath($version, $language, $package_format, $product),
- "unpacked_msi");
+ my $path = GetUnpackedPath($version, $is_current_version, $language, $package_format, $product);
+ return File::Spec->catfile($path, "unpacked");
}
-=head GetUnpackedCabPath ($version, $language, $package_format, $product)
+=head GetUnpackedCabPath ($version, $is_current_version, $language, $package_format, $product)
Convenience function that returns where a cab file is extracted
(with injected directory structure from the msi file) to.
=cut
-sub GetUnpackedCabPath ($$$$)
+sub GetUnpackedCabPath ($$$$$)
{
- my ($version, $language, $package_format, $product) = @_;
+ my ($version, $is_current_version, $language, $package_format, $product) = @_;
- return File::Spec->catfile(
- GetUnpackedPath($version, $language, $package_format, $product),
- "unpacked_cab");
+ my $path = GetUnpackedPath($version, $is_current_version, $language, $package_format, $product);
+ return File::Spec->catfile($path, "unpacked");
}
-=head2 GetUnpackedPath($version, $language, $package_format, $product)
+=head2 GetUnpackedPath($version, $is_current_version, $language, $package_format, $product)
Internal function for creating paths to where archives are unpacked.
=cut
-sub GetUnpackedPath ($$$$)
+sub GetUnpackedPath ($$$$$)
{
- my ($version, $language, $package_format, $product) = @_;
+ my ($version, $is_current_version, $language, $package_format, $product) = @_;
return File::Spec->catfile(
$ENV{'SRC_ROOT'},
@@ -252,13 +251,41 @@ sub GetUnpackedPath ($$$$)
$ENV{'INPATH'},
$product,
$package_format,
- installer::patch::Version::ArrayToDirectoryName(installer::patch::Version::StringToNumberArray($version)),
+ installer::patch::Version::ArrayToDirectoryName(
+ installer::patch::Version::StringToNumberArray($version)),
$language);
}
+sub GetMsiFilename ($$)
+{
+ my ($path, $version) = @_;
+
+ my $no_dot_version = installer::patch::Version::ArrayToNoDotName(
+ installer::patch::Version::StringToNumberArray(
+ $version));
+ return File::Spec->catfile(
+ $path,
+ "openoffice" . $no_dot_version . ".msi");
+}
+
+
+
+
+sub GetCabFilename ($$)
+{
+ my ($path, $version) = @_;
+
+ return File::Spec->catfile(
+ $path,
+ "openoffice1.cab");
+}
+
+
+
+
=head2 Download($language, $release_data, $filename)
Download an installation set to $filename. The URL for the
@@ -464,4 +491,282 @@ sub ProvideDownloadSet ($$$)
return $ext_sources_filename;
}
+
+
+
+sub ProvideUnpackedExe ($$$$$)
+{
+ my ($version, $is_current_version, $language, $package_format, $product_name) = @_;
+
+ # Check if the exe has already been unpacked.
+ my $unpacked_exe_path = installer::patch::InstallationSet::GetUnpackedExePath(
+ $version,
+ $is_current_version,
+ $language,
+ $package_format,
+ $product_name);
+ my $unpacked_exe_flag_filename = File::Spec->catfile($unpacked_exe_path, "__exe_is_unpacked");
+ my $exe_is_unpacked = -f $unpacked_exe_flag_filename;
+
+ if ($exe_is_unpacked)
+ {
+ # Yes, exe has already been unpacked. There is nothing more to do.
+ $installer::logger::Info->printf("downloadable installation set has already been unpacked to\n");
+ $installer::logger::Info->printf(" %s\n", $unpacked_exe_path);
+ return 1;
+ }
+ elsif ($is_current_version)
+ {
+ # For the current version the exe is created from the unpacked
+ # content and both are expected to be already present.
+
+ # In order to have the .cab and its unpacked content in one
+ # directory and don't interfere with the creation of regular
+ # installation sets, we copy the unpacked .exe into a separate
+ # directory.
+
+ my $original_path = File::Spec->catfile(
+ $ENV{'SRC_ROOT'},
+ "instsetoo_native",
+ $ENV{'INPATH'},
+ $product_name,
+ $package_format,
+ "install",
+ $language);
+ $installer::logger::Info->printf("creating a copy\n");
+ $installer::logger::Info->printf(" of %s\n", $original_path);
+ $installer::logger::Info->printf(" at %s\n", $unpacked_exe_path);
+ File::Path::make_path($unpacked_exe_path) unless -d $unpacked_exe_path;
+ my ($file_count,$directory_count) = CopyRecursive($original_path, $unpacked_exe_path);
+ return 0 if ( ! defined $file_count);
+ $installer::logger::Info->printf(" copied %d files in %d directories\n",
+ $file_count,
+ $directory_count);
+
+ touch($unpacked_exe_flag_filename);
+
+ return 1;
+ }
+ else
+ {
+ # No, we have to unpack the exe.
+
+ # Provide the exe.
+ my $filename = installer::patch::InstallationSet::ProvideDownloadSet(
+ $version,
+ $language,
+ $package_format);
+
+ # Unpack it.
+ if (defined $filename)
+ {
+ if (installer::patch::InstallationSet::UnpackExe($filename, $unpacked_exe_path))
+ {
+ $installer::logger::Info->printf("downloadable installation set has been unpacked to\n");
+ $installer::logger::Info->printf(" %s\n", $unpacked_exe_path);
+
+ touch($unpacked_exe_flag_filename);
+
+ return 1;
+ }
+ }
+ else
+ {
+ installer::logger::PrintError("could not provide .exe installation set at '%s'\n", $filename);
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+sub CopyRecursive ($$)
+{
+ my ($source_path, $destination_path) = @_;
+
+ return (undef,undef) unless -d $source_path;
+
+ my @todo = ([$source_path, $destination_path]);
+ my $file_count = 0;
+ my $directory_count = 0;
+ while (scalar @todo > 0)
+ {
+ my ($source,$destination) = @{shift @todo};
+
+ next if ! -d $source;
+ File::Path::make_path($destination);
+ ++$directory_count;
+
+ # Read list of files in the current source directory.
+ opendir( my $dir, $source);
+ my @files = readdir $dir;
+ closedir $dir;
+
+ # Copy all files and push all directories to @todo.
+ foreach my $file (@files)
+ {
+ next if $file =~ /^\.+$/;
+
+ my $source_file = File::Spec->catfile($source, $file);
+ my $destination_file = File::Spec->catfile($destination, $file);
+ if ( -f $source_file)
+ {
+ File::Copy::copy($source_file, $destination_file);
+ ++$file_count;
+ }
+ elsif ( -d $source_file)
+ {
+ push @todo, [$source_file, $destination_file];
+ }
+ }
+ }
+
+ return ($file_count, $directory_count);
+}
+
+
+
+
+sub CheckLocalCopy ($$$$)
+{
+ my ($version, $language, $package_format, $product_name) = @_;
+
+ # Compare creation times of the original .msi and its copy.
+
+ my $original_path = File::Spec->catfile(
+ $ENV{'SRC_ROOT'},
+ "instsetoo_native",
+ $ENV{'INPATH'},
+ $product_name,
+ $package_format,
+ "install",
+ $language);
+
+ my $copy_path = installer::patch::InstallationSet::GetUnpackedExePath(
+ $version,
+ 1,
+ $language,
+ $package_format,
+ $product_name);
+
+ my $msi_basename = "openoffice"
+ . installer::patch::Version::ArrayToNoDotName(
+ installer::patch::Version::StringToNumberArray($version))
+ . ".msi";
+
+ my $original_msi_filename = File::Spec->catfile($original_path, $msi_basename);
+ my $copied_msi_filename = File::Spec->catfile($copy_path, $msi_basename);
+
+ my @original_msi_stats = stat($original_msi_filename);
+ my @copied_msi_stats = stat($copied_msi_filename);
+ my $original_msi_mtime = $original_msi_stats[9];
+ my $copied_msi_mtime = $copied_msi_stats[9];
+
+ if (defined $original_msi_mtime
+ && defined $copied_msi_mtime
+ && $original_msi_mtime > $copied_msi_mtime)
+ {
+ # The installation set is newer than its copy.
+ # Remove the copy.
+ $installer::logger::Info->printf(
+ "removing copy of installation set (version %s) because it is out of date\n",
+ $version);
+ File::Path::remove_tree($copy_path);
+ }
+}
+
+
+
+
+=head2 ProvideUnpackedCab
+
+ 1a. Make sure that a downloadable installation set is present.
+ 1b. or that a freshly built installation set (packed and unpacked is present)
+ 2. Unpack the downloadable installation set
+ 3. Unpack the .cab file.
+
+ The 'Provide' in the function name means that any step that has
+ already been made is not made again.
+
+=cut
+sub ProvideUnpackedCab ($$$$$)
+{
+ my ($version, $is_current_version, $language, $package_format, $product_name) = @_;
+
+ if ($is_current_version)
+ {
+ # For creating patches we maintain a copy of the unpacked .exe. Make sure that that is updated when
+ # a new installation set has been built.
+ CheckLocalCopy($version, $language, $package_format, $product_name);
+ }
+
+ # Check if the cab file has already been unpacked.
+ my $unpacked_cab_path = installer::patch::InstallationSet::GetUnpackedCabPath(
+ $version,
+ $is_current_version,
+ $language,
+ $package_format,
+ $product_name);
+ my $unpacked_cab_flag_filename = File::Spec->catfile($unpacked_cab_path, "__cab_is_unpacked");
+ my $cab_is_unpacked = -f $unpacked_cab_flag_filename;
+
+ if ($cab_is_unpacked)
+ {
+ # Yes. Cab was already unpacked. There is nothing more to do.
+ $installer::logger::Info->printf("cab has already been unpacked to\n");
+ $installer::logger::Info->printf(" %s\n", $unpacked_cab_path);
+
+ return 1;
+ }
+ else
+ {
+ # Make sure that the exe is unpacked and the cab file exists.
+ ProvideUnpackedExe($version, $is_current_version, $language, $package_format, $product_name);
+
+ # Unpack the cab file.
+ my $unpacked_exe_path = installer::patch::InstallationSet::GetUnpackedExePath(
+ $version,
+ $is_current_version,
+ $language,
+ $package_format,
+ $product_name);
+ my $msi = new installer::patch::Msi(
+ installer::patch::InstallationSet::GetMsiFilename($unpacked_exe_path, $version),
+ $version,
+ $is_current_version,
+ $language,
+ $product_name);
+
+ my $cab_filename = installer::patch::InstallationSet::GetCabFilename(
+ $unpacked_exe_path,
+ $version);
+ if ( ! -f $cab_filename)
+ {
+ # Cab file does not exist.
+ installer::logger::PrintError(
+ "could not find .cab file at '%s'. Extraction of .exe seems to have failed.\n",
+ $cab_filename);
+ return 0;
+ }
+
+ if (installer::patch::InstallationSet::UnpackCab(
+ $cab_filename,
+ $msi,
+ $unpacked_cab_path))
+ {
+ $installer::logger::Info->printf("unpacked cab file '%s'\n", $cab_filename);
+ $installer::logger::Info->printf(" to '%s'\n", $unpacked_cab_path);
+
+ touch($unpacked_cab_flag_filename);
+
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
1;
diff --git a/solenv/bin/modules/installer/patch/Msi.pm b/solenv/bin/modules/installer/patch/Msi.pm
index c5c650a..5cefda8 100644
--- a/solenv/bin/modules/installer/patch/Msi.pm
+++ b/solenv/bin/modules/installer/patch/Msi.pm
@@ -23,6 +23,11 @@ package installer::patch::Msi;
use installer::patch::MsiTable;
use installer::patch::Tools;
+use installer::patch::InstallationSet;
+
+use File::Basename;
+use File::Copy;
+
use strict;
@@ -32,9 +37,37 @@ use strict;
=cut
+sub FindAndCreate($$$$$)
+{
+ my ($class, $version, $is_current_version, $language, $product_name) = @_;
+
+ my $condensed_version = $version;
+ $condensed_version =~ s/\.//g;
+
+ # When $version is the current version we have to search the msi at a different place.
+ my $path;
+ my $filename;
+ my $is_current = 0;
+ $path = installer::patch::InstallationSet::GetUnpackedExePath(
+ $version,
+ $is_current_version,
+ $language,
+ "msi",
+ $product_name);
+
+ # Find the msi in the path.ls .
+ $filename = File::Spec->catfile($path, "openoffice".$condensed_version.".msi");
+ $is_current = $is_current_version;
+
+ return $class->new($filename, $version, $is_current, $language, $product_name);
+}
+
+
-=head2 new($class, $version, $language, $product_name)
+
+
+=head2 new($class, $filename, $version, $is_current_version, $language, $product_name)
Create a new object of the Msi class. The values of $version, $language, and $product_name define
where to look for the msi file.
@@ -42,47 +75,24 @@ use strict;
If construction fails then IsValid() will return false.
=cut
-sub new ($$$$)
+sub new ($$$$$$)
{
- my ($class, $version, $language, $product_name) = @_;
-
- my $path = installer::patch::InstallationSet::GetUnpackedMsiPath(
- $version,
- $language,
- "msi",
- $product_name);
-
- # Find the msi in the path.
- my $filename = undef;
- if ( -d $path)
- {
- my @msi_files = glob(File::Spec->catfile($path, "*.msi"));
- if (scalar @msi_files != 1)
- {
- printf STDERR ("there are %d msi files in %s, should be 1", scalar @msi_files, $filename);
- $filename = "";
- }
- else
- {
- $filename = $msi_files[0];
- }
- }
- else
- {
- installer::logger::PrintError("can not access path '%s' to find msi\n", $path);
- return undef;
- }
+ my ($class, $filename, $version, $is_current_version, $language, $product_name) = @_;
if ( ! -f $filename)
{
- installer::logger::PrintError("can not access MSI file at '%s'\n", $filename);
+ installer::logger::PrintError("can not find the .msi file for version %s and language %s at '%s'\n",
+ $version,
+ $language,
+ $filename);
return undef;
}
my $self = {
'filename' => $filename,
- 'path' => $path,
+ 'path' => dirname($filename),
'version' => $version,
+ 'is_current_version' => $is_current_version,
'language' => $language,
'package_format' => "msi",
'product_name' => $product_name,
@@ -107,6 +117,41 @@ sub IsValid ($)
+=head2 Commit($self)
+
+ Write all modified tables back into the databse.
+
+=cut
+sub Commit ($)
+{
+ my $self = shift;
+
+ my @tables_to_update = ();
+ foreach my $table (values %{$self->{'tables'}})
+ {
+ push @tables_to_update,$table if ($table->IsModified());
+ }
+
+ if (scalar @tables_to_update > 0)
+ {
+ $installer::logger::Info->printf("writing modified tables to database:\n");
+ foreach my $table (@tables_to_update)
+ {
+ $installer::logger::Info->printf(" %s\n", $table->GetName());
+ $self->PutTable($table);
+ }
+
+ foreach my $table (@tables_to_update)
+ {
+ $table->UpdateTimestamp();
+ $table->MarkAsUnmodified();
+ }
+ }
+}
+
+
+
+
=head2 GetTable($seld, $table_name)
Return an MsiTable object for $table_name. Table objects are kept
@@ -129,8 +174,8 @@ sub GetTable ($$)
my $truncated_table_name = length($table_name)>8 ? substr($table_name,0,8) : $table_name;
my $command = join(" ",
"msidb.exe",
- "-d", installer::patch::Tools::CygpathToWindows($self->{'filename'}),
- "-f", installer::patch::Tools::CygpathToWindows($self->{'tmpdir'}),
+ "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}),
+ "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}),
"-e", $table_name);
my $result = qx($command);
print $result;
@@ -147,6 +192,51 @@ sub GetTable ($$)
+=head2 PutTable($self, $table)
+
+ Write the given table back to the databse.
+
+=cut
+sub PutTable ($$)
+{
+ my ($self, $table) = @_;
+
+ # Create text file from the current table content.
+ $table->WriteFile();
+
+ my $table_name = $table->GetName();
+
+ # Store table from text file into database.
+ my $table_filename = $table->{'filename'};
+
+ if (length($table_name) > 8)
+ {
+ # The file name of the table data must not be longer than 8 characters (not counting the extension).
+ # The name passed as argument to the -i option may be longer.
+ my $truncated_table_name = substr($table_name,0,8);
+ my $table_truncated_filename = File::Spec->catfile(
+ dirname($table_filename),
+ $truncated_table_name.".idt");
+ File::Copy::copy($table_filename, $table_truncated_filename) || die("can not create table file with short name");
+ }
+
+ my $command = join(" ",
+ "msidb.exe",
+ "-d", installer::patch::Tools::ToEscapedWindowsPath($self->{'filename'}),
+ "-f", installer::patch::Tools::ToEscapedWindowsPath($self->{'tmpdir'}),
+ "-i", $table_name);
+ my $result = system($command);
+
+ if ($result != 0)
+ {
+ installer::logger::PrintError("writing table '%s' back to database failed", $table_name);
+ # For error messages see http://msdn.microsoft.com/en-us/library/windows/desktop/aa372835%28v=vs.85%29.aspx
+ }
+}
+
+
+
+
=head2 EnsureAYoungerThanB ($filename_a, $filename_b)
Internal function (not a method) that compares to files according
@@ -226,52 +316,44 @@ sub SplitTargetSourceLongShortName ($)
}
+=head2 GetDirectoryMap($self)
-
-=head2 GetFileToDirectoryMap ($)
-
- Return a map (hash) that maps the unique name (column 'File' in
- the 'File' table) to its directory names. Each value is a
- reference to an array of two elements: the source path and the
- target path.
-
- The map is kept alive for the lifetime of the Msi object. All
- calls but the first are cheap.
+ Return a map that maps directory unique names (column 'Directory' in table 'Directory')
+ to hashes that contains short and long source and target names.
=cut
-sub GetFileToDirectoryMap ($)
+sub GetDirectoryMap ($)
{
my ($self) = @_;
- if (defined $self->{'FileToDirectoryMap'})
+ if (defined $self->{'DirectoryMap'})
{
- return $self->{'FileToDirectoryMap'};
+ return $self->{'DirectoryMap'};
}
- my $file_table = $self->GetTable("File");
my $directory_table = $self->GetTable("Directory");
- my $component_table = $self->GetTable("Component");
- $installer::logger::Info->printf("got access to tables File, Directory, Component\n");
-
my %dir_map = ();
foreach my $row (@{$directory_table->GetAllRows()})
{
- my ($target_name, undef, $source_name, undef)
+ my ($target_long_name, $target_short_name, $source_long_name, $source_short_name)
= installer::patch::Msi::SplitTargetSourceLongShortName($row->GetValue("DefaultDir"));
- $dir_map{$row->GetValue("Directory")} = {
+ my $unique_name = $row->GetValue("Directory");
+ $dir_map{$unique_name} =
+ {
+ 'unique_name' => $unique_name,
'parent' => $row->GetValue("Directory_Parent"),
- 'source_name' => $source_name,
- 'target_name' => $target_name};
+ 'default_dir' => $row->GetValue("DefaultDir"),
+ 'source_long_name' => $source_long_name,
+ 'source_short_name' => $source_short_name,
+ 'target_long_name' => $target_long_name,
+ 'target_short_name' => $target_short_name
+ };
}
# Set up full names for all directories.
my @todo = map {$_} (keys %dir_map);
- my $process_count = 0;
- my $push_count = 0;
while (scalar @todo > 0)
{
- ++$process_count;
-
my $key = shift @todo;
my $item = $dir_map{$key};
next if defined $item->{'full_source_name'};
@@ -279,17 +361,25 @@ sub GetFileToDirectoryMap ($)
if ($item->{'parent'} eq "")
{
# Directory has no parent => full names are the same as the name.
- $item->{'full_source_name'} = $item->{'source_name'};
- $item->{'full_target_name'} = $item->{'target_name'};
+ $item->{'full_source_long_name'} = $item->{'source_long_name'};
+ $item->{'full_source_short_name'} = $item->{'source_short_name'};
+ $item->{'full_target_long_name'} = $item->{'target_long_name'};
+ $item->{'full_target_short_name'} = $item->{'target_short_name'};
}
else
{
my $parent = $dir_map{$item->{'parent'}};
- if ( defined $parent->{'full_source_name'})
+ if ( defined $parent->{'full_source_long_name'})
{
# Parent aleady has full names => we can create the full name of the current item.
- $item->{'full_source_name'} = $parent->{'full_source_name'} . "/" . $item->{'source_name'};
- $item->{'full_target_name'} = $parent->{'full_target_name'} . "/" . $item->{'target_name'};
+ $item->{'full_source_long_name'}
+ = $parent->{'full_source_long_name'} . "/" . $item->{'source_long_name'};
+ $item->{'full_source_short_name'}
+ = $parent->{'full_source_short_name'} . "/" . $item->{'source_short_name'};
+ $item->{'full_target_long_name'}
+ = $parent->{'full_target_long_name'} . "/" . $item->{'target_long_name'};
+ $item->{'full_target_short_name'}
+ = $parent->{'full_target_short_name'} . "/" . $item->{'target_short_name'};
}
else
{
@@ -297,45 +387,78 @@ sub GetFileToDirectoryMap ($)
# Push both to the head of the list.
unshift @todo, $key;
unshift @todo, $item->{'parent'};
-
- ++$push_count;
}
}
}
- foreach my $key (keys %dir_map)
+ # Postprocess the path names for cleanup.
+ foreach my $item (values %dir_map)
{
- $dir_map{$key}->{'full_source_name'} =~ s/\/(\.\/)+/\//g;
- $dir_map{$key}->{'full_source_name'} =~ s/^SourceDir\///;
- $dir_map{$key}->{'full_target_name'} =~ s/\/(\.\/)+/\//g;
- $dir_map{$key}->{'full_target_name'} =~ s/^SourceDir\///;
+ foreach my $id (
+ 'full_source_long_name',
+ 'full_source_short_name',
+ 'full_target_long_name',
+ 'full_target_short_name')
+ {
+ $item->{$id} =~ s/\/(\.\/)+/\//g;
+ $item->{$id} =~ s/^SourceDir\///;
+ $item->{$id} =~ s/^\.$//;
+ }
}
- $installer::logger::Info->printf("for %d directories there where %d processing steps and %d pushes\n",
- $directory_table->GetRowCount(),
- $process_count,
- $push_count);
+
+ $self->{'DirectoryMap'} = \%dir_map;
+ return $self->{'DirectoryMap'};
+}
+
+
+
+
+=head2 GetFileMap ($)
+
+ Return a map (hash) that maps the unique name (column 'File' in
+ the 'File' table) to data that is associated with that file, like
+ the directory or component.
+
+ The map is kept alive for the lifetime of the Msi object. All
+ calls but the first are cheap.
+
+=cut
+sub GetFileMap ($)
+{
+ my ($self) = @_;
+
+ if (defined $self->{'FileMap'})
+ {
+ return $self->{'FileMap'};
+ }
+
+ my $file_table = $self->GetTable("File");
+ my $component_table = $self->GetTable("Component");
+ my $dir_map = $self->GetDirectoryMap();
# Setup a map from component names to directory items.
- my %component_to_directory_map = map {$_->GetValue('Component') => $_->GetValue('Directory_')} @{$component_table->GetAllRows()};
+ my %component_to_directory_map =
+ map
+ {$_->GetValue('Component') => $_->GetValue('Directory_')}
+ @{$component_table->GetAllRows()};
# Finally, create the map from files to directories.
- my $map = {};
+ my $file_map = {};
my $file_component_index = $file_table->GetColumnIndex("Component_");
my $file_file_index = $file_table->GetColumnIndex("File");
foreach my $file_row (@{$file_table->GetAllRows()})
{
my $component_name = $file_row->GetValue($file_component_index);
my $directory_name = $component_to_directory_map{$component_name};
- my $dir_item = $dir_map{$directory_name};
my $unique_name = $file_row->GetValue($file_file_index);
- $map->{$unique_name} = [$dir_item->{'full_source_name'},$dir_item->{'full_target_name'}];
+ $file_map->{$unique_name} = {
+ 'directory' => $dir_map->{$directory_name},
+ 'component_name' => $component_name
+ };
}
- $installer::logger::Info->printf("got full paths for %d files\n",
- $file_table->GetRowCount());
-
- $self->{'FileToDirectoryMap'} = $map;
- return $map;
+ $self->{'FileMap'} = $file_map;
+ return $file_map;
}
diff --git a/solenv/bin/modules/installer/patch/MsiRow.pm b/solenv/bin/modules/installer/patch/MsiRow.pm
index 24a6fd2..ca414c6 100644
--- a/solenv/bin/modules/installer/patch/MsiRow.pm
+++ b/solenv/bin/modules/installer/patch/MsiRow.pm
@@ -99,6 +99,15 @@ sub SetValue ($$$)
+sub GetAllValues ($)
+{
+ my ($self) = @_;
+ return @{$self->{'values'}};
+}
+
+
+
+
sub Format ($$)
{
my $self = shift;
diff --git a/solenv/bin/modules/installer/patch/MsiTable.pm b/solenv/bin/modules/installer/patch/MsiTable.pm
index a95b94a..0ff557c 100644
--- a/solenv/bin/modules/installer/patch/MsiTable.pm
+++ b/solenv/bin/modules/installer/patch/MsiTable.pm
@@ -44,11 +44,16 @@ sub new ($$$)
my $self = {
'name' => $table_name,
- 'is_valid' => 1
+ 'filename' => $filename,
+ 'columns' => undef,
+ 'column_specs' => undef,
+ 'codepage' => undef,
+ 'is_valid' => 1,
+ 'is_modified' => 0
};
bless($self, $class);
- if ( -f $filename)
+ if (defined $filename && -f $filename)
{
$self->ReadFile($filename);
}
@@ -58,6 +63,51 @@ sub new ($$$)
+sub SetColumnData ($@)
+{
+ my ($self, @data) = @_;
+
+ if (((scalar @data) % 2) != 0)
+ {
+ installer::logger::PrintError("column data has to have an even number of elements: (<column-name> <data-spec>)+)\n");
+ $self->{'is_valid'} = 0;
+ return;
+ }
+
+ $self->{'columns'} = [];
+ $self->{'column_specs'} = [];
+ while (scalar @data > 0)
+ {
+ my $name = shift @data;
+ my $spec = shift @data;
+ push @{$self->{'columns'}}, $name;
+ push @{$self->{'column_specs'}}, $spec;
+ }
+}
+
+
+
+
+sub SetIndexColumns ($@)
+{
+ my ($self, @index_columns) = @_;
+
+ $self->{'index_columns'} = [@index_columns];
+}
+
+
+
+
+sub SetCodepage ($$)
+{
+ my ($self, $codepage) = @_;
+
+ $self->{'codepage'} = $codepage;
+}
+
+
+
+
sub IsValid ($)
{
my ($self) = @_;
@@ -106,17 +156,22 @@ sub ReadFile ($$)
# Table name, index columns.
my $line = Trim(<$in>);
my @items = split(/\t/, $line);
- if (scalar @items == 3)
+ my $item_count = scalar @items;
+ if ($item_count>=1 && $items[0] eq $self->{'name'})
+ {
+ # No codepage.
+ }
+ elsif ($item_count>=2 && $items[1] eq $self->{'name'})
{
$self->{'codepage'} = shift @items;
}
- my $table_name = shift @items;
- if ($table_name ne $self->{'name'})
+ else
{
- printf STDERR ("reading wrong table data for table '%s' (got %s)\n", $self->{'name'}, $table_name);
+ printf STDERR ("reading wrong table data for table '%s' (got %s)\n", $self->{'name'}, $items[0]);
$self->{'is_valid'} = 0;
return;
}
+ shift @items;
$self->{'index_columns'} = [@items];
$self->{'index_column_index'} = $self->GetColumnIndex($items[0]);
@@ -136,6 +191,58 @@ sub ReadFile ($$)
+
+=head WriteFile($self, $filename)
+
+ Write a text file containing the current table content.
+
+=cut
+sub WriteFile ($$)
+{
+ my ($self, $filename) = @_;
+
+ open my $out, ">".$self->{'filename'};
+
+ print $out join("\t", @{$self->{'columns'}})."\r\n";
+ print $out join("\t", @{$self->{'column_specs'}})."\r\n";
+ if (defined $self->{'codepage'})
+ {
+ print $out $self->{'codepage'} . "\t";
+ }
+ print $out $self->{'name'} . "\t";
+ print $out join("\t",@{$self->{'index_columns'}})."\r\n";
+
+ foreach my $row (@{$self->{'rows'}})
+ {
+ print $out $row->Format("\t")."\r\n";
+ }
+
+ close $out;
+}
+
+
+
+
+sub UpdateTimestamp ($)
+{
+ my $self = shift;
+
+ utime(undef,undef, $self->{'filename'});
+}
+
+
+
+
+sub GetName ($)
+{
+ my $self = shift;
+
+ return $self->{'name'};
+}
+
+
+
+
=head2 GetColumnCount($self)
Return the number of columns in the table.
@@ -193,6 +300,33 @@ sub GetColumnIndex ($$)
+=head2 GetRowIndex($self, $index_column_index, $index_column_value)
+
+ Return the index, starting at 0, of the (first) row that has value $index_column_value
+ in column with index $index_column_index.
+
+ Return -1 if now such row is found.
+
+=cut
+sub GetRowIndex ($$$)
+{
+ my ($self, $index_column_index, $index_column_value) = @_;
+
+ my $rows = $self->{'rows'};
+ for (my ($row_index,$row_count)=(0,scalar @$rows); $row_index<$row_count; ++$row_index)
+ {
+ my $row = $rows->[$row_index];
+ if ($row->GetValue($index_column_index) eq $index_column_value)
+ {
+ return $row_index;
+ }
+ }
+
+ return -1;
+}
+
+
+
=head2 GetValue($self, $selector_column, $selector_column_value, $value_column)
@@ -270,5 +404,89 @@ sub GetAllRows ($)
+=head2 SetRow($self, {$key, $value}*)
+
+ Replace an existing row. If no matching row is found then add the row.
+
+ The row is defined by a set of key/value pairs. Their order is defined by the keys (column names)
+ and their indices as defined in $self->{'columns'}.
+
+ Rows are compared by their values of the index column. By default this is the first element of
+ $self->{'index_columns'} but is overruled by the last key that starts with a '*'.
+
+=cut
+sub SetRow ($@)
+{
+ my $self = shift;
+ my @data = @_;
+
+ my @items = ();
+ my $index_column = $self->{'index_columns'}->[0];
+
+ # Key/Value has to have an even number of entries.
+ MsiTools::Die("invalid arguments given to MsiTable::SetRow()\n") if (scalar @data%2) != 0;
+
+ # Find column indices for column names.
+ while (scalar @data > 0)
+ {
+ my $column_name = shift @data;
+ if ($column_name =~ /^\*(.*)$/)
+ {
+ # Column name starts with a '*'. Use it as index column.
+ $column_name = $1;
+ $index_column = $1;
+ }
+ my $value = shift @data;
+ my $column_index = $self->GetColumnIndex($column_name);
+ $items[$column_index] = $value;
+ }
+
+ my $index_column_index = $self->GetColumnIndex($index_column);
+ my $row_index = $self->GetRowIndex($index_column_index, $items[$index_column_index]);
+
+ if ($row_index < 0)
+ {
+ # Row does not yet exist. Add it.
+ push @{$self->{'rows'}}, installer::patch::MsiRow->new($self, @items);
+ }
+ else
+ {
+ # Row does already exist. Replace it.
+ $self->{'rows'}->[$row_index] = installer::patch::MsiRow->new($self, @items);
+ }
+
+ $self->MarkAsModified();
+}
+
+
+
+
+sub MarkAsModified ($)
+{
+ my $self = shift;
+
+ $self->{'is_modified'} = 1;
+}
+
+
+
+
+sub MarkAsUnmodified ($)
+{
+ my $self = shift;
+
+ $self->{'is_modified'} = 0;
+}
+
+
+
+
+sub IsModified ($)
+{
+ my $self = shift;
+
+ return $self->{'is_modified'};
+}
+
1;
diff --git a/solenv/bin/modules/installer/patch/ReleasesList.pm b/solenv/bin/modules/installer/patch/ReleasesList.pm
index 320e864..e0648eb 100644
--- a/solenv/bin/modules/installer/patch/ReleasesList.pm
+++ b/solenv/bin/modules/installer/patch/ReleasesList.pm
@@ -21,8 +21,9 @@
package installer::patch::ReleasesList;
-use XML::LibXML;
+use XML::Parser;
use File::Spec;
+
use strict;
=head1 NAME
@@ -43,7 +44,8 @@ sub Instance()
{
if ( ! defined $Instance)
{
- $Instance = new installer::patch::ReleasesList();
+ $Instance = new installer::patch::ReleasesList(
+ File::Spec->catfile($ENV{'SRC_ROOT'}, "instsetoo_native", "data", "releases.xml"));
}
return $Instance;
}
@@ -51,19 +53,23 @@ sub Instance()
-=head2 new($class)
+=head2 new($class, $filename)
Internal constructor. Don't call.
=cut
-sub new ($)
+sub new ($$)
{
- my ($class) = @_;
+ my ($class, $filename) = @_;
- my $self = {};
+ my $self = {
+ 'releases' => []
+ };
bless($self, $class);
- $self->Read();
+
+ $self->Read($filename);
+
return $self;
}
@@ -87,14 +93,14 @@ sub GetFirstChild ($$)
}
else
{
- my @child_nodes = $node->getElementsByTagName($child_name);
- if (scalar @child_nodes == 0)
+ my $value = $node->{$child_name};
+ if (ref($value) eq 'ARRAY')
{
- return undef;
+ return $value->[0];
}
else
{
- return $child_nodes[0];
+ return $value;
}
}
}
@@ -107,17 +113,24 @@ sub GetFirstChild ($$)
Internal function that returns the trimmed text content of a node.
=cut
-sub GetText ($)
+sub GetText ($;$)
{
- my ($node) = @_;
+ my ($node, $default_text) = @_;
if ( ! defined $node)
{
- return "";
+ if (defined $default_text)
+ {
+ return $default_text;
+ }
+ else
+ {
+ return "";
+ }
}
else
{
- my $text = $node->textContent();
+ my $text = $node->{'__text__'};
$text =~ s/(^\s+|\s+$)//g;
return $text;
}
@@ -125,39 +138,165 @@ sub GetText ($)
+sub GetAttribute ($$)
+{
+ my ($node, $attribute_name) = @_;
+
+ my $attributes = $node->{'__attributes__'};
+ if ( ! defined $attributes)
+ {
+ return undef;
+ }
+ else
+ {
+ return $attributes->{$attribute_name};
+ }
+}
+
+
+
+
+sub PrintNode($$);
+sub ReadDomTree ($)
+{
+ my ($filename) = @_;
+
+ my $root = {};
+ my $data = {
+ 'current_node' => $root,
+ 'node_stack' => []
+ };
+ my $parser = new XML::Parser(
+ 'Handlers' => {
+ 'Start' => sub {HandleStartTag($data, @_)},
+ 'End' => sub{HandleEndTag($data, @_)},
+ 'Char' => sub{HandleText($data, @_)}
+ });
+ $parser->parsefile($filename);
+
+# PrintNode("", $root);
+
+ return $root;
+}
+
-=head2 Read($self)
+
+
+sub PrintNode($$)
+{
+ my ($indentation, $node) = @_;
+
+ if (defined $node->{'__attributes__'})
+ {
+ while (my ($name,$attribute) = each(%{$node->{'__attributes__'}}))
+ {
+ printf(" %s%s -> %s\n", $indentation, $name, $attribute);
+ }
+ }
+
+ while (my ($key,$value) = each(%$node))
+ {
+ if ($key eq '__text__')
+ {
+ printf("%stext '%s'\n", $indentation, $value);
+ }
+ elsif ($key eq '__attributes__')
+ {
+ next;
+ }
+ elsif (ref($value) eq "ARRAY")
+ {
+ foreach my $item (@$value)
+ {
+ printf("%s%s {\n", $indentation, $key);
+ PrintNode($indentation." ", $item);
+ printf("%s}\n", $indentation);
+ }
+ }
+ else
+ {
+ printf("%s%s {\n", $indentation, $key);
+ PrintNode($indentation." ", $value);
+ printf("%s}\n", $indentation);
+ }
+ }
+}
+
+
+sub HandleStartTag ($$$@)
+{
+ my ($data, $expat, $element, @attributes) = @_;
+
+ # Create new node with attributes.
+ my $node = {'__attributes__' => {@attributes}};
+
+ # Append it to the list of $element objects.
+ my $current_node = $data->{'current_node'};
+ $current_node->{$element} = [] unless defined $current_node->{$element};
+ push @{$current_node->{$element}}, $node;
+
+ # Make the new node the current node.
+ push @{$data->{'node_stack'}}, $current_node;
+ $data->{'current_node'} = $node;
+}
+
+sub HandleEndTag ($$$)
+{
+ my ($data, $expat, $element) = @_;
+
+ # Restore the parent node as current node.
+ $data->{'current_node'} = pop @{$data->{'node_stack'}};
+}
+
+sub HandleText ($$$)
+{
+ my ($data, $expat, $text) = @_;
+ if ($text !~ /^\s*$/)
+ {
+ $data->{'current_node'}->{'__text__'} .= $text;
+ }
+}
+
+=head2 Read($self, $filename)
Read the releases.xml file as doctree and parse its content.
=cut
-sub Read ($)
+sub Read ($$)
{
- my ($self) = @_;
+ my ($self, $filename) = @_;
- my $filename = File::Spec->catfile($ENV{'SRC_ROOT'}, "instsetoo_native", "data", "releases.xml");
- my $parser = XML::LibXML->new();
- my $document = $parser->parse_file($filename);
- foreach my $release_node ($document->getElementsByTagName("release"))
+ my $document = ReadDomTree($filename);
+ foreach my $release_node (@{$document->{'releases'}->[0]->{'release'}})
{
my $version_node = GetFirstChild($release_node, "version");
- my $version = GetText($version_node);
- next if $version eq "";
+ my $version_major = GetText(GetFirstChild($version_node, "major"));
+ my $version_minor = GetText(GetFirstChild($version_node, "minor"), "0");
+ my $version_micro = GetText(GetFirstChild($version_node, "micro"), "0");
+ my $version = sprintf("%d.%d.%d", $version_major, $version_minor, $version_micro);
+ die "could not read version from releases.xml" if $version eq "";
- foreach my $download_node (GetFirstChild($release_node, "download"))
- {
- my $package_node = GetFirstChild($download_node, "package-format");
- my $package_format = GetText($package_node);
- next if $package_format eq "";
+ push @{$self->{'releases'}}, $version;
- my $download_data = ParseDownloadData($download_node);
- if (defined $download_data)
+ my $download_node = GetFirstChild($release_node, "downloads");
+ my $package_format = GetText(GetFirstChild($download_node, "package-format"));
+ my $url_template = GetText(GetFirstChild($download_node, "url-template"));
+ my $upgrade_code = GetText(GetFirstChild($download_node, "upgrade-code"));
+ my $build_id = GetText(GetFirstChild($download_node, "build-id"));
+ die "could not read package format from releases.xml" if $package_format eq "";
+
+ $self->{$version}->{$package_format}->{'upgrade-code'} = $upgrade_code;
+ $self->{$version}->{$package_format}->{'build-id'} = $build_id;
+
+ foreach my $item_node (@{$download_node->{'item'}})
+ {
+ my ($language, $download_data) = ParseDownloadData($item_node, $url_template);
+ if (defined $download_data && defined $language)
{
- $self->{$version}->{$package_format} = $download_data;
+ $self->{$version}->{$package_format}->{$language} = $download_data;
}
}
}
-
}
@@ -168,43 +307,69 @@ sub Read ($)
Parse the data for one set of download data (there is one per release and package format).
=cut
-sub ParseDownloadData ($)
+sub ParseDownloadData ($$)
{
- my ($download_node) = @_;
+ my ($item_node, $url_template) = @_;
- my $url_node = GetFirstChild($download_node, "url-template");
- my $url_template = GetText($url_node);
- if ($url_template eq "")
+ my $language = GetText(GetFirstChild($item_node, "language"));
+ my $checksum_node = GetFirstChild($item_node, "checksum");
+ if ( ! defined $checksum_node)
{
- print STDERR "releases data file corrupt (no URL template)\n";
+ print STDERR "releases data file corrupt (item has no 'checksum' node)\n";
return undef;
}
-
- my $download_data = {};
- foreach my $item_node (@{$download_node->getElementsByTagName("item")})
- {
- my $language = GetText(GetFirstChild($item_node, "language"));
- my $checksum_node = GetFirstChild($item_node, "checksum");
- if ( ! defined $checksum_node)
+ my $checksum_type = GetAttribute($checksum_node, "type");
+ my $checksum_value = GetText($checksum_node);
+ my $file_size = GetText(GetFirstChild($item_node, "size"));
+ my $product_code = GetText(GetFirstChild($item_node, "product-code"));
+
+ my $url = $url_template;
+ $url =~ s/\%L/$language/g;
+ return (
+ $language,
{
- print STDERR "releases data file corrupt (item has no 'checksum' node)\n";
- return undef;
- }
- my $checksum_type = $checksum_node->getAttribute("type");
- my $checksum_value = GetText($checksum_node);
- my $file_size = GetText(GetFirstChild($item_node, "size"));
-
- my $url = $url_template;
- $url =~ s/\%L/$language/g;
- $download_data->{$language} = {
'URL' => $url,
'checksum-type' => $checksum_type,
'checksum-value' => $checksum_value,
- 'file-size' => $file_size
- };
+ 'file-size' => $file_size,
+ 'product-code' => $product_code
+ });
+}
+
+
+
+
+=head2 GetPreviousVersion($version)
+
+ Look up $version in the sorted list of released versions. Return
+ the previous element. Whe $version is not found then return the
+ last element (under the assumption that $version will be the next
+ released version).
+
+=cut
+sub GetPreviousVersion ($)
+{
+ my ($current_version) = @_;
+
+ my $release_data = installer::patch::ReleasesList::Instance();
+ my $previous_version = undef;
+ foreach my $version (@{$release_data->{'releases'}})
+ {
+ if ($version eq $current_version)
+ {
+ return $previous_version;
+ }
+ else
+ {
+ $previous_version = $version;
+ }
}
- return $download_data;
+ return $previous_version;
}
+
+
+
+
1;
diff --git a/solenv/bin/modules/installer/patch/Tools.pm b/solenv/bin/modules/installer/patch/Tools.pm
index b29b559..06035a3 100644
--- a/solenv/bin/modules/installer/patch/Tools.pm
+++ b/solenv/bin/modules/installer/patch/Tools.pm
@@ -30,17 +30,32 @@ package installer::patch::Tools;
-=head2 CygpathToWindows ($path)
+=head2 ToEscapedWindowsPath ($path)
Convert the given path with the 'cygpath' command into Windows format. Quote backslashes.
=cut
-sub CygpathToWindows($)
+sub ToEscapedWindowsPath($)
{
my ($path) = @_;
+
my $windows_path = qx(cygpath -w "$path");
$windows_path =~ s/(^\s+|\s+$)//g;
$windows_path =~ s/\\/\\\\/g;
+
+ return $windows_path;
+}
+
+
+
+
+sub ToWindowsPath ($)
+{
+ my ($path) = @_;
+
+ my $windows_path = qx(cygpath -w "$path");
+ $windows_path =~ s/(^\s+|\s+$)//g;
+
return $windows_path;
}
diff --git a/solenv/bin/modules/installer/patch/Version.pm b/solenv/bin/modules/installer/patch/Version.pm
index 685df6d..4e50cb0 100644
--- a/solenv/bin/modules/installer/patch/Version.pm
+++ b/solenv/bin/modules/installer/patch/Version.pm
@@ -35,7 +35,7 @@ my $VersionPartCount = 3;
-=head StringToNumberArray($version_string)
+=head2 StringToNumberArray($version_string)
Convert a version string (where the individual parts are separated by '.') into an array of three numbers.
Missing numbers are filled with 0.
@@ -57,7 +57,7 @@ sub StringToNumberArray ($)
-=head ArrayToDirectoryName (@)
+=head2 ArrayToDirectoryName (@)
Return a directory name (without any path) for the given array of version numbers.
@@ -69,6 +69,37 @@ sub ArrayToDirectoryName (@)
+=head2 ArrayToNoDotName (@)
+
+ This symply creates a version array (A,B,C) into a version string
+ "ABC" with no dots between major, minor and micro version number.
+
+=cut
+sub ArrayToNoDotName (@)
+{
+ return join("", @_);
+}
+
+
+
+
+=head2 IsMajorVersion ($version_string)
+
+ Return 1 if $version_string is a major version, ie. ?.0.0
+ Return 0 otherwise.
+
+=cut
+sub IsMajorVersion ($)
+{
+ my ($version_string) = @_;
+ my @version = installer::patch::Version::StringToNumberArray($version_string);
+ for (my $index=1; $index<$VersionPartCount; ++$index)
+ {
+ return 0 if $version[$index] ne "0";
+ }
+ return 1;
+}
+
1;
diff --git a/solenv/bin/modules/installer/systemactions.pm b/solenv/bin/modules/installer/systemactions.pm
index b4396b4..a492f37 100644
--- a/solenv/bin/modules/installer/systemactions.pm
+++ b/solenv/bin/modules/installer/systemactions.pm
@@ -1710,36 +1710,48 @@ sub read_complete_directory
# Version 2
##############################################################
-sub read_full_directory {
+sub read_full_directory ($$$)
+{
my ( $currentdir, $pathstring, $collector ) = @_;
my $item;
my $fullname;
local *DH;
- unless (opendir(DH, $currentdir))
- {
- return;
- }
- while (defined ($item = readdir(DH)))
+ $installer::logger::Lang->printf("seaching files under '%s'\n", $currentdir);
+
+ my @directory_queue = [$currentdir, $pathstring];
+
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list